说我有三张桌子:
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'
)
可能有很多答案条件。
基本上我问的问题是,编写查询的最佳方法是在同一个表中具有相同列的多行的条件...
很抱歉,如果这令人困惑,请随时提出任何问题,我会尽力回答这些问题......
感谢。
答案 0 :(得分: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')
)
如果您的情况变得更复杂,您可能需要阅读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'
)
答案 1 :(得分:3)
还可以使用PIVOT operator。
以上建议的查询是如何编写的:
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
子句,这很容易写/读/理解/ maintain(参见上面代码块中的最后三行)。
<强>更新强>
对于性能分析,请比较以下两个查询:
(执行查询后,点击结果上方的&#34; 查看执行计划&#34;链接以查看SQL在幕后的内容)< / p>
我建议您在自己的数据库上运行这些查询,您可能已经创建了适当的索引,并且数据量足以产生相关结果。
我没有SQL性能专家,但我有一种预感,Ann L.'s solution可以更高效,并且可以更好地扩展到大量数据。但同样,这只是一种预感;如果您可以对您的环境进行测试,您可以看到实际结果。