这个问题最好用一个简单的例子来表达。
为什么我不能这样做?
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
答案 0 :(得分:3)
您可以使用派生表/嵌套视图...
select
fullname
from
(
select
(lastname + ', ' + firstname) as fullname
from
people
) myview
where
myview.fullname = 'Bloggs, Joe'
编辑:只是为了澄清,这是为了展示你所询问的概念。在此特定示例中,WHERE子句应检查firstname ='Joe'和lastname ='Bloggs',因为KM已经回答,而不是检查全名。
答案 1 :(得分:1)
尝试:
select
(lastname + ', ' + firstname) as fullname
from people
where lastname = 'Bloggs' AND firstname='Joe'
不要根据格式化的输出“fullname”进行过滤,根据列进行过滤,这些列应该在索引中。
修改强>
根据您修改后的问题:
将条件放在派生表中以限制它(并使其尽可能小)。通过单独执行此操作,我看到查询速度更快。我确信查询引擎足够聪明,不能两次执行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
答案 2 :(得分:1)
选择列表是从返回的虚拟表的转换,其中和订单条款。这些子句不知道选择列表。此外,中子句中定义的列的任何转换都不是可搜索的,强制SQL执行表或索引扫描。换句话说,这样做绝对会扼杀性能。
答案 3 :(得分:1)
您编辑的示例是否过于复杂?出了什么问题:
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
答案 4 :(得分:0)
如何使此查询与IN和多列一起使用?这适用于Oracle,但不适用于T-SQL。
select (lastname + ', ' + firstname) as fullname
from people
where ((lastname, firstname)) IN (('Bloggs', 'Joe'))