在条款
中使用复合选择项这个问题最好用一个简单的例子来描述。在条款
为什么我不能这样做?
select (lastname + ', ' + firstname) as fullname
from people
where fullname = 'Bloggs, Joe'
相反,我必须这样做:
select (lastname + ', ' + firstname) as fullname
from people
where (lastname + ', ' + firstname) = 'Bloggs, Joe'
这气味对我不好。
查询越复杂,这个问题就越严重。
后续
这是基于从问题起源于现实世界的问题的一个更好的例子。
SELECT ClientID,
Name,
ContractStartDate,
ContractDetails.ContractLength,
DATEADD(MONTH, ContractDetails.ContractLength, ContractStartDate)
as ContractEndDate
FROM Clients
LEFT OUTER JOIN ContractDetails
ON Clients.ClientID = ContractDetails.ClientID
WHERE DATEADD(MONTH, ContractDetails.ContractLength, ContractStartDate)
> '2009-06-30'
我已经重写了查询以使用建议的嵌入视图。但它仍然包含重复 - 但这次是加入。
SELECT ClientID,
Name,
contractStartDate,
ContractDetails.ContractLength,
contractEndDate
FROM (
SELECT ClientID,
Name,
ContractStartDate,
DATEADD(MONTH, ContractDetails.ContractLength, contractStartdate)
AS contractEndDate
FROM Clients
LEFT OUTER JOIN ContractDetails
on Clients.ClientID = ContractDetails.ClientID
) myview
LEFT OUTER JOIN ContractDetails
on myview.ClientID = ContractDetails.ClientID
WHERE myview.ContractEndDate > '2009-06-30'
ORDER BY ClientID
该查询的点是找到所有活的客户端如在特定的时间点,在没有历史状态数据被保持(即计算从一个已知的合同开始日期和长度合同结束日期)。
任何人都可以想出一种消除这种重复的方法吗?
末次随访
罗宾天帮了我与我错过这里的关键,其实让我删除重复。然而,KM有一个观点,他说WHERE应该在嵌套视图上,而不是最终结果,这将需要重复部分语句(这是我试图避免的)。 在这种特殊情况下我可以逃脱它,因为我知道没有数百万的ContractDetails表中的记录,永远不会。
SELECT ClientID,
Name,
ContractStartDate,
myview.ContractLength,
ContractEndDate
FROM (
SELECT ClientID,
Name,
ContractStartDate,
DATEADD(MONTH, ContractDetails.ContractLength, ContractStartdate)
AS ContractEndDate,
ContractDetails.ContractLength as Length
FROM Clients
LEFT OUTER JOIN ContractDetails
on Clients.ClientID = ContractDetails.ClientID
) myview
WHERE myview.ContractEndDate > '2009-06-30'
ORDER BY ClientID
的选择列表是虚拟表从由返回,其中和顺序子句的变换。条款不知道选择列表。此外,在中定义的列的任何转换均不会强制执行表或索引扫描,其中子句不是sargable,而强制SQL执行表或索引扫描。换句话说,这样做绝对会杀死性能。
对原始问题的简明回答,表明它只是在查询中的其他地方工作。非常感谢。 – tomfanning 2009-08-12 15:55:38
尝试:
select
(lastname + ', ' + firstname) as fullname
from people
where lastname = 'Bloggs' AND firstname='Joe'
不过滤基于格式化输出“全名”的基础上,列,这应该是一个指数滤波器。
编辑
根据修改后的问题:
把条件派生表来限制它(并保持尽可能小)。我一眼就看到了查询的速度更快。我确定查询引擎足够聪明,不会执行DATEADD()两次,所以不要担心。
SELECT ClientID,
Name,
contractStartDate,
ContractDetails.ContractLength,
contractEndDate
FROM (
SELECT ClientID,
Name,
ContractStartDate,
DATEADD(MONTH, ContractDetails.ContractLength, contractStartdate)
AS contractEndDate
FROM Clients
LEFT OUTER JOIN ContractDetails
on Clients.ClientID = ContractDetails.ClientID
WHERE DATEADD(MONTH, ContractDetails.ContractLength, contractStartdate) > '2009-06-30'
) myview
LEFT OUTER JOIN ContractDetails
on myview.ClientID = ContractDetails.ClientID
ORDER BY ClientID
-1,我想你错过了一点 - 我给了一个简单的例子。也许太简单了。 select语句的别名可能包含很大的计算,子查询等等。当然,你可以使用原始字段进行过滤 - 这不是重点。 – tomfanning 2009-08-12 15:19:29
@tomfanning,用更好的例子编辑你的问题。我回答你的问题,而不是你在想什么(我无法理解你的想法)。 – 2009-08-12 15:35:39
@KM,问题是“为什么我不能做这个特定的事情”,而不是“解决这个查询问题”。不过,我已经根据Robin Day的回答添加了一个特定于域的问题和使用嵌入式视图进行修改。 – tomfanning 2009-08-12 15:45:19
您可以使用派生表/嵌套视图...
select
fullname
from
(
select
(lastname + ', ' + firstname) as fullname
from
people
) myview
where
myview.fullname = 'Bloggs, Joe'
编辑:只是为了澄清,这是展现你问这个概念。在这个特定的例子中,你的WHERE子句应该检查firstname ='Joe'和lastname ='Bloggs',因为KM已经回答而不是检查全名。
我喜欢你的编辑信息,基本上重复我的答案。然而,我的答案到目前为止已经收到两次反对票... – 2009-08-12 15:38:45
@Robin Day:你没有真正回答这个问题,你只是提供了一个解决方法,让他获得他想要的抽象。 – MyItchyChin 2009-08-12 15:43:21
@CptSkippy,没有办法 – 2009-08-12 15:49:48
是不是你编辑的例子过于复杂?有什么问题:
SELECT *
FROM (
SELECT ClientID,
Name,
ContractStartDate,
ContractLength,
DATEADD(MONTH, ContractDetails.ContractLength, contractStartdate)
AS contractEndDate
FROM Clients
LEFT OUTER JOIN ContractDetails
on Clients.ClientID = ContractDetails.ClientID
) myview
WHERE myview.ContractEndDate > '2009-06-30'
ORDER BY ClientID
如果我正确理解他的逻辑,那么这个策略已经被这个KM推荐,因为DATEADD()被调用了Clients表中的所有内容。这是它的错误。 – tomfanning 2009-08-12 16:15:35
您的“最终跟进”与我上面的建议完全相同,除了我的SELECT语句中的星号,它只是删除了一些冗长的内容。 – 2009-08-12 16:41:48
如何使这个查询工作与IN和多列?这适用于Oracle,但不适用于T-SQL。
select (lastname + ', ' + firstname) as fullname
from people
where ((lastname, firstname)) IN (('Bloggs', 'Joe'))
为什么downvote? – tomfanning 2009-08-12 15:52:28
将ContractLength添加到嵌套视图,并且不再需要在该视图之外执行联接。 – 2009-08-12 15:56:32