【问题标题】:T-SQL Subquery Max(Date) and JoinsT-SQL 子查询 Max(Date) 和连接
【发布时间】:2010-10-27 02:51:14
【问题描述】:

我正在尝试加入多个表,但其中一个表有多个记录,用于具有不同日期的 partid。我想获取最近日期的记录。

以下是一些示例表:

Table: MyParts
Partid   Partnumber   Description
1        ABC-123      Pipe
2        ABC-124      Handle
3        ABC-125      Light


Table: MyPrices
Partid   Price        PriceDate
1        $1           1/1/2005
1        $2           1/1/2007
1        $3           1/1/2009
2        $2           1/1/2005
2        $4           1/1/2006
2        $5           1/1/2008
3        $10          1/1/2008
3        $12          1/1/2009

如果我只是想找到某个零件的最新价格,我可以这样做:

SELECT * FROM MyPrice WHERE PriceDate = (SELECT MAX(PriceDate) 
FROM MyPrice WHERE Partid = 1)

但是,我想先加入并取回所有零件的正确价格,而不仅仅是一个。这是我尝试过的:

SELECT * FROM MyParts LEFT JOIN MyPrice ON MyParts.Partid = MyPrice.Partid WHERE 
MyPart.PriceDate = (SELECT MAX(PriceDate) FROM MyPrice)

结果是错误的,因为它取了整个表格的最高价格日期。

SELECT * FROM MyParts LEFT JOIN MyPrice ON MyParts.Partid = MyPrice.Partid WHERE 
MyPart.PriceDate = (SELECT MAX(PriceDate) FROM MyPrice WHERE MyPrice.Partid =   
MyParts.Partid)

那个错误了。

我该怎么做才能得到我想要的结果。

【问题讨论】:

  • 这适用于 SQL 2000、2005 还是 2008?
  • 您的示例都只显示日期时间戳。以下所有示例均假设每个日期有一条记录。如果在某一天有重复,它们要么最终显示多条记录,要么被任意挑选。如果您的 MyPrices 表具有标识,则此问题将被消除。仅供参考:)

标签: sql sql-server tsql join subquery


【解决方案1】:

这是另一种不使用子查询的方法。这种方法通常会优于其他方法,因此值得测试这两种方法,看看哪种方法性能最佳。

SELECT
     PRT.PartID,
     PRT.PartNumber,
     PRT.Description,
     PRC1.Price,
     PRC1.PriceDate
FROM
     MyParts PRT
LEFT OUTER JOIN MyPrices PRC1 ON
     PRC1.PartID = PRT.PartID
LEFT OUTER JOIN MyPrices PRC2 ON
     PRC2.PartID = PRC1.PartID AND
     PRC2.PriceDate > PRC1.PriceDate
WHERE
     PRC2.PartID IS NULL

如果您有两个具有相同 EXACT PriceDate 的价格,这将给出多个结果(大多数其他解决方案都会这样做)。另外,我没有什么可以解释最后一个价格日期是在未来。无论您最终使用哪种方法,您都可能需要考虑对此进行检查。

【讨论】:

  • 谢谢,速度很快。我认为在 WHERE 上方应该是 PRC2.PriceDate > PRC1.PriceDate。
  • 问题 Where PRC2.PartId is null 对查询有什么作用?
  • 算了,它减少了返回的记录数。
  • 您似乎已经弄清楚了,但为了清楚起见......它实际上是使用 LEFT JOIN 作为 NOT EXISTS。如果没有行可以连接,则该表中的 ID 必须为 NULL。
  • 这种方法对于“聚合的聚合”的真正复杂的数据非常宝贵......不知道如何在简短的评论中说出我的意思,但@TomH。 ,你真的把我救到了这里。谢谢。
【解决方案2】:

试试这个:

Select *,
    Price = (Select top 1 Price 
             From MyPrices 
             where PartID = mp.PartID 
             order by PriceDate desc
            )
from MyParts mp

【讨论】:

  • 因为它是针对 SQL 2005 的,所以我打算用 WITH 语句做一些花哨的事情,然后我决定采用绝对最简单的方法。
  • @KM,我不知道你的表是如何被索引的,或者关于你的数据的任何其他信息,但你的可能更好。我只是在我的头顶上写下了我的。 @MaxGeek,您可能应该使用他的。在我的辩护中,我的从一开始就正常工作:)
  • 根据 MyParts 中的行数,这是一个子查询,必须对从 MyParts 表返回的每一行进行一次评估。这可能会变得非常昂贵,因为它与使用游标相当。
  • 我喜欢 Tom H 的回答。它有一种简单的优雅。这只是表明你不应该只敲出第一条突然出现在你脑海中的 SQL。
  • 哦,快乐的一天,这太棒了。非常感谢。
【解决方案3】:
SELECT
    MyParts.*,MyPriceDate.Price,MyPriceDate.PriceDate
    FROM MyParts
        INNER JOIN (SELECT Partid, MAX(PriceDate) AS MaxPriceDate FROM MyPrice GROUP BY Partid) dt ON MyParts.Partid = dt.Partid
        INNER JOIN MyPrice ON dt.Partid = MyPrice.Partid AND MyPrice.PriceDate=dt.MaxPriceDate

【讨论】:

  • 最新的零件价格是多少?
【解决方案4】:

在 SQL Server 2005 及更高版本中使用ROW_NUMBER()

SELECT * FROM 
    ( SELECT p.*,
        ROW_NUMBER() OVER(PARTITION BY Partid ORDER BY PriceDate DESC) AS rn
    FROM MyPrice AS p ) AS t
WHERE rn=1

【讨论】:

    【解决方案5】:

    类似的东西

    SELECT * 
    FROM MyParts 
    LEFT JOIN 
    (
    SELECT MAX(PriceDate), PartID FROM MyPrice group by PartID
    ) myprice
     ON MyParts.Partid = MyPrice.Partid 
    

    如果你知道你的partid或者可以限制它把它放在join中。

       SELECT myprice.partid, myprice.partdate, myprice2.Price, * 
        FROM MyParts 
        LEFT JOIN 
        (
        SELECT MAX(PriceDate), PartID FROM MyPrice group by PartID
        ) myprice
         ON MyParts.Partid = MyPrice.Partid 
        Inner Join MyPrice myprice2
        on myprice2.pricedate = myprice.pricedate
        and myprice2.partid = myprice.partid
    

    【讨论】:

    • 输出中partid的最新价格在哪里?
    【解决方案6】:
    SELECT
        *
    FROM
        (SELECT MAX(PriceDate) AS MaxP, Partid FROM MyPrices GROUP BY Partid) MaxP 
        JOIN
        MyPrices MP On MaxP.Partid = MP.Partid AND MaxP.MaxP = MP.PriceDate
        JOIN
        MyParts P ON MP.Partid = P.Partid
    

    您首先获取partid 的最新价格日期(标准聚合),然后将其加入以获取价格(不能在聚合中),然后获取零件详细信息。

    【讨论】:

    • 只要将其复制粘贴到查询窗口并执行即可。
    • @Andomar:是的。输出中只有 3 个 Partid 列。现在我们已经为 JOIN 提供了 FROM 子句,OP 可以计算出他想要哪些列
    【解决方案7】:

    加入价格表,然后选择最后一天的条目:

    select pa.partid, pa.Partnumber, max(pr.price)
    from myparts pa
    inner join myprices pr on pr.partid = pa.partid
    where pr.PriceDate = (
        select max(PriceDate) 
        from myprices 
        where partid = pa.partid
    )
    

    max() 是在每天有多个价格的情况下;我假设你想显示最高的。如果您的价格表有一个 id 列,您可以避免使用 max() 并简化如下:

    select pa.partid, pa.Partnumber, pr.price
    from myparts pa
    inner join myprices pr on pr.partid = pa.partid
    where pr.priceid = (
        select max(priceid)
        from myprices 
        where partid = pa.partid
    )
    

    附:请改用 wcm 的解决方案!

    【讨论】:

      【解决方案8】:

      所有其他答案都必须有效,但使用相同的语法(并理解错误原因)

      SELECT * FROM MyParts LEFT JOIN MyPrice ON MyParts.Partid = MyPrice.Partid WHERE 
      MyPart.PriceDate = (SELECT MAX(MyPrice2.PriceDate) FROM MyPrice as MyPrice2 
      WHERE MyPrice2.Partid =  MyParts.Partid)
      

      【讨论】:

        【解决方案9】:

        请尝试下一个代码示例:

        select t1.*, t2.partprice, t2.partdate 
        from myparts t1
        join myprices t2 
        on t1.partid = t2.partid
        where partdate = 
        (select max(partdate) from myprices t3 
        where t3.partid = t2.partid group by partid)
        

        【讨论】:

        • 欢迎使用 StackOverflow:如果您发布代码、XML 或数据示例,请在文本编辑器中突出显示这些行,然后单击编辑器工具栏上的“代码示例”按钮 ( { } ) 或使用 Ctrl键盘上的 +K 可以很好地格式化和语法突出显示它!
        • 一个好的答案应该解释它的作用。
        【解决方案10】:

        对于 MySQL,请查找以下查询:

        select * from (select PartID, max(Pricedate) max_pricedate from MyPrices group bu partid) as a 
            inner join MyParts b on
            (a.partid = b.partid and a.max_pricedate = b.pricedate)
        

        在子查询中,它为 MyPrices 的每个 partyid 获取 max pricedate,然后, 使用 partid 和 ma​​x_priceate

        与 MyParts 进行内部连接

        【讨论】:

        • 问题不在于 MySQL。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-29
        • 1970-01-01
        • 2020-09-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多