SQLinfo.ru - Все о MySQL

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

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

Вы не зашли.

#1 18.02.2011 21:47:43

shura-o
Участник
Зарегистрирован: 18.02.2011
Сообщений: 5

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

Здравствуйте.
Некоторое время вожусь с MySQL, но забуксовал на такой вот проблеме:

Table:
id         code
1234     1       
367       5       
545       2       
1234     8       
1234     3       
367       2
1234     5
367       1     

Есть список id, они определяются в другом месте, а в эту вот таблицу  для каждого (или не каждого) id записывается код события, которое с этим id произошло. Соответственно для какого-тоid может вообще не быть записей, для другого их может быть несколько, с разными кодами (а могут быть и с одинаковыми). Задача: вытащить только те id, для которых в этой таблице имеется некая комбинация кодов: например, есть запись с code=1 и code=3 (это будет id=1234), или code=1 и code=5 (это будут id=1234 и 367).
Хочется решить задачу в общем виде, для произвольной комбинации кодов (их может быть не два, а больше - скажем, 1,2,5 или 3,7,12,22), а также для случая, когда некий код (коды) есть, а неких другие, наоборот, при этом нету (1,2,8 есть и при том нет 12).
Ничего умного в голову не приходит sad   Пока только жалкие потуги с JOIN (для двух кодов), но все очень некрасиво и громоздко sad
Может быть, есть какие-то разумные пути? Хотя бы намекните, в какую сторону рыть smile может, процедуру надо или еще какую фичу - с этими вещами я пока плохо знаком.
Заранее благодарен за любые советы.

Спасибо.

Неактивен

 

#2 20.02.2011 15:50:45

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3880

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

А сколько кодов разных? Как написано 8 или их миллион? Сколько строк в таблице? Сколько id с заданным кодом?

В такой форме таблице ничего более красивого, чем много JOIN-ов сделать не получится. Если есть возможность быстро преобразовать таблицу к другому виду, решение будет более красивым. Если кодов мало - сделать битовое поле. Если много - текстовую строку.

Например

SELECT id,CONCAT(',',GROUP_CONCAT(code), ',') s FROM tbl GROUP BY id;

сгруппирует данные в формате (запятые в начале и в конце существенны)
1234 ,1,8,3,5,
367       ,5,2,1,
545       ,2,

В таком формате можно искать строковым поиском ",id,". То есть
SELECT id,CONCAT(',',GROUP_CONCAT(code), ',') s FROM tbl GROUP BY id HAVING s LIKE '%,8,%' AND s LIKE '%,3,%' AND s NOT LIKE '%,2,%'

Неактивен

 

#3 21.02.2011 16:51:34

shura-o
Участник
Зарегистрирован: 18.02.2011
Сообщений: 5

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

Спасибо! smile Да, пожалуй, это наиболее плодотворный подход. Более того, в принципе можно в момент добавления новой строки в эту таблицу заранее составлять список для данного id кодов и хранить (id с описанием хранится же в другой таблице, где id - ключевое поле). Наверное.

Неактивен

 

#4 21.02.2011 17:19:41

shura-o
Участник
Зарегистрирован: 18.02.2011
Сообщений: 5

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

А еще вопрос: в чем преимущество битовой строки? Кодов не очень много, примерно 20-30. То есть, если я правильно понял, номер кода == позиция в битовой строке. И как это можно использовать?

Спасибо.

Неактивен

 

#5 21.02.2011 18:07:53

shura-o
Участник
Зарегистрирован: 18.02.2011
Сообщений: 5

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

Извините, не полностью описал параметры: сейчас id-ов порядка 4-5 тысяч (и более в перспективе, но вряд ли больше 100000), по каждому id от примерно 3-5 до 10-15 (может более, но редко) записей с кодами. Кроме того, в рассматриваемой таблице еще ряд записей, служебных, тоже по несколько (4-8) на каждый id. Реально сейчас записей в таблице примерно в 10 раз больше, чем id-ов (порядка 40 тысяч).

Неактивен

 

#6 24.02.2011 01:35:20

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

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

Да, битовое поле — это поле, где каждый бит обозначает свой элемент.

Использовать — очень просто. Придумываете нужную последовательность
(например, 1-2-5), преобразуете в число (биты считают от нуля, поэтому
в нашем примере 2^0 + 2^1 + 2^4 = 19) и делаете выборку
(SELECT FROM tablename WHERE codes = 19).

--

А вот сколько видов кодов Вы не сказали smile

Неактивен

 

#7 01.03.2011 21:51:53

shura-o
Участник
Зарегистрирован: 18.02.2011
Сообщений: 5

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

Спасибо! smile
Кодов не очень много, примерно 20-30, я как раз таки написал smile но тогда придется заранее собирать эту битовую строку и хранить. Тогда все понятно и просто. А если ее собирать во время запроса... тогда, вероятно, как-то так?

SELECT DISTINCT id, SUM(2^(code-1)) s FROM tbl GROUP BY id WHERE s=<число>;


(поскольку код может встречаться не раз для одного и того же id, видимо, нужно исключить повторяющиеся сочетания id-код -
правильно ли я поставил DISTINCT? ).

По большому счету, и биты тут ни при чем - работаем же просто с числом smile
Но если все же хранить... Если не ошибаюсь, BIGINT позволит 63 бита хранить? А, 64. То есть раза в два - два с половиной больше, чем у меня сейчас кодов.
Но тогда, действительно, работать, наверно, удобнее именно с битовой строкой? Скажем, добавлять новый или убирать имевшийся код для этого id - поменял один бит и все. Вот, нашел. Для этого, видимо, нужно использовать  побитовые операции. да?

..я правильно рассуждаю? или что-то упустил?
И как вы думаете, что быстрее будет работать - LIKE с CONCAT или вот  такая штука со степенями двойки?

Спасибо.

Неактивен

 

#8 01.03.2011 23:49:16

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

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

Да, и правда я не заметил количество значений smile Чтобы упростить себе работу
с битами, можно подумать о типе SET — может оказаться более простым с точки
зрения преобразований.

Штука со степенями двойки при равенствах будет работать, разумеется, быстрее.
Хотя бы потому, что сможет использовать индекс.

Неактивен

 

Board footer

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