0

我有一个使用子查询的查询,但在返回预期结果时遇到问题。我收到的错误是......“当子查询不使用 EXISTS 引入时,选择列表中只能指定一个表达式。” 我怎样才能重写这个工作?

SELECT
    a.Part,
    b.Location,
    b.LeadTime
FROM
    dbo.Parts a
    LEFT OUTER JOIN dbo.Vendor b ON b.Part = a.Part
WHERE
    b.Location IN ('A','B','C')
AND
    Date IN (SELECT Location, MAX(Date) FROM dbo.Vendor GROUP BY Location)
GROUP BY
    a.Part,
    b.Location,
    b.LeadTime
ORDER BY
    a.Part
4

3 回答 3

3

我认为这样的东西可能是你正在寻找的东西。您没有说 SQL Server 的版本——这适用于 SQL 2005 及更高版本:

SELECT
    p.Part,
    p.Location, -- from *p*, otherwise if no match we'll get a NULL
    v.LeadTime
FROM
    dbo.Parts p
    OUTER APPLY (
       SELECT TOP (1) * -- * here is okay because we specify columns outside
       FROM dbo.Vendor v
       WHERE p.Location = v.Location -- the correlation part
       ORDER BY v.Date DESC
    ) v
WHERE
    p.Location IN ('A','B','C')
ORDER BY
    p.Part
;

现在,您的查询可以通过添加“相关”部分来修复您的查询,以将您的查询更改为 a correlated subquery,如Kory 的答案所示(您还可以删除该GROUP BY子句)。但是,该方法仍然需要额外的不必要的连接,这会损害性能,而且一次只能拉一列。此方法允许您从另一个表中提取所有列,并且没有额外的连接。

注意:这在逻辑上给出了与Lamak 的答案相同的结果,但是出于以下几个原因,我更喜欢它:

  1. 当相关列(Location此处的 , )上有索引时,可以通过搜索来满足,但Row_Number解决方案必须扫描(我相信)。
  2. 我更喜欢这种更直接、更简洁地表达查询意图的方式。在该Row_Number方法中,必须了解外部条件以查看我们只是在获取rn = 1值,然后返回 CTE 以查看它是什么。
  3. 使用CROSS APPLYor OUTER APPLY,未参与单内行每外行选择的所有其他表都在(对我而言)它们所属的位置之外。我们不会一起解决问题。使用Row_Number感觉有点像DISTINCT在查询上抛出一个来修复重复而不是处理潜在问题。我想这与前一点以不同的方式表达的问题基本相同。
  4. 当您有两张表希望从中提取最新值时,Row_Number()解决方案就彻底崩溃了。使用这种语法,您只需轻松添加另一个APPLY子句,您在做什么就一目了然。有一种方法可以Row_Number通过将其他表移到外部来用于多表场景,但我仍然不喜欢这种语法。
  5. 使用此语法,您可以根据所选行是否存在(在未找到匹配行的情况下)执行附加连接。在Row_Number解决方案中,您只能合理地NOT NULL检查外部查询——因此您被迫将查询拆分为多个独立的部分(您不想加入将要丢弃的值!)。

PS 我强烈建议您使用暗示它们所代表的表的别名。请不要使用aand b。我使用p了 forPartsvfor Vendor--this 可以帮助您和其他人在未来更快地理解查询。

于 2013-06-03T18:00:03.420 回答
1

如果我理解正确,您需要位置 A、B 和 C 的最大日期行。现在,假设 SQL Server 2005+,您可以这样做:

;WITH CTE AS
(
    SELECT
        a.Part,
        b.Location,
        b.LeadTime,
        RN = ROW_NUMBER() OVER(PARTITION BY a.Part ORDER BY [Date] DESC)
    FROM
        dbo.Parts a
        LEFT OUTER JOIN dbo.Vendor b ON b.Part = a.Part
    WHERE
        b.Location IN ('A','B','C')
)
SELECT  Part, 
        Location,
        LeadTime
FROM CTE
WHERE RN = 1
ORDER BY Part
于 2013-06-03T17:06:11.690 回答
0

在您的子查询中,您需要将 Location 和 Part 与外部查询相关联。例子:

Date = (SELECT MAX(Date) 
        FROM dbo.Vender v 
        WHERE v.Location = b.Location 
          AND v.Part = b.Part
       )

所以这将为每个位置和部分带回一个日期

于 2013-06-03T17:04:21.670 回答