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 岁以下等的用户

最好(最有效)的方法是从用户表到答案表有多个连接(每个所需的答案条件一个)

例如:

如果我想获得喜欢狗和红色的用户,我可以使用以下 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

您的基本查询看起来很好。随着您变得更加详细,您将根据需要如何组合条件来稍微不同地构建 WHERE 子句。

例如,在您提供的示例中,红色或紫色都是可接受的答案,您可以像这样构造 WHERE 子句:

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

如果只有某些答案集是可以接受的,它会变得更加复杂,所以如果“Red”和“Dogs”或“Purple”和“Cats”是可以接受的,它看起来更像这样:

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')
  )

如果您的条件变得更复杂,您可能需要阅读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 回答
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子句,这很容易编写/阅读/理解/维护(请参阅最后三行上面的代码块)。

更新:

对于性能分析,比较这两个查询:

执行查询后,单击结果上方的“查看执行计划”链接,查看 SQL 在幕后做了什么)

我建议您在自己的数据库上运行这些查询,您可能已经在其中创建了适当的索引,并且数据量足以产生相关结果。

我不是 SQL 性能专家,但我有一种预感,Ann L. 的解决方案可能更高效,并且可以更好地扩展到大量数据。但这又只是一种预感。如果您可以在您的环境中执行测试,您可以看到实际结果。

于 2012-10-13T12:05:57.753 回答