2009-05-27 2 views
2

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

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

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

+0

Я предлагаю вам скопировать и вставить фрагмент кода, на который вы ссылаетесь, с этого сайта, вставить его в свой вопрос и пометить его как «Кто-нибудь может объяснить, как это работает» –

+0

Несомненно. предложение. – Grnbeagle

ответ

2

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

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

Если это возможно, я обычно предпочитаю чистые решения 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 (...) и установите значение COUNT (...), который по умолчанию будет количество ответов, чтобы проверить полный набор.

+0

Спасибо, ван! Я пробовал этот метод, и он прекрасно работает .. и это не так загадочно. :) – Grnbeagle

+0

и мне объясняет оригинальный запрос :) –

1

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

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

+0

Я догадываюсь, что я запутался со всеми бит-операциями. Спасибо за вход! – Grnbeagle

0

The MySQL documentation объясняет, что 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, вопрос).

Смежные вопросы