3

3 つのテーブルがあるとします。

User Table
{
    UserId INT,
    Username NVARCHAR
    ...
}

Questions
{
    QuestionId INT
    QuestionText NVARCHAR
}

Answers
{
    AnswerId INT,
    QuestionId INT,
    UserId INT,
    Answer NVARCHAR
}

この構造は明らかに過度に単純化されていますが、この例の目的には十分です。

たとえば、特定の質問に対して特定の回答を持っているユーザーを選択する最善の方法は何でしょうか - テーブルに次のデータが入力されていると仮定します。

ユーザーテーブル

UserId              Username                ...
--------------------------------------------------------------------------------------------------------
1                   User1                   ... 
2                   User2                   ... 
3                   User3                   ...
4                   User4                   ...
5                   User5                   ...
6                   User6                   ...
7                   User7                   ...
8                   User8                   ...
9                   User9                   ...
10                  User10                  ...
...                 ...                     ...

etc

質問表

QuestionId              QuestionText
--------------------------------------------------------------------------------------------------------
1                       What is your favorite color?
2                       What do you prefer cats or dogs?
3                       Do you prefer if it is too hot or too cold?
4                       What is your favorite season (Summer, Autumn (Fall), Winter, Spring)?
5                       How Old Are you?
...                     ...

etc

回答表

AnswerId                QuestionId              UserId          Answer
--------------------------------------------------------------------------------------------------------
1                       1                       1               Red 
2                       1                       2               Red
3                       1                       3               Blue
4                       1                       4               Green
5                       1                       5               Black
6                       2                       6               Cats
7                       2                       1               Dogs
8                       3                       1               Too Cold
9                       4                       1               Spring
10                      5                       1               22
11                      2                       4               Dogs
12                      3                       4               Too Hot
13                      3                       3               Too Cold
14                      5                       6               46
15                      1                       8               Purple

犬と赤や紫が好きで50歳未満のユーザーを選択したい場合など

これを行う最善の (最も効率的な) 方法は、ユーザー テーブルから回答テーブルへの複数の結合 (必要な回答条件ごとに 1 つ) を行うことでしょうか。

例えば:

犬と赤が好きなユーザーを獲得したい場合は、次の MSSQL を使用できます。

SELECT * 
FROM 
Users 
JOIN Answers As a1 
ON Users.UserId = a1.UserId 
JOIN Answers as a2 
ON Users.UserId = a2.UserId 
WHERE 
    (
        a1.QuestionId = 1 AND 
        a1.Answer = 'Red'
    ) AND 
    (
        a2.QuestionId = 2 AND 
        a2.Answer = 'Dogs'
    )

多数の回答条件が存在する可能性があります。

基本的に私が求めている質問は、同じ列を持つ同じテーブルの複数の行に条件があるクエリを作成する最良の方法は何ですか...

わかりにくい場合は申し訳ありませんが、ご不明な点がございましたら、お気軽にお問い合わせください。できる限りお答えします...

ありがとう。

4

2 に答える 2

3

PIVOT 演算子を使用するオプションもあります。

上記で提案したクエリは次のように記述できます。

select UserId, UserName
from (
  select
    u.UserId,
    u.UserName,
    case 
      when a.QuestionId = 1 then 'Color'
      when a.QuestionId = 2 then 'Animal'
      when a.QuestionId = 3 then 'Temperature'
      when a.QuestionId = 4 then 'Season'
      when a.QuestionId = 5 then 'Age'
    end as Question,
    a.Answer
  from Users u
  join Answers a on a.UserId = u.UserId
) as SourceTable
pivot (
  max(Answer)
  for Question in (
    [Color], 
    [Animal], 
    [Temperature], 
    [Season], 
    [Age])
) as pivotTable

where Animal = 'Dogs'
  and Color in ('red', 'purple')
  and Age < 50

これをオンラインでテストするためのリンクは次のとおりです。http://www.sqlfiddle.com/#!3/5c960/23

はい、クエリは面倒に見えますが、一度記述して (質問がそれほど頻繁に変更されないと仮定して)where句を変更するだけで、記述/読み取り/理解/維持が非常に簡単になります (上記のコードブロック)。

アップデート:

パフォーマンス分析のために、次の 2 つのクエリを比較します。

(クエリを実行した後、結果の上にある[実行計画の表示]リンクをクリックして、SQL が内部で何を行っているかを確認します)

ただし、適切なインデックスが既に作成されていて、適切な結果を生成するのに十分な量のデータが存在する可能性がある独自のデータベースでこれらのクエリを実行することをお勧めします。

私は SQL パフォーマンスの専門家ではありませんが、Ann L. のソリューションはより効率的で、大量のデータにうまくスケーリングできるという予感があります。しかし、これもまた、ただの予感です。環境でテストを実行できれば、実際の結果を確認できます。

于 2012-10-13T12:05:57.753 に答える
3

基本的なクエリは問題ないようです。より複雑になると、条件をどのように組み合わせる必要があるかに応じて、WHERE 句の構成が少し異なります。

たとえば、あなたが提供した例では、赤または紫のいずれかが受け入れられる回答であり、次のように WHERE 句を作成できます。

WHERE (a1.QuestionId = 1 AND (a1.Answer IN ('Red','Purple')) 
  AND (a2.QuestionId = 2 AND a2.Answer = 'Dogs')

特定の回答セットのみが許容される場合はさらに複雑になるため、「赤」と「犬」または「紫」と「猫」が許容される場合は、次のようになります。

WHERE 
  (
          (a1.QuestionId = 1 AND a1.Answer = 'Red')
      AND (a2.QuestionId = 2 AND a2.Answer = 'Dogs')
  )
  OR
  (
          (a1.QuestionId = 1 AND a1.Answer = 'Purple')
      AND (a2.QuestionId = 2 AND a2.Answer = 'Cats')
  )

条件がさらに複雑になる場合は、Dynamic Search Conditions in T-SQL を参照してください。条件は動的ではありませんが、有益な情報がたくさんあります。

最後に、どの質問 ID がどの回答に対応するかについて混乱しやすいため、特にそれらが適切で人間が認識できる値でない場合は、CTE を使用して回答を事前に選択しておくと役立ちます。

WITH Colors
AS   (
    SELECT *
    FROM   Answers
    WHERE  QuestionID = 1
)
,    Animals
AS   (
    SELECT *
    FROM   Answers
    WHERE  QuestionID = 2
)
SELECT   *
FROM     Users 
   JOIN  Colors
       ON  Users.UserID = Colors.UserID
   JOIN  Animals
       ON  Users.UserID = Animals.UserID
WHERE   (
        Colors.Answer = 'Red'
    AND Animals.Answer = 'Dogs'
    )
    OR  (
        Colors.Answer = 'Purple'
    AND Animals.Answer = 'Cats'
    )
于 2012-10-13T11:36:42.983 に答える