SQL join against date ranges?

后端 未结 6 1577
故里飘歌
故里飘歌 2020-12-05 00:57

Consider two tables:

Transactions, with amounts in a foreign currency:

     Date  Amount
========= =======
 1/2/2009    1500
 2/4/         


        
6条回答
  •  感动是毒
    2020-12-05 01:35

    There's nothing about a join that will be more elegant than the TOP 1 correlated subquery in your original post. However, as you say, it doesn't satisfy requirement B.

    These queries do work (SQL Server 2005 or later required). See the SqlFiddle for these.

    SELECT
       T.*,
       ExchangeRate = E.Rate
    FROM
      dbo.Transactions T
      CROSS APPLY (
        SELECT TOP 1 Rate
        FROM dbo.ExchangeRate E
        WHERE E.RateDate <= T.TranDate
        ORDER BY
          CASE WHEN E.RateDate <= T.TranDate THEN 0 ELSE 1 END,
          E.RateDate DESC
      ) E;
    

    Note that the CROSS APPLY with a single column value is functionally equivalent to the correlated subquery in the SELECT clause as you showed. I just prefer CROSS APPLY now because it is much more flexible and lets you reuse the value in multiple places, have multiple rows in it (for custom unpivoting) and lets you have multiple columns.

    SELECT
       T.*,
       ExchangeRate = Coalesce(E.Rate, E2.Rate)
    FROM
      dbo.Transactions T
      OUTER APPLY (
        SELECT TOP 1 Rate
        FROM dbo.ExchangeRate E
        WHERE E.RateDate <= T.TranDate
        ORDER BY E.RateDate DESC
      ) E
      OUTER APPLY (
        SELECT TOP 1 Rate
        FROM dbo.ExchangeRate E2
        WHERE E.Rate IS NULL
        ORDER BY E2.RateDate
      ) E2;
    

    I don't know which one might perform better, or if either will perform better than other answers on the page. With a proper index on the Date columns, they should zing pretty well--definitely better than any Row_Number() solution.

提交回复
热议问题