使用依赖于相关性的计算列进行SELECT

时间:2009-08-17 21:51:57

标签: sql sql-server calculated-columns

我没有做很多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,如果重要的话,我无法更改数据库架构。

我还希望将其保留为一个自包含查询,而不必创建存储过程或临时表。

3 个答案:

答案 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

只有在所有您要搜索的列中,首先是索引,然后是第二个具有高基数(许多不同的值)时,这才会有效。

请参阅我的博客中有关效果详情的文章: