3

我不会做很多 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' OR Col3 = 1 OR Col4 = 5 计算结果 > 1 并且结果集如下所示:

> | ID | Cal |
> | 1  |  2  |
> | 2  |  2  |
> | 3  |  2  |

我正在使用 T-SQL 和 SQL Server 2005,如果重要的话,我无法更改数据库架构。

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

4

3 回答 3

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 
于 2009-08-17T22:06:09.300 回答
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;
于 2009-08-17T21:57:59.800 回答
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

仅当您要搜索的所有列首先被索引并且其次具有高基数(许多不同的值)时,这才会有效。

有关性能详细信息,请参阅我的博客中的这篇文章:

于 2009-08-17T21:58:37.443 回答