Sql值不是所需的日期,但首先可用

时间:2010-01-19 14:53:35

标签: sql

我在MS SQL 2005/2008数据库中有这个SQL QUERY,它可以获得Money Money,Money Currency,Money Time和Currency Converter。我离开时加入了Table,它每天都收集波兰国家银行关于货币转换器的信息。

以下是查询:

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的NULL值。当在[KursyWalutNBP]中找不到[kurs_sredni]时,会发生这种情况。我想要实现的是当它发生时它应该得到最近的可能日期并获得当天的价值。

例如:
如果[Kurs Sredni]对于2007-09-30日期的值为NULL,它应该从2007-10-01获得值(如果它有一个当然)。

我该如何接受这个?

关于,

MadBoy

6 个答案:

答案 0 :(得分:1)

我个人会转移到这种类型的用户定义函数,而不是连接。这样您就可以完全控制评估过程。您可以根据您的笔记以下列方式进行操作。

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

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

答案 1 :(得分:1)

我不能尝试使用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

答案 2 :(得分:1)

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中的交易和CurrencyNearRates中的汇率之间进行简单的连接:

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        |
 -----------------------------------------------------------------------------------

答案 3 :(得分:0)

我在理解您的查询时遇到了一些麻烦,但这是我认为您要解决的问题的一般解决方案。如果每个父母可能有很多孩子,那么您可能希望限制日期开始(例如,在LEFT OUTER JOIN和子查询中包含条件,以便它仅限于@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))
    )

答案 4 :(得分:0)

这样的事情应该这样做:

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'

答案 5 :(得分:0)

对此最好的答案是米切尔的一个。我已经创建了

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秒)。我使用AND [kurs_sredni] IS NULL来验证空值现在是否正确值。