1

DB が正しく設計されておらず、多くのレコードが含まれている既存のサイトがあるため、DB 構造を変更できません。

最新号のデータベースには、主に 4 つのテーブル、ユーザー、質問、オプション、および回答が含まれています。質問とオプションの標準セットがありますが、ユーザーごとに、質問とオプションのセットごとに回答テーブルに 1 つの行があります。DB 構造とサンプル データはSQL fiddleで入手できます。

高度な検索の新しい要件として、複数の検索フィルターを適用してユーザーを見つける必要があります。入力例と期待される出力は、 SQL Fiddleのコメントに記載されています。

すべてのタイプの結合、交差を適用しようとしましたが、何らかの理由で常に失敗します。DBには多くのレコード(10000以上のユーザー、100以上の質問、500以上のオプション、回答テーブルの500000以上のレコード)が含まれているため、正しいクエリ、できれば軽量/最適化された結合を書くのを手伝ってもらえますか?

編集:2つの回答に基づいて、次のクエリを使用しました

SELECT u.id, u.first_name, u.last_name
FROM users u
    JOIN answers a ON a.user_id = u.id
WHERE (a.question_id = 1 AND a.option_id IN (3, 5))
    OR (a.question_id = 2 AND a.option_id IN (8))
GROUP BY u.id, u.first_name, u.last_name
HAVING
    SUM(CASE WHEN (a.question_id = 1 AND a.option_id IN (3, 5)) THEN 1 ELSE 0 END) >=1
    AND SUM(CASE WHEN (a.question_id = 2 AND a.option_id IN (8)) THEN 1 ELSE 0 END) >= 1;

注意:実際のデータベースでは、列とuser_idテーブルのインデックスが作成されます。question_idoption_idanswers

SQL Fiddleで指定された実行中のクエリ。

dnoeth の回答に対するSQL Fiddle 。

calcinai の回答に対するSQL Foddle

4

2 に答える 2

1

OR を使用してすべてのnフィルターを WHERE に追加し、AND を使用して HAVING(SUM(CASE)) でそれらを繰り返します。

SELECT u.id, u.first_name, u.last_name
FROM users u JOIN answers a
  ON a.user_id = u.id
JOIN questions q
  ON a.question_id = q.id
JOIN question_options o
  ON a.option_id = o.id
WHERE (q.question = 'Language known' AND o.OPTION IN ('French','Russian'))
   OR (q.question = 'height' AND o.OPTION = '1.51 - 1.7')
GROUP BY u.id, u.first_name, u.last_name
HAVING
  SUM(CASE WHEN (q.question = 'Language known' AND o.OPTION IN ('French','Russian')) THEN 1 ELSE 0 END) >=1
AND 
  SUM(CASE WHEN (q.question = 'height'         AND o.OPTION = '1.51 - 1.7')          THEN 1 ELSE 0 END) >= 1
;

結合をより読みやすい標準 SQL 構文に変更しました。

于 2013-09-17T06:44:49.737 に答える