使用exists select 1获取任何列包含序列的行

时间:2018-06-10 07:32:59

标签: sql sql-server

我有一个包含三列的表格,其中包含以下值(dbFiddle

C1      C2         C3
----------------------------
Red     Yellow     Blue
null    Red        Green
Yellow  null       Violet

我尝试创建一个返回包含值"黄色"的所有行的查询。不使用INOR。如果我执行以下查询:

SELECT 1 
FROM test 
WHERE CONCAT(C1, C2, C3) LIKE '%Yellow%'

它正确返回指定的行。但是,如果我尝试在exists

中使用此查询
SELECT * 
FROM test 
WHERE EXISTS (SELECT 1 FROM test WHERE CONCAT(C1, C2, C3) LIKE '%Yellow%')

它返回所有行,而不仅仅是"黄色"字。我在这里做错了什么?

非常感谢任何帮助。

3 个答案:

答案 0 :(得分:2)

<强> RE

SELECT 1 FROM test WHERE CONCAT(C1, C2, C3) LIKE '%Yellow%'
  

“正确返回指定的行”

select返回单个列1,但这是因为有一行在其文本的某处有一列包含Yellow

这是因为EXISTS

  

如果子查询包含任何行,则返回TRUE。

即。以下所有查询都返回了test表中的所有行:

SELECT * FROM test WHERE EXISTS (SELECT 1);

SELECT * FROM test WHERE EXISTS (SELECT 0);

SELECT * FROM test WHERE EXISTS (SELECT NULL);

...只是因为SELECT至少返回一行!

EXISTS的通常用法还包括将EXISTS中的子查询与外部选择相关联。

相关示例

在下面的人为例子中,我们有4个人住在两个房子里。在这里,我们使用EXISTS来确定幸福者的姓名,并且还有一个其他的人也很幸福生活在同一个(相关)的房子里。

CREATE TABLE House
(
    HouseId INT PRIMARY KEY,
    Name VARCHAR(MAX)
);

CREATE TABLE Person
(
    PersonId INT PRIMARY KEY,
    HouseId INT FOREIGN KEY REFERENCES HOUSE(HouseId),
    Name VARCHAR(MAX),
    IsHappy BIT
);

INSERT INTO House(HouseId, Name) VALUES (1, 'House1'), (2, 'House2');

INSERT INTO Person(PersonId, HouseId, Name, IsHappy) VALUES 
(1, 1, 'Joe', 0), 
(2, 1, 'Jim', 1),
(3, 2, 'Fred', 1),
(4, 2, 'Mary', 1);

SELECT pOuter.Name
FROM Person pOuter
WHERE pOuter.IsHappy = 1
AND EXISTS 
    (SELECT 1 
        FROM Person pInner 
        WHERE pInner.HouseId = pOuter.HouseId 
        AND pInner.PersonId != pOuter.PersonId
        AND pInner.IsHappy = 1);

返回

Mary
Fred

(显然有其他方法可以找到相同的结果,例如找到House Id的分组,其中有2个或更多幸福的人,等等)

答案 1 :(得分:1)

exists子句检查指定一个子查询来测试是否存在行。

所以当任何列包含exists (SELECT 1 FROM test WHERE CONCAT(C1, C2, C3) LIKE '%Yellow%')数据时,yellow始终会有行。

如果要使用exists,则需要通过外部表设置内部exists查询CONCAT(t.C1, t.C2, t.C3)

SELECT * 
FROM test t 
where exists (SELECT 1 FROM test WHERE CONCAT(t.C1, t.C2, t.C3) LIKE '%Yellow%')

您不需要使用exists仅在where上设置条件

SELECT * 
FROM test 
where CONCAT(C1, C2, C3) LIKE '%Yellow%'

sqlfiddle

答案 2 :(得分:1)

我会使用cross apply

SELECT 1 
FROM test t CROSS APPLY
     (SELECT COUNT(*) as cnt
      FROM (VALLUES (C1), (C2), (C3)) V(C)
      WHERE c = 'Yellow'
     ) v
WHERE cnt > 0;

您可以轻松地将其调整为子查询:

SELECT . . .
FROM test t
WHERE EXISTS (SELECT 1
              FROM (VALLUES (C1), (C2), (C3)) V(C)
              WHERE c = 'Yellow'
             ) ;

就个人而言,我更喜欢将每个值直接比较为'Yellow',而不是使用LIKE。例如,这与“黄绿色”或“黄色”是名称的一部分的任何其他值不匹配。

而且,只是为了记录,你仍然可以使用布尔逻辑,即使你不使用ORIN

where not (coalesce(c1, '') <> 'Yellow' and
           coalesce(c2, '') <> 'Yellow' and
           coalesce(c3, '') <> 'Yellow' 
          )

从技术上讲,这可能是解决您问题的“最简单”的解决方案。但是,我仍然更喜欢apply方法,因为意图更清晰。