编码此相关查询的最佳方法是什么? (选择优先级后可能包含NULL的价格)

时间:2011-09-28 11:10:58

标签: sql sql-server-2005 tsql

让我们假设您有一个价值组合,其中包含需要定价的4个资产。 SourceID规定了应该给出PriceSource的优先级,并且应该检索最低的SourceID。如果EODPrice表中没有可用的价格,则应检索AverageBookCost(它位于不同的表中)。我正在使用SQL Server 2005。

举个例子,假设EODPrice表有以下数据('TEST004'缺失):

SourceID    Date                   Ticker     Price
0           2011-08-02 00:00:00    TEST001    104.50
1           2011-08-01 00:00:00    TEST001    100.00
1           2011-08-02 00:00:00    TEST001    105.00
1           2011-08-04 00:00:00    TEST001    115.00
2           2011-08-03 00:00:00    TEST001    109.38
2           2011-08-04 00:00:00    TEST001    114.24
1           2011-08-01 00:00:00    TEST002    9.99
1           2011-08-02 00:00:00    TEST002    9.89
1           2011-08-03 00:00:00    TEST002    9.79
1           2011-08-04 00:00:00    TEST002    9.69
0           2011-08-03 00:00:00    TEST003    0.42
2           2011-08-01 00:00:00    TEST003    0.33
2           2011-08-02 00:00:00    TEST003    0.38
2           2011-08-03 00:00:00    TEST003    0.28
2           2011-08-04 00:00:00    TEST003    0.45

让我们想象一下,我们想构建一个Select语句,我们为以下资产检索EODPrice('TEST001','TEST002','TEST003','TEST004')。请注意,'TEST004'是刚刚进入市场的新资产,在EODPrice表或市场中尚无价格。

此外,让我们假设任何日期的所有代码都有一个来自RunningTotal表的非NULL AverageBookCost字段。 (即SELECT AverageBookCost FROM RunningTotal WHERE Ticker ='TEST004'AND Date ='2011-08-03'将返回值0.15说。)

如何构建最有效的“相关”或“COALESCE / ISNULL”查询:

SELECT Ticker, SourceID, Price
   ???
   WHERE [Date] = '2011-08-03' 
   AND [Ticker] IN ('TEST001','TEST002', 'TEST003' and 'TEST004') 

这将返回下面的表:(注意'TEST004'Price是AverageBookCost而不在EODPrice表中,然后SourceID设置为NULL以指示Price来自RunningTotal表:

Ticker   SourceID   Price
TEST1    2          109.38
TEST2    1          9.79
TEST3    0          0.42
TEST4    NULL       0.15

非常感谢, 贝尔蒂。

1 个答案:

答案 0 :(得分:2)

我很可能过于复杂,但这可能会让你开始。

简而言之,推理就像这样

  • 在子选择中,SELECT给定日期的所有代码及其最低的SourceID。
  • JOIN此子选择的结果返回原始表格。此步骤允许为具有给定日期和最低SourceID的每个股票代码检索价格。
  • FULL OUTER JOIN以前的结果与平均图书费用。此步骤会为每个行添加该股票代码的平均价格,并为没有从Pricetable返回的记录的代码添加行。
  • SELECT从这些结果中得出Price(如果可用),否则从附加列中选择平均图书费用。

SQL语句

SELECT  [Ticker] = ISNULL(pt.Ticker, pt_avg.Ticker)
        , [SourceID] = pt.SourceID
        , [Price] = ISNULL(pt.Price, pt_avg.AverageBookCost)
FROM    EODPriceTable pt 
        INNER JOIN (
          SELECT  SourceID = MIN(SourceID), Ticker, Date
          FROM    EODPriceTable
          WHERE   Date = '2011-08-03 00:00:00'
          GROUP BY
                  Ticker, Date
         ) pt_min ON  pt_min.SourceID = pt.SourceID 
                      AND pt_min.Ticker = pt.Ticker
                      AND pt_min.Date = pt.Date
         FULL OUTER JOIN (
            SELECT  Ticker, AverageBookCost
            FROM    RunningTable
         ) pt_avg ON pt_avg.Ticker = pt.Ticker
WHERE  ISNULL(pt.Ticker, pt_avg.Ticker) IN ('TEST001', 'TEST002', 'TEST003', 'TEST004')

测试脚本

;WITH EODPriceTable (SourceID, Date, Ticker, Price) AS (
  SELECT 0, '2011-08-02 00:00:00', 'TEST001', 104.50
  UNION ALL SELECT 1, '2011-08-01 00:00:00', 'TEST001', 100.00
  UNION ALL SELECT 1, '2011-08-02 00:00:00', 'TEST001', 105.00
  UNION ALL SELECT 1, '2011-08-04 00:00:00', 'TEST001', 115.00
  UNION ALL SELECT 2, '2011-08-03 00:00:00', 'TEST001', 109.38
  UNION ALL SELECT 2, '2011-08-04 00:00:00', 'TEST001', 114.24
  UNION ALL SELECT 1, '2011-08-01 00:00:00', 'TEST002', 9.99
  UNION ALL SELECT 1, '2011-08-02 00:00:00', 'TEST002', 9.89
  UNION ALL SELECT 1, '2011-08-03 00:00:00', 'TEST002', 9.79
  UNION ALL SELECT 1, '2011-08-04 00:00:00', 'TEST002', 9.69
  UNION ALL SELECT 0, '2011-08-03 00:00:00', 'TEST003', 0.42
  UNION ALL SELECT 2, '2011-08-01 00:00:00', 'TEST003', 0.33
  UNION ALL SELECT 2, '2011-08-02 00:00:00', 'TEST003', 0.38
  UNION ALL SELECT 2, '2011-08-03 00:00:00', 'TEST003', 0.28
  UNION ALL SELECT 2, '2011-08-04 00:00:00', 'TEST003', 0.45
)
, RunningTable (Ticker, AverageBookCost) AS (
  SELECT 'TEST004', 0.15
  UNION ALL SELECT 'TEST003', 0.09
)
SELECT  [Ticker] = ISNULL(pt.Ticker, pt_avg.Ticker)
        , [SourceID] = pt.SourceID
        , [Price] = ISNULL(pt.Price, pt_avg.AverageBookCost)
FROM    EODPriceTable pt 
        INNER JOIN (
          SELECT  SourceID = MIN(SourceID), Ticker, Date
          FROM    EODPriceTable
          WHERE   Date = '2011-08-03 00:00:00'
          GROUP BY
                  Ticker, Date
         ) pt_min ON  pt_min.SourceID = pt.SourceID 
                      AND pt_min.Ticker = pt.Ticker
                      AND pt_min.Date = pt.Date
         FULL OUTER JOIN (
            SELECT  Ticker, AverageBookCost
            FROM    RunningTable
         ) pt_avg ON pt_avg.Ticker = pt.Ticker
WHERE  ISNULL(pt.Ticker, pt_avg.Ticker) IN ('TEST001', 'TEST002', 'TEST003', 'TEST004')