【问题标题】:Query where any not null values also have a flag (bit) set查询任何非空值也设置了标志(位)的位置
【发布时间】:2018-06-01 11:04:11
【问题描述】:

我有一个 Customer 表,其中包含针对每个客户的 4 个可能的电话号码。每个电话号码也有一个标志。

我正在尝试查询以找到以下位置的客户: 如果他们提供的所有电话号码也都设置了标志。

所以,他们需要一个或多个电话号码 NOT NULL 和 对于每个不为空的电话号码,是否有标志 = 1

我想我可以编写一个很长而且很复杂的查询来得到这个,但是有没有我遗漏的简单方法?

CREATE TABLE #Listing (id INT,
Customer VARCHAR(50),
Phone1 VARCHAR(20) NULL,
Phone1Flagged BIT,
Phone2 VARCHAR(20) NULL,
Phone2Flagged BIT,
Phone3 VARCHAR(20) NULL,
Phone3Flagged BIT,
Phone4 VARCHAR(20) NULL,
Phone4Flagged BIT)

INSERT INTO #Listing VALUES(1, 'Dave', NULL, 0, NULL, 0, NULL, 0, NULL, 0)
INSERT INTO #Listing VALUES(2, 'Fred', '0712345678', 0, NULL, 0, NULL, 0, NULL, 0)
INSERT INTO #Listing VALUES(3, 'Bob', '0712121212', 1, '0123121212', 0, NULL, 0, NULL, 0)
INSERT INTO #Listing VALUES(4, 'Bill', NULL, 0, NULL, 0, '0799999999', 1, NULL, 0)
INSERT INTO #Listing VALUES(5, 'Bert', NULL, 0, NULL, 0, '0799999977', 0, '0799999988', 1)
INSERT INTO #Listing VALUES(6, 'Andy', '01212121212', 1, '0121212122', 1, '0799999977', 1, '0799999988', 1)

并查询:

SELECT * FROM #Listing

SELECT
    *
FROM
    #Listing
WHERE
    (
        Phone1 IS NULL
        OR
            (
                Phone1 IS NOT NULL
                AND Phone1Flagged = 1
            )
    )
    AND
        (
            Phone2 IS NULL
            OR
                (
                    Phone2 IS NOT NULL
                    AND Phone2Flagged = 1
                )
        )
--etc. etc. etc.

DROP TABLE #Listing

“希望”的结果

id  Customer    Phone1  Phone1Flagged   Phone2  Phone2Flagged   Phone3  Phone3Flagged   Phone4  Phone4Flagged
4   Bill        False       False   0799999999  True        False
6   Andy    01212121212 True    0121212122  True    0799999977  True    0799999988  True

【问题讨论】:

  • 您使用的是哪个数据库? SQL 服务器?甲骨文?
  • 样本数据和期望的结果会有所帮助。
  • @TimBiegeleisen - SQL Server 2014(添加了标签,抱歉!)
  • @GordonLinoff 在样本数据中添加了一些样本结果

标签: sql sql-server tsql select


【解决方案1】:

描述有点模糊,但您可以将条件重写为:

SELECT l.*
FROM #Listing l
CROSS APPLY (SELECT MIN(CASE WHEN (p IS NOT NULL AND f = 1) 
                             OR p IS NULL THEN 1 ELSE 0 END) r, COUNT(p) AS c
             FROM (VALUES(Phone1, Phone1Flagged),
                         (Phone2, Phone2Flagged),
                         (Phone3, Phone3Flagged),
                         (Phone4, Phone4Flagged)) s(p,f)
            ) sub
WHERE r= 1 AND c > 0;

DBFiddle Demo

输出:

┌────┬──────────┬─────────────┬───────────────┬────────────┬───────────────┬────────────┬───────────────┬────────────┬───────────────┐
│ id │ Customer │   Phone1    │ Phone1Flagged │   Phone2   │ Phone2Flagged │   Phone3   │ Phone3Flagged │   Phone4   │ Phone4Flagged │
├────┼──────────┼─────────────┼───────────────┼────────────┼───────────────┼────────────┼───────────────┼────────────┼───────────────┤
│  4 │ Bill     │ null        │ False         │ null       │ False         │ 0799999999 │ True          │ null       │ False         │
│  6 │ Andy     │ 01212121212 │ True          │ 0121212122 │ True          │ 0799999977 │ True          │ 0799999988 │ True          │
└────┴──────────┴─────────────┴───────────────┴────────────┴───────────────┴────────────┴───────────────┴────────────┴───────────────┘

【讨论】:

  • 这真是太棒了!但是 b) 返回 1 - Dave,他没有设置电话号码。
  • @BlueChippy 这与您的初始查询完全相同。我将添加条件来处理。
  • 谢谢@lad2025..这就是问题所在,我只能让我的查询处理大量嵌套语句。
  • @BlueChippy 请检查修改后的版本。现在它不等同于您的原始查询,而是按照您在评论中的描述处理所有空值。
  • @BlueChippy 很容易理解。使用VALUES,我取消了您的表,然后使用MIN 操作交换多个AND,并且我使用条件聚合来处理您的要求。 COUNT 用于排除所有 NULL 场景:)
【解决方案2】:

你的结构很好。但是这个问题有点难以理解。此答案基于:

因此,他们需要一个或多个不为空的电话号码,并且对于每个不为空的电话号码,它是否具有标志 = 1

为此,逻辑是:

SELECT l.*
FROM #Listing l
WHERE (Phone1 IS NOT NULL AND Phone1Flagged = 1) OR
      (Phone2 IS NOT NULL AND Phone2Flagged = 1) OR
      (Phone3 IS NOT NULL AND Phone3Flagged = 1) OR
      (Phone4 IS NOT NULL AND Phone4Flagged = 1) ;

【讨论】:

  • 至少拥有一个电话号码的所有客户......以及他们拥有的所有电话号码都会被标记。
猜你喜欢
  • 1970-01-01
  • 2011-03-09
  • 1970-01-01
  • 2010-11-23
  • 1970-01-01
  • 2016-08-03
  • 1970-01-01
  • 1970-01-01
  • 2011-11-09
相关资源
最近更新 更多