#mysql #group-by #distinct #bit-manipulation
#mysql #группировка по #различные #манипулирование битами
Вопрос:
У меня есть таблица, в которой есть побитовый столбец, представляющий список статусов, которые могут быть прикреплены к записи. Для каждой записи может быть выбрано несколько статусов (отсюда и использование побитовой логики).
Что я хотел бы сделать, так это вывести запрос, который сообщит мне, сколько целых значений существует для каждого статуса (т. Е. сколько раз каждый бит включен). Трудность, с которой я сталкиваюсь, заключается в том, что, конечно, есть перекрытие, поэтому GROUP BY или DISTINCT не собираются его сокращать (насколько я могу видеть).
В качестве примера давайте просто возьмем два значения, 1 и 2. и следующие данные
Id | Status
1 | 1
2 | 1
3 | 2
4 | 3
Теперь я хочу подсчитать, сколько записей имеется для каждого бита, поэтому я хотел бы что-то, что учитывает это значение 3 в обоих итоговых значениях 1 и 2, выводя что-то вроде этого:
Bit | Count
1 | 3
2 | 2
Кажется, что самое близкое, что я могу получить на данный момент, — это извлекать различные значения, а затем добавлять значения с несколькими записями в соответствующие им значения, используя PHP. Очевидно, я хотел бы сделать что-то более элегантное.
Есть идеи?
Ответ №1:
При необходимости разверните таблицу bits
select `bit`, count(*) `count`
from bitt s
inner join (select 1 `bit` union all
select 2 union all
select 3 union all
select 4 union all
select 5) bits on s.status amp; Pow(2,bits.`bit`-1)
group by bits.`bit`
Комментарии:
1. Да, это может сработать. Объединения немного некрасивы, но я подозревал, что мне придется сделать что-то в этом роде. Мне интересно, есть ли способ получить соответствующие значения в таблице bits, используя внутреннее объединение и BIT_OR(), но я не могу понять, как разложить результат.
Ответ №2:
Вы могли бы сделать:
SUM(IF(`Status`amp;1,1,0)) as `count1`,
SUM(IF(`Status`amp;2,1,0)) as `count2`,
SUM(IF(`Status`amp;4,1,0)) as `count4`
Если вы хотите оптимизировать это, вы все еще можете GROUP BY Status
, но тогда вам потребуется (небольшая) постобработка, чтобы суммировать 8 строк, которые вы получили бы для 3-разрядной ситуации.
Ответ №3:
Еще один вариант —
SELECT 0, COUNT(IF(status >> 0 amp; 1 = 1, 1, NULL)) FROM table1
UNION
SELECT 1, COUNT(IF(status >> 1 amp; 1 = 1, 1, NULL)) FROM table1
UNION
SELECT 2, COUNT(IF(status >> 2 amp; 1 = 1, 1, NULL)) FROM table1
...