SQL Server:仅显示条件连接列不为空的行

时间:2013-04-11 09:06:17

标签: sql sql-server-2008 reference concatenation

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

我有一张工作表i.d,电子邮件地址,以及应该使用的布尔值'列。

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)

根据' MustUse'以及将这些电子邮件地址连接到每个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

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

3 个答案:

答案 0 :(得分:2)

您说“逻辑顺序”,但从逻辑上讲,SELECTWHERE之后执行。你可以把它放在子查询中:

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语言中,你通常会试图告诉系统你想要什么,而不是如何做到。这是优化工作。

答案 1 :(得分:1)

您显然无法调用在同一级别创建的ALIAS子句上的WHERESQL Order of Operation如下:

  • FROM clause
  • WHERE子句
  • GROUP BY子句
  • HAVING条款
  • SELECT子句(此处创建ALIAS)
  • 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

答案 2 :(得分:1)

尝试:

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