代码之家  ›  专栏  ›  技术社区  ›  MadBoy

不是所需日期但第一个可用的SQL值

sql
  •  0
  • MadBoy  · 技术社区  · 15 年前

    我在MS SQL 2005/2008数据库中得到了这个SQL查询,它为我提供了货币金额、货币、货币时间和货币转换器。我留下了一张桌子,上面收集了波兰国家银行每天关于货币兑换的信息。

    以下是问题:

    SELECT  t1.[TransakcjeGotowkoweKwota],  
            t1.TypyWaluty,  
            t1.[TransakcjeGotowkoweData],  
            t2.[kurs_sredni]  
    FROM    [BazaZarzadzanie].[dbo].[TransakcjeGotowkowe] t1
    
    LEFT JOIN [BazaZarzadzanie].[dbo].[KursyWalutNBP] t2
    ON t1.TypyWaluty = t2.[kod waluty]  AND t2.[data publikacji] = t1.[TransakcjeGotowkoweData]  
    WHERE   [TypyWaluty] = 'EUR'
    

    输出结果如下:

    TransakcjeGotowkoweKwota TypyWaluty TransakcjeGotowkoweData kurs_sredni
    -14153.04000000         EUR         2009-01-05 00:00:00.000    4,1137    
    -18.36000000            EUR         2009-07-01 00:00:00.000    4,4157    
    4.61000000              EUR         2007-09-30 00:00:00.000    NULL
    55.50000000             EUR         2007-09-30 00:00:00.000    NULL  
    

    问题在于kurs sredni的空值。当在那个特定的日子里[库尔斯沃鲁特尼]找不到[库尔斯沃鲁特尼]时,就会发生这种情况。我想实现的是,当它发生时,它应该得到最接近的可能日期,并得到当天的价值。

    例如:
    如果日期2007-09-30的[kurs sredni]的值为空,则应该从2007-10-01获取值(如果它当然有一个值)。

    我该怎么解决这个问题?

    问候,

    疯子

    6 回复  |  直到 15 年前
        1
  •  1
  •   Mitchel Sellers    15 年前

    我个人会为这种类型的事情转移到一个用户定义的函数,而不是一个连接。这样,您就可以完全控制评估过程。根据你的笔记,你可以按照如下的方式来做。

    SELECT TOP 1 kurs_sredni
    FROM YourTable
    WHERE (Your Comparison here)
    ORDER BY Date 
    

    这样,您就可以在“日期”上进行>=比较,如果它不存在,您将得到下一个最新的日期值。

        2
  •  1
  •   Peter Lang    15 年前

    我不能尝试使用MS SQL,但类似的方法应该对您有效。

    它应该返回日期差异最小的值(如果可能,返回相同的日期)。

    SELECT * FROM (
        SELECT  t1.[TransakcjeGotowkoweKwota],  
                t1.TypyWaluty,
                t2.[kurs_sredni],
                ROW_NUMBER() OVER( PARTITION BY t1.[TransakcjeGotowkoweData] ORDER BY ABS(cast(t1.[TransakcjeGotowkoweData] - t2.[data publikacji] AS FLOAT)) ) rank
        FROM    [BazaZarzadzanie].[dbo].[TransakcjeGotowkowe] t1
        LEFT JOIN [BazaZarzadzanie].[dbo].[KursyWalutNBP] t2
        ON t1.TypyWaluty = t2.[kod waluty]
        WHERE   [TypyWaluty] = 'EUR'
    ) x
    WHERE rank = 1
    
        3
  •  1
  •   Community CDub    6 年前

    helper table of dates 这是有用的;加入到Kursywalutnbp,你可以很容易地计算出每个日期的正确汇率。我将此作为一个视图进行展示,以简化最终查询:

    CREATE VIEW CurrencyNearRates (kod_waluty, data, kurs_sredni)
    AS 
    SELECT currencydates.kod_waluty, currencydates.data, ratenow.kurs_sredni FROM (SELECT currencies.kod_waluty, Helper_Dates.data FROM currencies CROSS JOIN Helper_Dates) currencydates
    LEFT OUTER JOIN KursyWalutNBP ratenow
    ON 
    currencydates.kod_waluty = ratenow.kod_waluty
    AND currencydates.data <= ratenow.data_publikacji
    AND ratenow.data_publikacji = 
    (
      SELECT MIN(futurerates.data_publikacji)
      FROM KursyWalutNBP futurerates
      WHERE ratenow.kod_waluty = futurerates.kod_waluty
      AND currencydates.data <= futurerates.data_publikacji
    ) 
    

    这给了你这样的数据:

    SELECT * FROM CurrencyNearRates ORDER BY kod_waluty, data;
    |kod_waluty     |data        |kurs_sredni|
    |----------------------------------------|
    |EUR            |2009-01-04  |4.1137     |
    |EUR            |2009-01-05  |4.1137     |
    |EUR            |2009-01-06  |4.4157     |
    |EUR            |2009-01-07  |4.4157     |
     ----------------------------------------
    

    然后,您只需在Transakcjegotowkowe中的交易和货币汇率之间进行简单的连接:

    SELECT
     t1.[TransakcjeGotowkoweKwota],  
     t1.[TypyWaluty],  
     t1.[TransakcjeGotowkoweData],  
     CurrencyNearRates.[kurs_sredni]
    FROM
    dbo.[TransakcjeGotowkowe] t1
    LEFT OUTER JOIN CurrencyNearRates
     ON t1.[TypyWaluty] = CurrencyNearRates.[kod_waluty]
     AND t1.[TransakcjeGotowkoweData] = CurrencyNearRates.[data]
    WHERE t1.[TypyWaluty] = 'EUR'  
    ORDER BY t1.[TransakcjeGotowkoweData]
    

    这给了你这样的输出:

    |TransakcjeGotowkoweKwota   |TypyWaluty   |TransakcjeGotowkoweData   |kurs_sredni   |
    |-----------------------------------------------------------------------------------|
    |-18.36                     |EUR          |2009-07-01                |4.4157        |
    |-14153.04                  |EUR          |2009-01-05                |4.1137        |
    |4.61                       |EUR          |2007-09-30                |4.5678        |
    |55.5                       |EUR          |2007-09-30                |4.5678        |
     -----------------------------------------------------------------------------------
    
        4
  •  0
  •   Tom H zenazn    15 年前

    我在理解您的查询时遇到了一些困难,但这是对我认为您要解决的问题的一般解决方案。如果每个父级可能有许多子级,那么您可能希望按开始日期限制(例如,在左侧外部联接和子查询中包括条件,这样它就只限制在@my_date的3天内的子级(例如)。至少在这个日期的索引可能会得到一些使用,而下面的代码根本无法使用它。

    SELECT
        P.parent_id,
        C.stuff
    FROM
        Parent P
    LEFT OUTER JOIN Child C ON
        C.parent_id = P.parent_id
    WHERE
        NOT EXISTS
        (
            SELECT
                *
            FROM
                Child C2
            WHERE
                C2.parent_id = P.parent_id AND
                ABS(DATEDIFF(ss, C2.my_date, @my_date)) < ABS(DATEDIFF(ss, C.my_date, @my_date))
        )
    
        5
  •  0
  •   D'Arcy Rittich    15 年前

    像这样的事情应该可以做到:

    SELECT  t1.[TransakcjeGotowkoweKwota],  
            t1.TypyWaluty,  
            t1.[TransakcjeGotowkoweData],  
            t2.[kurs_sredni]  
    FROM    [BazaZarzadzanie].[dbo].[TransakcjeGotowkowe] t1
    LEFT JOIN (
        select ta.TypyWaluty, ta.[TransakcjeGotowkoweData], min(ABS(cast(ta.[TransakcjeGotowkoweData] - tb.[data publikacji] as float))) as ClosestDate
        FROM    [BazaZarzadzanie].[dbo].[TransakcjeGotowkowe] ta
        inner join [BazaZarzadzanie].[dbo].[KursyWalutNBP] tb ON ta.TypyWaluty = tb.[kod waluty] 
        group by ta.TypyWaluty, ta.[TransakcjeGotowkoweData]
    ) t2c ON t1.TypyWaluty = t2c.TypyWaluty
        AND t1.[TransakcjeGotowkoweData] = t2c.[TransakcjeGotowkoweData]
    LEFT JOIN [BazaZarzadzanie].[dbo].[KursyWalutNBP] t2 ON t2c.TypyWaluty = t1.TypyWaluty
        AND t1.[TransakcjeGotowkoweData] = t2.[TransakcjeGotowkoweData]
        AND t2c.ClosestDate = ABS(cast(t1.[TransakcjeGotowkoweData] - t2.[data publikacji] as float))
    WHERE   t1.[TypyWaluty] = 'EUR'
    
        6
  •  0
  •   MadBoy    15 年前

    最好的办法是米切尔的。我创造了

    CREATE FUNCTION KursWaluty
    (
      @typWaluty nvarchar(15),
      @dataWaluty DATETIME
    )
    RETURNS varchar(30)
    AS BEGIN
    RETURN ( SELECT TOP 1
                    kurs_sredni
             FROM   [BazaZarzadzanie].[dbo].[KursyWalutNBP]
             WHERE  [kod waluty] = @typWaluty
                    AND [data publikacji] >= @dataWaluty
             ORDER BY [data publikacji]
           )
    
    end
    

    并使用此查询获取:

    SELECT  t1.[TransakcjeGotowkoweKwota],
        TypyWaluty,
        [TransakcjeGotowkoweData],
        CASE WHEN [kurs_sredni] IS NULL
             THEN BazaZarzadzanie.dbo.KursWaluty(TypyWaluty, [TransakcjeGotowkoweData])
             ELSE [kurs_sredni]
        END AS 'Currency'
    
    FROM    [BazaZarzadzanie].[dbo].[TransakcjeGotowkowe] t1
        LEFT JOIN [BazaZarzadzanie].[dbo].[KlienciPortfeleKonta] t2
        ON t1.[KlienciPortfeleKontaID] = t2.[KlienciPortfeleKontaID]
        LEFT JOIN [BazaZarzadzanie].[dbo].[KursyWalutNBP]
        ON TypyWaluty = [kod waluty]
           AND [data publikacji] = [TransakcjeGotowkoweData]
     WHERE   [TypyWaluty] = 'EUR' -- AND [kurs_sredni] IS NULL
    

    这很有效,而且看起来很快(2秒)。我已经使用并且[kurs_sredni]为空来验证空值现在是否得到了正确的值。