質問への回答を保存するために使用するテーブルがあります。特定の質問に対する特定の回答を持つユーザーを見つけることができる必要があります。したがって、表が次のデータで構成されている場合:
user_id question_id answer_value
Sally 1 Pooch
Sally 2 Peach
John 1 Pooch
John 2 Duke
また、質問1で「Pooch」、質問2で「Peach」と回答するユーザーを見つけたい場合、次のSQLは(明らかに)動作しません。
select user_id
from answers
where question_id=1
and answer_value = 'Pooch'
and question_id=2
and answer_value='Peach'
私が最初に考えたのは、私たちが探している答えごとに、自分でテーブルに参加することでした。
select a.user_id
from answers a, answers b
where a.user_id = b.user_id
and a.question_id=1
and a.answer_value = 'Pooch'
and b.question_id=2
and b.answer_value='Peach'
これは機能しますが、任意の数の検索フィルターを許可するため、より効率的なものを見つける必要があります。私の次の解決策はこのようなものでした:
select user_id, count(question_id)
from answers
where (
(question_id=2 and answer_value = 'Peach')
or (question_id=1 and answer_value = 'Pooch')
)
group by user_id
having count(question_id)>1
ただし、ユーザーが同じアンケートに2回回答できるようにしたいので、回答表の質問1に2つの回答が表示される可能性があります。
だから、今、私は途方に暮れています。これに取り組む最善の方法は何ですか?よろしくお願いします!
user_id
他のテーブルからデータを取得するための結合チェーンのanswers
テーブルからですが、回答テーブルSQLを分離し、そのような単純な用語でそれを記述することで、ソリューションを見つけるのに役立ちました。
SELECT user_id, COUNT(question_id)
FROM answers
WHERE
(question_id = 2 AND answer_value = 'Peach')
OR (question_id = 1 AND answer_value = 'Pooch')
GROUP by user_id
HAVING COUNT(question_id) > 1
2番目のサブクエリを不必要に使用していました。
自己結合なしでこのクエリを実行する賢い方法を見つけました。
これらのコマンドをMySQL 5.5.8 for Windowsで実行すると、次の結果が得られました。
use test
DROP TABLE IF EXISTS answers;
CREATE TABLE answers (user_id VARCHAR(10),question_id INT,answer_value VARCHAR(20));
INSERT INTO answers VALUES
('Sally',1,'Pouch'),
('Sally',2,'Peach'),
('John',1,'Pooch'),
('John',2,'Duke');
INSERT INTO answers VALUES
('Sally',1,'Pooch'),
('Sally',2,'Peach'),
('John',1,'Pooch'),
('John',2,'Duck');
SELECT user_id,question_id,GROUP_CONCAT(DISTINCT answer_value) given_answers
FROM answers GROUP BY user_id,question_id;
+---------+-------------+---------------+
| user_id | question_id | given_answers |
+---------+-------------+---------------+
| John | 1 | Pooch |
| John | 2 | Duke,Duck |
| Sally | 1 | Pouch,Pooch |
| Sally | 2 | Peach |
+---------+-------------+---------------+
この表示は、ジョンが質問2に対して2つの異なる答えを出し、サリーが質問1に対して2つの異なる答えを出したことを示しています。
すべてのユーザーが異なる回答をした質問を見つけるには、上記のクエリをサブクエリに配置し、指定された回答のリストでカンマをチェックして、次のように異なる回答の数を取得します。
SELECT user_id,question_id,given_answers,
(LENGTH(given_answers) - LENGTH(REPLACE(given_answers,',','')))+1 multianswer_count
FROM (SELECT user_id,question_id,GROUP_CONCAT(DISTINCT answer_value) given_answers
FROM answers GROUP BY user_id,question_id) A;
私はこれを得た:
+---------+-------------+---------------+-------------------+
| user_id | question_id | given_answers | multianswer_count |
+---------+-------------+---------------+-------------------+
| John | 1 | Pooch | 1 |
| John | 2 | Duke,Duck | 2 |
| Sally | 1 | Pouch,Pooch | 2 |
| Sally | 2 | Peach | 1 |
+---------+-------------+---------------+-------------------+
次に、別のサブクエリを使用してmultianswer_count = 1の行を除外します。
SELECT * FROM (SELECT user_id,question_id,given_answers,
(LENGTH(given_answers) - LENGTH(REPLACE(given_answers,',','')))+1 multianswer_count
FROM (SELECT user_id,question_id,GROUP_CONCAT(DISTINCT answer_value) given_answers
FROM answers GROUP BY user_id,question_id) A) AA WHERE multianswer_count > 1;
これは私が得たものです:
+---------+-------------+---------------+-------------------+
| user_id | question_id | given_answers | multianswer_count |
+---------+-------------+---------------+-------------------+
| John | 2 | Duke,Duck | 2 |
| Sally | 1 | Pouch,Pooch | 2 |
+---------+-------------+---------------+-------------------+
基本的に、私は3つのテーブルスキャンを実行しました。1つはメインテーブル、2つは小さなサブクエリです。結合なし!!!
試してみる !!!
私自身、joinメソッドが好きです。
SELECT a.user_id FROM answers a
INNER JOIN answers a1 ON a1.question_id=1 AND a1.answer_value='Pooch'
INNER JOIN answers a2 ON a2.question_id=2 AND a2.answer_value='Peach'
GROUP BY a.user_id
pdateより大きなテーブル(約100万行)でテストした後、このメソッドは元の質問で述べた単純なOR
メソッドよりも大幅に時間がかかりました。
大量のデータセットがある場合は、2つのインデックスを作成します。
データの編成方法により、複数回参加する必要があります。どの質問のどの値が最も一般的でないかがわかっている場合、クエリを少し高速化できるかもしれませんが、オプティマイザがそれを実行する必要があります。
次のようにクエリを試してください:
SELECT a1.user_id FROM回答a1 WHERE a1.question_id = 1 AND a1.answer_value = 'Pooch' INNER JOIN回答a2 ON a2.question_id = 2 AND a2.answer_value = 'ピーチ' AND a1.user_id = a2.user_id
テーブルa1は最初のインデックスを使用する必要があります。データの分散に応じて、オプティマイザはどちらのインデックスも使用できます。インデックス全体からクエリ全体が満たされる必要があります。
これに取り組む1つの方法は、user_idのサブセットを取得して、2番目の一致についてそれらをテストすることです。
SELECT user_id
FROM answers
WHERE question_id = 1
AND answer_value = 'Pooch'
AND user_id IN (SELECT user_id FROM answers WHERE question_id=2 AND answer_value = 'Peach');
Rolandoの構造を使用:
CREATE TABLE answers (user_id VARCHAR(10),question_id INT,answer_value VARCHAR(20));
INSERT INTO answers VALUES
('Sally',1,'Pouch'),
('Sally',2,'Peach'),
('John',1,'Pooch'),
('John',2,'Duke');
INSERT INTO answers VALUES
('Sally',1,'Pooch'),
('Sally',2,'Peach'),
('John',1,'Pooch'),
('John',2,'Duck');
収量:
mysql> SELECT user_id FROM answers WHERE question_id = 1 AND answer_value = 'Pooch' AND user_id IN (SELECT user_id FROM answers WHERE question_id=2 AND answer_value = 'Peach');
+---------+
| user_id |
+---------+
| Sally |
+---------+
1 row in set (0.00 sec)