Задавайте вопросы, мы ответим
Вы не зашли.
Здравствуйте !
Помогите с составлением запроса, смысл в следующем:
Есть таблица (software) в которой собрано более 100 тыс. записей следующего содержания:
Date - дата инвентаризации
arm - имя автоматизированного рабочего места
software - название установленного программного обеспечения.
Один и тот же АРМ может иметь несколько результатов инвентаризации ПО по датам, но не более одного результата в день.
Нужно составить такой запрос, чтобы выдавался список всего ПО и количество его установок на АРМах, но состоящих из результатов самой последней инвентаризации по каждому АРМу. Потому что ненужное ПО уже могли деинсталлировать.
Я сделал такой запрос:
Неактивен
Запрос выглядит нормально, только IN я бы на «=» заменил, и группировка лишняя
в подзапросе (т.е. WHERE `date` = (SELECT MAX(`date`) FROM software a WHERE a.arm = b.arm)).
А чтобы работало быстрее, нужны индексы на (arm, `date`), (software, `date`).
Неактивен
Ок, в понедельник на работе попробую...
а группировку в подзапросе я уж точно назря сделал... явное компостирование мозгов компу... :-)
Отредактированно Евген (30.01.2011 16:44:49)
Неактивен
Попробовал, индексы действительно рулят, понял что в большой таблице без них реально не обойтись...
время выполнения получилось 9-10 секунд (раньше зависал, сбрасывал выполнение через 5 минут)
сейчас возникла другая проблема... с этим же запросом, немного модифицированным под раздачу прав для другой роли...
смысл в следующем... я добавляю в этот же запрос дополнительные условия и условие на максимальную дату перестаёт работать... :-(
т.е. в результате подсчитывает количество каждого софта по всем инвентаризациям арма а не по последней :-(
вот какой он у меня в последней редакции...
Отредактированно Евген (31.01.2011 19:23:09)
Неактивен
Как-то неудачно у Вас выдралось из текста — c:\inetpub
Вы добавляете не только дополнительные условия, но и дополнительные таблицы.
В результате Вы получаете увеличение количества строк (если условие связи
выдает, например, более одной строки).
Возможно, Вам будет проще работать с представлением «последняя инвентаризация»:
CREATE VIEW last_software AS SELECT * FROM software b WHERE `date` = (SELECT MAX(`date`) FROM software a WHERE a.arm = b.arm);
Это будет некоторый аналог подзапроса, но зато Вы не сможете добавить туда
ненужное (или наоборот — выкинуть). Ну или сделайте эту штуку честным
подзапросом, и объединяйтесь уже с ним
P.S. И не забудьте экранировать символы в session("login"), или готовьтесь принять
последствия, если в качестве сессии приедет строка «'; DROP TABLE software; SELECT '»
P.P.S. По поводу Вашего письма — мы люди корыстные, и помогаем бесплатно только
в рамках форума, извините. Но задавать Ваши вопросы на форуме при этом никто
не мешает
Неактивен
Спасибо большущее за подсказку CREATE VIEW !!!
Пошёл пробовать реализовать...
Насколько я понял потом из сделанного вида (который read only) можно делать SELCT'ом выборки ! :-)
Отредактированно Евген (01.02.2011 07:21:30)
Неактивен
Понял где у меня грабли, но пока не знаю как исправить, прошу помощи...
смысл в следующем !!!
Грабли происходят вот тут, двойной учёт получается из за того, что 2 спеца обслуживают один офис и им обоим через табицу соответствия назначен DNS имя одного и того же офиса и поэтому software этого офиса на этих компьютерах учитываеться дважды вот в этом месте
lcase(c.dnsname)=lcase(left(b.arm,4))
Как можно сделать так, чтобы выбиралось DISTINCT c.dnsname ?
Заранее спасибо !
Неактивен
Пробовал вот так
Отредактированно Евген (01.02.2011 09:09:37)
Неактивен
Честно говоря не сильно вникал в суть вопроса, но может поможет DISTINCT
Неактивен
Правильно ли я понимаю, что у Вас два человека ходят по одному и тому же офису,
собирают в одно и то же время данные со всех машинок, и кладут в одну таблицу,
не различая строки между собой? То есть на каждый элемент software у Вас за одну
дату может быть или одна строка (второй человек не успел), или две строки?
Если так — то да, или DISTINCT в представлении, или группировка по всем полям.
Если строки всегда две, то можно просто COUNT() делить пополам
Неактивен
Каждый элемент software за одну дату по каждому АРМу может быть только один !
Две строки с одним элементом software одного АРМа за одну дату не может быть !
Проблема в том, что учитывает дважды, потому что у двух человек сопоставлено одно и тоже dnsname прикреплённого подразделения и поэтому после вот этого
Отредактированно Евген (02.02.2011 17:27:35)
Неактивен
Не понятно. У Вас есть таблица. Условие WHERE может уменьшить количество
строк в выборке. Увеличить не может никак. Значит — у Вас две одинаковые
строки с точки зрения запроса, но WHERE не ограничивает. Так?
Неактивен
Да !
У меня две одинаковые строчки в результирующем наборе хотя изначально в базе - одна, и я так понимаю что раздвоил её как раз WHERE.
Для меня это тоже не вероятно, но это так !
paulus написал:
Если строки всегда две...
не обязательно две, их столько же, сколько человек назначено на обслуживание офиса...
P.S. Это я про вот такой запрос
Отредактированно Евген (02.02.2011 19:35:16)
Неактивен
Я, наверное, как-то плохо объясняю Давайте я попробую написать простых фактов
в простых терминах, а Вы потом самостоятельно примените к своим табличкам, а то
букв много, и донести не удается
1. WHERE — это фильтр. Он никогда и никак не может добавить строк. Чаще всего он
используется для того, чтобы уменьшить количество строк, проходящих через себя.
Например: У Вас есть корзина с яблоками. «WHERE цвет = красный» не может увели-
чить количество яблок в корзине.
2. Выборка из нескольких таблиц выдает количество строк, равное произведению ко-
личества строк отдельных таблиц.
Например: у Вас есть таблица А со строками (1, 2, 3) и таблица B со строками (a, b).
SELECT * FROM A, B выдаст следующие строки:
1 a, 1 b, 2 a, 2 b, 3 a, 3 b — всего шесть штук.
3. Если у Вас есть две *совсем* одинаковые строки в выборке, Вы можете сделать вы-
борку уникальной, добавив слово DISTINCT. Например, возьмем таблицы из пункта 2,
но немного изменим запрос: SELECT A.* FROM A, B. Простая выборка выдаст строки
1, 1, 2, 2, 3, 3. SELECT DISTINCT A.* FROM A,B выберет 1, 2, 3.
4. Если у Вас *не совсем* одинаковые строки, то можно сгруппировать по одинаковым
полям. Пример с теми же таблицами, SELECT A.id, COUNT(*) FROM A, B GROUP BY A.id
выдаст 1 2, 2 2, 3 2. Второе число — количество соответствующих группировке строк.
Я хочу, чтобы Вы поняли, что добавление в готовый запрос с COUNT(*) лишних таблиц
этот COUNT благополучно портит. Дело не в WHERE, дело в построении запроса целиком.
Неактивен
ИМХО DISTINCT действует на результирующий набор , а не на условие WHERE,
Ну да ладно... я разбил то условие на несколько запросов и реализовал задуманное...
Есть ещё одно любопытство, но думаю такого не бывает....
возьмём ту же самую таблицу software и представим результаты инвентаризации за три дня подряд, где каждый день деинсталлировали по одной программе и каждый же жень инсталлировали по ещё одной программе. Возможно ли реализовать такую выборку, которая показывала бы даты и элементы software, которые не являются общими во всех трёх датах ?
Неактивен
Про DISTINCT я не писал в контексте с WHERE
Конечно, просто сгруппируйте и посчитайте количество. Там, где оно не равно трем —
это Ваш случай.
Неактивен
paulus написал:
Конечно, просто сгруппируйте и посчитайте количество. Там, где оно не равно трем —
это Ваш случай.
Блин !!! Гениальное просто !!! Просто эврика !!! Ёшкин кот !!! Я ведь по-началу даже не понял что это ответ !!!
Неактивен