我没有做很多SQL,而且大多数时候,我正在做CRUD操作。偶尔我会得到一些更复杂的东西。所以,这个问题可能是一个新手问题,但我已经准备好了。我一直在努力解决这个问题几个小时,这是没用的。
所以,想象一下下面的表结构:
> | ID | Col1 | Col2 | Col3 | .. | Col8 |
我想选择ID和计算列。计算列的范围为0 - 8,它包含查询匹配的数量。我还想将结果集限制为仅包含具有一定数量匹配的行。
所以,从这个样本数据:
> | 1 | 'a' | 'b' | 1 | 2 |
> | 2 | 'b' | 'c' | 1 | 2 |
> | 3 | 'b' | 'c' | 4 | 5 |
> | 4 | 'x' | 'x' | 9 | 9 |
我想查询Col1 ='a'OR Col2 ='c'或Col3 = 1或Col4 = 5其中计算结果> 1,结果集如下:
> | ID | Cal |
> | 1 | 2 |
> | 2 | 2 |
> | 3 | 2 |
我正在使用T-SQL和SQL Server 2005,如果重要的话,我无法更改数据库架构。
我还希望将其保留为一个自包含查询,而不必创建存储过程或临时表。
答案 0 :(得分:4)
这个答案适用于SQL 2005,使用CTE稍微清理派生表。
WITH Matches AS
(
SELECT ID, CASE WHEN Col1 = 'a' THEN 1 ELSE 0 END +
CASE WHEN Col2 = 'c' THEN 1 ELSE 0 END +
CASE WHEN Col3 = 1 THEN 1 ELSE 0 END +
CASE WHEN Col4 = 5 THEN 1 ELSE 0 END AS Result
FROM Table1
WHERE Col1 = 'a' OR Col2 = 'c' OR Col3 = 1 OR Col4 = 5
)
SELECT ID, Result
FROM Matches
WHERE Result > 1
答案 1 :(得分:2)
这是一个利用布尔比较返回整数1或0这一事实的解决方案:
SELECT * FROM (
SELECT ID, (Col1='a') + (Col2='c') + (Col3=1) + (Col4=5) AS calculated
FROM MyTable
) q
WHERE calculated > 1;
请注意,您必须为布尔比较加括号,因为+
的优先级高于=
。此外,您必须将它全部放在子查询中,因为您通常无法在同一查询的WHERE
子句中使用列别名。
看起来你应该在子查询中使用WHERE
子句来限制它的行,但是你很可能最终会得到一个全表扫描,所以它可能不是一个大赢家。另一方面,如果您希望这样的限制极大地减少子查询结果中的行数,那么它是值得的。
Re Quassnoi的评论,如果你不能将布尔表达式视为整数值,应该有一种方法将布尔条件映射到整数,即使它有点冗长。例如:
SELECT * FROM (
SELECT ID,
CASE WHEN Col1='a' THEN 1 ELSE 0 END
+ CASE WHEN Col2='c' THEN 1 ELSE 0 END
+ CASE WHEN Col3=1 THEN 1 ELSE 0 END
+ CASE WHEN Col4=5 THEN 1 ELSE 0 END AS calculated
FROM MyTable
) q
WHERE calculated > 1;
答案 2 :(得分:1)
此查询更符合索引:
SELECT id, SUM(match)
FROM (
SELECT id, 1 AS match
FROM mytable
WHERE col1 = 'a'
UNION ALL
SELECT id, 1 AS match
FROM mytable
WHERE col2 = 'c'
UNION ALL
SELECT id, 1 AS match
FROM mytable
WHERE col3 = 1
UNION ALL
SELECT id, 1 AS match
FROM mytable
WHERE col4 = 5
) q
GROUP BY
id
HAVING SUM(match) > 1
只有在所有您要搜索的列中,首先是索引,然后是第二个具有高基数(许多不同的值)时,这才会有效。
请参阅我的博客中有关效果详情的文章: