Полный набор в SQL - PullRequest
       19

Полный набор в SQL

2 голосов
/ 27 мая 2009

Мне нужно было придумать запрос SQL, который возвращает строки, удовлетворяющие нескольким условиям. Эта статья описывает, что мне нужно было сделать, и решение: http://thenoyes.com/littlenoise/?p=58

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

SET @q = 'A,B';

SELECT studentName
FROM quizAnswers
GROUP BY studentName
HAVING
        BIT_OR(1 << FIND_IN_SET(question, @q) - 1)
    =
        (1 << LENGTH(@q) - LENGTH(REPLACE(@q, ',', '')) + 1) - 1; -- This is 2^numValues - 1
+-------------+
| studentName |
+-------------+
| seekwill    |
+-------------+

Я проверил это, и он работает, как ожидалось. Может кто-нибудь объяснить, как это работает?

Спасибо, Amie

Ответы [ 3 ]

2 голосов
/ 28 мая 2009

Я не собираюсь объяснять, что делает BIT_OR.

Альтернативное решение:

Если это возможно, я обычно предпочитаю pure SQL-решения, которые не зависят от особенностей поставщика. Если то, что вам нужно, похоже на пример в статье, на которую вы ссылаетесь, то этот оператор SQL должен работать практически на любой СУБД и давать желаемый результат:

-- //return those students that have correctly answered not less then 3 questions among A,B,C
select      studentName, COUNT(DISTINCT question) AS CNT
from        quizAnswers
where       question in ('A', 'B', 'C')
GROUP BY    studentName
HAVING COUNT(DISTINCT question) >= 3

и, играя с HAVING COUNT..., вы еще более гибки:

-- //return those students that have correctly answered at least 1 question among A,B (either A or B)
select      studentName, COUNT(DISTINCT question) AS CNT
from        quizAnswers
where       question in ('A', 'B',)
GROUP BY    studentName
HAVING COUNT(DISTINCT question) >= 1

Как правило, вам просто нужно заполнить ... в части where question in (...) и установить значение СЧЕТА (...), которое по умолчанию будет числом ответов, которое нужно проверить для полного набора.

1 голос
/ 28 мая 2009

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

Этот метод явно ограничен количеством битов, которые может содержать возвращаемый тип.

0 голосов
/ 28 мая 2009

В документации MySQL поясняется, что FIND_IN_SET () "возвращает (и) позицию индекса первого аргумента во втором аргументе". Учитывая, что набор доступных вопросов был «A», «B» или «C», мы можем использовать этот запрос, чтобы увидеть, что делает FIND_IN_SET ():

SELECT studentName, 
       question, 
       FIND_IN_SET(question, 'A,B,C') AS position 
FROM quizAnswers;

Используя их примеры записей, мы получим:

+-------------+----------+----------+
| studentName | question | position |
+-------------+----------+----------+
| seekwill    | A        |        1 |
| seekwill    | B        |        2 |
| seekwill    | C        |        3 |
| roxlu       | A        |        1 |
| fury        | B        |        2 |
| fury        | B        |        2 |
+-------------+----------+----------+

Теперь они предлагают вам превратить это в битовую маску и использовать битовый xor для устранения дубликатов для любой заданной пары (studentName, question).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...