Tsql 在where子句中使用复合选择项

Tsql 在where子句中使用复合选择项,tsql,syntax,Tsql,Syntax,这个问题最好用一个简单的例子来表达 为什么我不能这样做 select (lastname + ', ' + firstname) as fullname from people where fullname = 'Bloggs, Joe' 相反,我必须这样做: select (lastname + ', ' + firstname) as fullname from people where (lastname + ', ' + firstname) = 'Bloggs, Joe' 我觉得很

这个问题最好用一个简单的例子来表达

为什么我不能这样做

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
尝试:

不要基于格式化输出“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
尝试:

不要基于格式化输出“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

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

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

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

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

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

编辑:澄清一下,这是为了展示你所问的概念。在此特定示例中,WHERE子句应检查firstname='Joe'和lastname='Bloggs',因为KM已回答,而不是检查fullname。

选择列表是from、WHERE和order子句返回的虚拟表的转换。这些子句不知道select列表。此外,where子句中定义的列的任何转换都是不可搜索的,强制SQL执行表或索引扫描。换句话说,这样做绝对会降低性能。

选择列表是对from、where和order子句返回的虚拟表的转换。这些子句不知道select列表。此外,where子句中定义的列的任何转换都是不可搜索的,强制SQL执行表或索引扫描。换句话说,这样做绝对会降低性能。

您编辑的示例是否过于复杂?有什么问题吗

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

您编辑的示例是否过于复杂?有什么问题吗

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

如何使此查询与IN和multiple column一起工作?这适用于Oracle,但不适用于T-SQL

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

如何使此查询与IN和multiple column一起工作?这适用于Oracle,但不适用于T-SQL

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

-1、我想你没有抓住重点——我举了一个简单化的例子。也许太简单了。select语句的别名位可能包含大量的计算、子查询等等。当然,您可以使用原始字段进行筛选-这不是重点。@tomfanning,请用更好的示例编辑您的问题。我回答你的问题,而不是你在想什么(我看不懂你的心思)。@KM,问题是“为什么我不能做这个具体的事情”,而不是“解决这个问题”。尽管如此,我还是根据Robin Day的答案添加了一个特定于域的问题和一个使用嵌入式视图的返工。@KM感谢您更新您的答案。但是它仍然没有删除重复项。@tomfanning,没有办法删除重复项,请编写您的查询以提高速度,并使用琐碎的重复项-1,我认为您没有抓住要点-我给出了一个简单化的示例。也许太简单了。select语句的别名位可能包含大量的计算、子查询等等。当然,您可以使用原始字段进行筛选-这不是重点。@tomfanning,请用更好的示例编辑您的问题。我回答你的问题,而不是你在想什么(我看不懂你的心思)。@KM,问题是“为什么我不能做这个具体的事情”,而不是“解决这个问题”。尽管如此,我还是根据Robin Day的答案添加了一个特定于域的问题和一个使用嵌入式视图的返工。@KM感谢您更新您的答案。但是它仍然没有删除重复项。@tomfanning,没有办法删除重复项,无法编写查询以提高速度,也无法处理琐碎的重复项我喜欢你的编辑消息,基本上是重复我的答案。然而,到目前为止,我的答案已经收到了两张反对票。@Robin Day:你并没有真正回答这个问题,你只是提供了一个解决方案,让他得到他想要的抽象。@CptSkippy这就是为什么这个没有被标记为答案,而你的答案被标记为。这很好,因为它教会了我一种实现我需要的方法,但你已经回答了我提出的问题。@tomfanning,永远不要这样做!!!!如果人们有一百万行,你是吗