【问题标题】:SQL Server: display only rows where conditional concatinated column is not nullSQL Server:仅显示条件连接列不为空的行
【发布时间】:2013-04-03 09:51:03
【问题描述】:

是的,我已经和这个问题斗争了一段时间,虽然我有一个有效的查询,但它让我觉得这是不合逻辑的。如果我表明我的意思会更容易:

我有一个表格,其中包含工作 ID、电子邮件地址和一个布尔值“应该使用”列。

CREATE TABLE LWEmail
(ID int, Email varchar(64), MustUse int)

INSERT INTO LWEmail VALUES(1,'adfgae@asfdvaerg.com',1)
INSERT INTO LWEmail VALUES(1,'sdfghsth@asfdvaerg.com',1)
INSERT INTO LWEmail VALUES(1,'admjury@asfdvaerg.com',0)
INSERT INTO LWEmail VALUES(2,'dyj@asfdvaerg.com',0)
INSERT INTO LWEmail VALUES(2,'adynee@asfdvaerg.com',0)
INSERT INTO LWEmail VALUES(3,'kitu@asfdvaerg.com',1)
INSERT INTO LWEmail VALUES(3,'aswtrhe@asfdvaerg.com',1)
INSERT INTO LWEmail VALUES(3,'abetr@asfdvaerg.com',1)
INSERT INTO LWEmail VALUES(3,'aeryje@asfdvaerg.com',0)
INSERT INTO LWEmail VALUES(3,'eyj@asfdvaerg.com',0)
INSERT INTO LWEmail VALUES(4,'dej@asfdvaerg.com',1)
INSERT INTO LWEmail VALUES(4,'aetyj@asfdvaerg.com',1)
INSERT INTO LWEmail VALUES(4,'ey@asfdvaerg.com',0)
INSERT INTO LWEmail VALUES(5,'egn@asfdvaerg.com',0)
INSERT INTO LWEmail VALUES(5,'egrn@asfdvaerg.com',0)
INSERT INTO LWEmail VALUES(6,'bneyh@asfdvaerg.com',1)
INSERT INTO LWEmail VALUES(6,'eryh@asfdvaerg.com',1)
INSERT INTO LWEmail VALUES(6,'adfeyj@asfdvaerg.com',0)

以及根据“必须使用”标准将这些电子邮件地址连接到每个 ID 一行的查询:

SELECT DISTINCT
CONVERT (varchar(24), [LWEmail].[ID]) AS LogBatch,
STUFF((SELECT CAST(', ' + LWEmail2.Email  AS VARCHAR(MAX))
         FROM   [LWEmail] AS LWEmail2
         WHERE  LWEmail2.[ID] = [LWEmail].[ID] and [MustUse] = 1
         FOR XML PATH('')), 1,2,'') AS Emails
FROM   [LWEmail]

这会产生:

LOGBATCH   EMAILS
1      adfgae@asfdvaerg.com, sdfghsth@asfdvaerg.com
2      (null)
3      kitu@asfdvaerg.com, aswtrhe@asfdvaerg.com, abetr@asfdvaerg.com
4      dej@asfdvaerg.com, aetyj@asfdvaerg.com
5      (null)
6      bneyh@asfdvaerg.com, eryh@asfdvaerg.com

如果“电子邮件”返回 null(第 2 行和第 5 行),我还希望它忽略该行 所以逻辑上我试图添加:

  WHERE Emails IS NOT NULL

最后。这不起作用:'无效的列名“电子邮件”'。但这确实有效:

SELECT DISTINCT
CONVERT (varchar(24), [LWEmail].[ID]) AS LogBatch,
STUFF((SELECT CAST(', ' + LWEmail2.Email  AS VARCHAR(MAX))
         FROM   [LWEmail] AS LWEmail2
         WHERE  LWEmail2.[ID] = [LWEmail].[ID] and [MustUse] = 1
         FOR XML PATH('')), 1,2,'') AS Email

FROM   [LWEmail]

WHERE 
STUFF((SELECT CAST(', ' + LWEmail2.Email  AS VARCHAR(MAX))
         FROM   [LWEmail] AS LWEmail2
         WHERE  LWEmail2.[ID] = [LWEmail].[ID] and [MustUse] = 1
         FOR XML PATH('')), 1,2,'') IS NOT NULL

为什么我不能将“电子邮件”作为条件引用,而由于括号和逻辑顺序,执行路径将使其成为首先要执行的事情之一,使其可用于评估?例如,您可以使用转换后的日期或数学运算来执行此操作。有什么见解吗?为了效率,我宁愿参考和评估已经计算过的东西,而不是计算两次。真的只是想学习并提高效率。

【问题讨论】:

  • 这很容易解决!知道这很简单,只需要在 WHERE 可以通过使其成为子查询来评估之前强制创建“电子邮件”列。感谢大家的快速响应!

标签: sql sql-server-2008 reference concatenation


【解决方案1】:

您说的是“逻辑顺序”,但从逻辑上讲,SELECT 执行 WHERE。您可以将其放在子查询中:

SELECT * FROM (
  SELECT DISTINCT
  CONVERT (varchar(24), [LWEmail].[ID]) AS LogBatch,
  STUFF((SELECT CAST(', ' + LWEmail2.Email  AS VARCHAR(MAX))
         FROM   [LWEmail] AS LWEmail2
         WHERE  LWEmail2.[ID] = [LWEmail].[ID] and [MustUse] = 1
         FOR XML PATH('')), 1,2,'') AS Emails
  FROM   [LWEmail]
) t
where Emails is not null

有关处理顺序,请参见例如维基百科上的Select (SQL)

  • FROM
  • ON
  • WHERE
  • GROUP BY
  • HAVING
  • SELECT
  • DISTINCT
  • ORDER BY

还有:

为了效率,我宁愿参考和评估已经计算过的东西,而不是计算两次。

SQL Server 有很多技巧,它可以观察到相同的计算被要求进行两次,并且将避免实际上多次执行计算。另一方面,仅仅因为一个计算在您的语句中只出现一次并不能保证系统实际上不会多次计算它。

在这种情况下,我同意减少它只是因为它看起来很乱。但是您应该知道,在 SQL 语言中,您通常试图告诉系统您想要什么,而不是如何去做。这就是优化器的工作。

【讨论】:

  • 是的,已经做了一些过程编程(java、C++ 等),如果不拖累思维过程,很难转移到操作性语言上。感谢您提供额外的信息。
【解决方案2】:

您显然不能在同一级别上创建的WHERE 子句上调用ALIASSQL Order of Operation如下:

  • FROM 子句
  • WHERE 子句
  • GROUP BY 子句
  • HAVING 子句
  • SELECT 子句(此处创建别名)
  • ORDER BY 子句

ALIAS 是在 SELECT 子句上创建的,WHERE 子句首先执行。您想从别名调用的唯一解决方案是将整个查询包装在子查询中。例如,

SELECT  * 
FROM 
        (
            SELECT  DISTINCT CONVERT (varchar(24), [LWEmail].[ID]) AS LogBatch,
                    STUFF(( SELECT CAST(', ' + LWEmail2.Email  AS VARCHAR(MAX))
                            FROM   [LWEmail] AS LWEmail2
                            WHERE  LWEmail2.[ID] = [LWEmail].[ID] and
                                   [MustUse] = 1
                            FOR XML PATH('')), 1,2,'') AS Emails
            FROM    [LWEmail]
        ) subQuery
WHERE   Emails IS NOT NULL

【讨论】:

    【解决方案3】:

    试试:

    SELECT *
    FROM 
    (SELECT DISTINCT
    CONVERT (varchar(24), [LWEmail].[ID]) AS LogBatch,
    STUFF((SELECT CAST(', ' + LWEmail2.Email  AS VARCHAR(MAX))
             FROM   [LWEmail] AS LWEmail2
             WHERE  LWEmail2.[ID] = [LWEmail].[ID] and [MustUse] = 1
             FOR XML PATH('')), 1,2,'') AS Email
    
    FROM   [LWEmail] ) Sub
    WHERE Email IS NOT NULL
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-10-16
      • 1970-01-01
      • 1970-01-01
      • 2012-09-17
      • 2011-11-21
      • 2018-04-25
      • 2021-02-03
      相关资源
      最近更新 更多