1

是的,我已经为此奋斗了一段时间,尽管我有一个有效的查询,但它困扰着我,这是不合逻辑的。如果我表明我的意思会更容易:

我有一个包含工作 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

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

4

3 回答 3

2

您说“逻辑顺序”,但从逻辑上讲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

有关处理顺序,请参见例如Wikipedia 上的Select (SQL) :

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

还:

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

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

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

于 2013-04-11T09:08:58.963 回答
1

您显然不能调用在同一级别上创建ALIAS的子句。如下WHERESQL Order of Operation

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

ALIASis created onSELECT子句和子句首先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
于 2013-04-11T09:10:25.307 回答
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
于 2013-04-11T09:12:24.220 回答