SQLinfo.ru - Все о MySQL Webew.ru: теория и практика веб-технологий

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 29.01.2011 10:07:58

Евген
Участник
Зарегистрирован: 26.01.2011
Сообщений: 17

Помогите с составлением запроса

Здравствуйте !
Помогите с составлением запроса, смысл в следующем:
Есть таблица (software) в которой собрано более 100 тыс. записей следующего содержания:
Date - дата инвентаризации
arm - имя автоматизированного рабочего места
software - название установленного программного обеспечения.

Один и тот же АРМ может иметь несколько результатов инвентаризации ПО по датам, но не более одного результата в день.
Нужно составить такой запрос, чтобы выдавался список всего ПО и количество его установок на АРМах, но состоящих из результатов самой последней инвентаризации по каждому АРМу. Потому что ненужное ПО уже могли деинсталлировать.

Я сделал такой запрос:

select b.software, count(b.software) from software b where b.date in (select max(a.date) from software a where a.arm=b.arm group by a.arm) group by b.software
Запрос работает, но ужасно долго...  подозреваю что нужно сделать через использование EXISTS, но никак не получается, не пойму почему...  :-(

Неактивен

 

#2 29.01.2011 23:38:45

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6756

Re: Помогите с составлением запроса

Запрос выглядит нормально, только IN я бы на «=» заменил, и группировка лишняя
в подзапросе (т.е. WHERE `date` = (SELECT MAX(`date`) FROM software a WHERE a.arm = b.arm)).

А чтобы работало быстрее, нужны индексы на (arm, `date`), (software, `date`).

Неактивен

 

#3 30.01.2011 14:48:21

Евген
Участник
Зарегистрирован: 26.01.2011
Сообщений: 17

Re: Помогите с составлением запроса

Ок, в понедельник на работе попробую...
а группировку в подзапросе я уж точно назря сделал... явное компостирование мозгов компу...  :-)

Отредактированно Евген (30.01.2011 16:44:49)

Неактивен

 

#4 31.01.2011 19:13:03

Евген
Участник
Зарегистрирован: 26.01.2011
Сообщений: 17

Re: Помогите с составлением запроса

Попробовал, индексы действительно рулят, понял что в большой таблице без них реально не обойтись...
время выполнения получилось 9-10 секунд (раньше зависал, сбрасывал выполнение через 5 минут)

сейчас возникла другая проблема...  с этим же запросом, немного модифицированным под раздачу прав для другой роли...
смысл в следующем...  я добавляю в этот же запрос дополнительные условия и условие на максимальную дату перестаёт работать... :-(
т.е. в результате подсчитывает количество каждого софта по всем инвентаризациям арма а не по последней  :-(

вот какой он у меня в последней редакции...

select b.software, count(b.software) from software b, c:\inetpub\wwwroot\reports.cross c, c:\inetpub\wwwroot\reports.suborden d where b.date=(select max(a.date) from software a where a.arm=b.arm ) and c.login=d.spec and d.nachsek='" & session("login") & "' and lcase(c.dnsname)=lcase(left(b.arm,4)) group by b.software


Подсчитывает за все даты :-(
Может есть какие-нибудь тонкости с обработкой индексированных текстовых полей ?

Отредактированно Евген (31.01.2011 19:23:09)

Неактивен

 

#5 31.01.2011 21:00:43

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6756

Re: Помогите с составлением запроса

Как-то неудачно у Вас выдралось из текста — c:\inetpub smile

Вы добавляете не только дополнительные условия, но и дополнительные таблицы.
В результате Вы получаете увеличение количества строк (если условие связи
выдает, например, более одной строки).

Возможно, Вам будет проще работать с представлением «последняя инвентаризация»:
CREATE VIEW last_software AS SELECT * FROM software b WHERE `date` = (SELECT MAX(`date`) FROM software a WHERE a.arm = b.arm);
Это будет некоторый аналог подзапроса, но зато Вы не сможете добавить туда
ненужное (или наоборот — выкинуть). Ну или сделайте эту штуку честным
подзапросом, и объединяйтесь уже с ним smile


P.S. И не забудьте экранировать символы в session("login"), или готовьтесь принять
последствия, если в качестве сессии приедет строка «'; DROP TABLE software; SELECT '»

P.P.S. По поводу Вашего письма — мы люди корыстные, и помогаем бесплатно только
в рамках форума, извините. Но задавать Ваши вопросы на форуме при этом никто
не мешает smile

Неактивен

 

#6 01.02.2011 07:21:09

Евген
Участник
Зарегистрирован: 26.01.2011
Сообщений: 17

Re: Помогите с составлением запроса

Спасибо большущее за подсказку CREATE VIEW !!!
Пошёл пробовать реализовать...

Насколько я понял потом из сделанного вида (который read only) можно делать SELCT'ом выборки ! :-)

Отредактированно Евген (01.02.2011 07:21:30)

Неактивен

 

#7 01.02.2011 08:20:04

Евген
Участник
Зарегистрирован: 26.01.2011
Сообщений: 17

Re: Помогите с составлением запроса

Понял где у меня грабли, но пока не знаю как исправить, прошу помощи...
смысл в следующем !!!
Грабли происходят вот тут, двойной учёт получается из за того, что 2 спеца обслуживают один офис и им обоим через табицу соответствия назначен DNS имя одного и того же офиса и поэтому software этого офиса на этих компьютерах учитываеться дважды вот в этом месте
lcase(c.dnsname)=lcase(left(b.arm,4))

Как можно сделать так, чтобы выбиралось DISTINCT c.dnsname ?

Заранее спасибо !

Неактивен

 

#8 01.02.2011 09:02:58

Евген
Участник
Зарегистрирован: 26.01.2011
Сообщений: 17

Re: Помогите с составлением запроса

Пробовал вот так

select b.software,count(b.software) from software b,C:\Inetpub\wwwroot\WREP\reports.suborden c where c.nachsek='" & session("login") & "' and lcase(left(b.arm,4)) in ( select distinct lcase(d.dnsname) from C:\Inetpub\wwwroot\WREP\reports.cross d where c.spec=d.login ) group by b.software


Всё равно двоиться, видать надо как-то учесть неповторяющийся список АРМ'ов...  :-(
Я в ступоре :-(

Отредактированно Евген (01.02.2011 09:09:37)

Неактивен

 

#9 01.02.2011 09:55:43

jmadhead
Участник
Зарегистрирован: 11.01.2011
Сообщений: 10

Re: Помогите с составлением запроса

Честно говоря не сильно вникал в суть вопроса, но может поможет DISTINCT

Неактивен

 

#10 01.02.2011 23:22:21

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6756

Re: Помогите с составлением запроса

Правильно ли я понимаю, что у Вас два человека ходят по одному и тому же офису,
собирают в одно и то же время данные со всех машинок, и кладут в одну таблицу,
не различая строки между собой? То есть на каждый элемент software у Вас за одну
дату может быть или одна строка (второй человек не успел), или две строки?

Если так — то да, или DISTINCT в представлении, или группировка по всем полям.
Если строки всегда две, то можно просто COUNT() делить пополам wink

Неактивен

 

#11 02.02.2011 17:26:25

Евген
Участник
Зарегистрирован: 26.01.2011
Сообщений: 17

Re: Помогите с составлением запроса

Каждый элемент software за одну дату по каждому АРМу может быть только один !
Две строки с одним элементом software одного АРМа за одну дату не может быть !
Проблема в том, что учитывает дважды, потому что у двух человек сопоставлено одно и тоже dnsname прикреплённого подразделения и поэтому после вот этого

lcase(c.dnsname)=lcase(left(b.arm,4))
условия записи по одним и тем же АРМам офиса, который обслуживают эти два специалиста начинают учитываться дважды :-(

Отредактированно Евген (02.02.2011 17:27:35)

Неактивен

 

#12 02.02.2011 18:15:30

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6756

Re: Помогите с составлением запроса

Не понятно. У Вас есть таблица. Условие WHERE может уменьшить количество
строк в выборке. Увеличить не может никак. Значит — у Вас две одинаковые
строки с точки зрения запроса, но WHERE не ограничивает. Так?

Неактивен

 

#13 02.02.2011 18:52:18

Евген
Участник
Зарегистрирован: 26.01.2011
Сообщений: 17

Re: Помогите с составлением запроса

Да !
У меня две одинаковые строчки в результирующем наборе хотя изначально в базе - одна, и я так понимаю что раздвоил её как раз WHERE.
Для меня это тоже не вероятно, но это так !

paulus написал:

Если строки всегда две...

не обязательно две,  их столько же, сколько человек назначено на обслуживание офиса...

P.S. Это я про вот такой запрос

select b.arm from software b, c:\inetpub\wwwroot\reports.cross c, c:\inetpub\wwwroot\reports.suborden d where b.date=(select max(a.date) from software a where a.arm=b.arm ) and c.login=d.spec and d.nachsek='" & session("login") & "' and lcase(c.dnsname)=lcase(left(b.arm,4)) and b.software='Citrix client'
, с помощью которохо захотел узнать софт с каких АРМов попадает в расчёты и увидел что один и тот же АРМ (их несколько таких) попадает дважды в результат, поэтому количество установок софта получалось больше чем АРМов.

Отредактированно Евген (02.02.2011 19:35:16)

Неактивен

 

#14 03.02.2011 01:01:43

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6756

Re: Помогите с составлением запроса

Я, наверное, как-то плохо объясняю sad Давайте я попробую написать простых фактов
в простых терминах, а Вы потом самостоятельно примените к своим табличкам, а то
букв много, и донести не удается sad

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, дело в построении запроса целиком.

Неактивен

 

#15 03.02.2011 18:28:09

Евген
Участник
Зарегистрирован: 26.01.2011
Сообщений: 17

Re: Помогите с составлением запроса

ИМХО DISTINCT действует на результирующий набор , а не на условие WHERE,
Ну да ладно... я разбил то условие на несколько запросов и реализовал задуманное...   
Есть ещё одно любопытство, но думаю такого не бывает....   
возьмём ту же самую таблицу software и представим результаты инвентаризации за три дня подряд, где каждый день деинсталлировали по одной программе и каждый же жень инсталлировали по ещё одной программе. Возможно ли реализовать такую выборку, которая показывала бы даты и элементы software, которые не являются общими во всех трёх датах ?

Неактивен

 

#16 03.02.2011 19:04:35

paulus
Администратор
MySQL Authorized Developer and DBA
Зарегистрирован: 22.01.2007
Сообщений: 6756

Re: Помогите с составлением запроса

Про DISTINCT я не писал в контексте с WHERE wink

Конечно, просто сгруппируйте и посчитайте количество. Там, где оно не равно трем —
это Ваш случай.

Неактивен

 

#17 03.02.2011 19:17:53

Евген
Участник
Зарегистрирован: 26.01.2011
Сообщений: 17

Re: Помогите с составлением запроса

paulus написал:

Конечно, просто сгруппируйте и посчитайте количество. Там, где оно не равно трем —
это Ваш случай.

Блин !!! Гениальное просто !!! Просто эврика !!! Ёшкин кот !!! Я ведь по-началу даже не понял что это ответ !!!

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson