2009-08-12 80 views
0

中使用复合选择项这个问题最好用一个简单的例子来描述。在条款

为什么我不能这样做?

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

为什么downvote? – tomfanning 2009-08-12 15:52:28

+2

将ContractLength添加到嵌套视图,并且不再需要在该视图之外执行联接。 – 2009-08-12 15:56:32

回答

1

选择列表虚拟表从由返回,其中顺序子句的变换。条款不知道选择列表。此外,在中定义的列的任何转换均不会强制执行表或索引扫描,其中子句不是sargable,而强制SQL执行表或索引扫描。换句话说,这样做绝对会杀死性能。

+0

对原始问题的简明回答,表明它只是在查询中的其他地方工作。非常感谢。 – tomfanning 2009-08-12 15:55:38

1

尝试:

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 
+0

-1,我想你错过了一点 - 我给了一个简单的例子。也许太简单了。 select语句的别名可能包含很大的计算,子查询等等。当然,你可以使用原始字段进行过滤 - 这不是重点。 – tomfanning 2009-08-12 15:19:29

+0

@tomfanning,用更好的例子编辑你的问题。我回答你的问题,而不是你在想什么(我无法理解你的想法)。 – 2009-08-12 15:35:39

+0

@KM,问题是“为什么我不能做这个特定的事情”,而不是“解决这个查询问题”。不过,我已经根据Robin Day的回答添加了一个特定于域的问题和使用嵌入式视图进行修改。 – tomfanning 2009-08-12 15:45:19

3

您可以使用派生表/嵌套视图...

select 
    fullname 
from 
(
    select 
     (lastname + ', ' + firstname) as fullname 
    from 
     people 
) myview 
where 
    myview.fullname = 'Bloggs, Joe' 

编辑:只是为了澄清,这是展现你问这个概念。在这个特定的例子中,你的WHERE子句应该检查firstname ='Joe'和lastname ='Bloggs',因为KM已经回答而不是检查全名。

+0

我喜欢你的编辑信息,基本上重复我的答案。然而,我的答案到目前为止已经收到两次反​​对票... – 2009-08-12 15:38:45

+0

@Robin Day:你没有真正回答这个问题,你只是提供了一个解决方法,让他获得他想要的抽象。 – MyItchyChin 2009-08-12 15:43:21

+0

@CptSkippy,没有办法 – 2009-08-12 15:49:48

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 
+0

如果我正确理解他的逻辑,那么这个策略已经被这个KM推荐,因为DATEADD()被调用了Clients表中的所有内容。这是它的错误。 – tomfanning 2009-08-12 16:15:35

+0

您的“最终跟进”与我上面的建议完全相同,除了我的SELECT语句中的星号,它只是删除了一些冗长的内容。 – 2009-08-12 16:41:48

0

如何使这个查询工作与IN和多列?这适用于Oracle,但不适用于T-SQL。

select (lastname + ', ' + firstname) as fullname 
from people 
where ((lastname, firstname)) IN (('Bloggs', 'Joe'))