SQL - 将 Dynamic SQL 与 Pivot 和 Full Join 相结合

SQL - Combining Dynamic SQL with Pivot and Full Join

我正在寻找 solution/suggestion。我不仅搜索了 Whosebug,而且搜索了好几天,但仍然没有找到 suitable 解决方案。

场景:


declare     @Tickers nvarchar(MAX),
@StartDate datetime,
@EndDate datetime,
@Field nvarchar(10);

select @Tickers ='[ADDRC BDSR Curncy], [USDRC BDSR Curncy], [JYDRC BDSR Curncy], [NDDRC BDSR Curncy], [BPDRC BDSR Curncy], [SFDRC BDSR Curncy], [CDDRC BDSR Curncy], [NKDRC BDSR Curncy], [DKDRC BDSR Curncy], [SKDRC BDSR Curncy], [EUDRC BDSR Curncy], [KWDRC BDSR Curncy], [IRDRC BDSR Curncy], [CGDRC BDSR Curncy], [HFDRC BDSR Curncy], [CKDRC BDSR Curncy], [SADRC BDSR Curncy], [PZDRC BDSR Curncy], [MPDRC BDSR Curncy]',
@StartDate = '01/05/1990' ,
@EndDate = '01/13/2016',
@Field = 'PX_LAST';

DECLARE @pTickers nvarchar(MAX) = @Tickers,
    @pStartDate datetime = @StartDate,
    @pEndDate datetime = @EndDate,
    @pField nvarchar(10) = @Field,
    @pSQL nvarchar(MAX);

--Dynamic SQL
SET @pSQL = '
;With CTE as
(
  SELECT * FROM
  (
      SELECT SecurityIdentifier as [Ticker], PriceDate as [pDate], Price as [Price] FROM Bbg_' + @pField  +
' WHERE PriceDate BETWEEN ''' + CAST(@pStartDate as nvarchar) + ''' AND ''' + cast(@pEndDate as NVARCHAR) +'''
  ) as s
PIVOT
(
  MIN (s.Price)
  for [Ticker] in (' + @pTickers + ') -- Column names for pivot
) as pvt
)
Select * from CTE a
order by a.pDate DESC'
EXECUTE(@pSQL);

此代码将针对其中一个 table 生成一个旋转结果集。我需要对第二个 table 做同样的事情,然后根据 priceDate/pDate.

完全加入两个结果

我这样做对吗?

编辑:

Table Bbg_PX_LAST
==========================================
| SecurityIdentifier  | PriceDate | Price|
------------------------------------------
| ADDRC BDSR Curncy   | 03/02/2016| 10.00|
| ADDRC BDSR Curncy   | 04/02/2016| 11.00|
| ADDRC BDSR Curncy   | 05/02/2016| 12.00|
| ADDRC BDSR Curncy   | 06/02/2016| 13.00|
| USDRC BDSR Curncy   | 03/02/2016| 20.00|
| USDRC BDSR Curncy   | 04/02/2016| 21.00|
| USDRC BDSR Curncy   | 05/02/2016| 22.00|
| USDRC BDSR Curncy   | 06/02/2016| 23.00|
==========================================

Table Bbg_CUR_PX
==========================================
| SecurityIdentifier  | PriceDate | Price|
------------------------------------------
| ADDRC BDSR Curncy   | 03/02/2016| 30.00|
| ADDRC BDSR Curncy   | 04/02/2016| 31.00|
| ADDRC BDSR Curncy   | 05/02/2016| 32.00|
| ADDRC BDSR Curncy   | 06/02/2016| 33.00|
| USDRC BDSR Curncy   | 03/02/2016| 40.00|
| USDRC BDSR Curncy   | 04/02/2016| 41.00|
| USDRC BDSR Curncy   | 05/02/2016| 42.00|
==========================================

Result:

================================================================================
| PDate       | ADDRC BDSR | ADDRC BDSR  | USDRC BDSR | USDRC BDSR  | .....
|             | Curncy     | Curncy (2)  | Curncy     | Curncy (2)  |  ....
--------------------------------------------------------------------------------
| 03/02/2016  |  10.00     |   30.00     |  20.00     |   40.00     |   ...
| 04/02/2016  |  11.00     |   31.00     |  21.00     |   41.00     |   ...
| 05/02/2016  |  12.00     |   32.00     |  22.00     |   42.00     |   ...
| 06/02/2015  |  13.00     |   33.00     |  23.00     |   NULL      |   ...
================================================================================

*ADDRC BDSR Curncy      - is from table Bbg_PX_LAST
*ADDRC BDSR Curncy (2)  - is from table Bbg_CUR_PX
*USDRC BDSR Curncy      - is from table Bbg_PX_LAST
*USDRC BDSR Curncy (2)  - is from table Bbg_CUR_PX

最终结果中有更多的列。此示例仅提供两 (2) 个来演示我正在努力实现的目标。

你能做什么:

  • 重写 @pSQL 以不使用 WITH 子句(这是多余的)
  • 分别为 table A 和 B 生成 PIVOT SQL,就像你已经为一个 table 所做的那样:@pSQLA@pSQLB
  • 编写一个结合两者的查询,在 A 的派生 table 和 B
  • 之间有一个 FULL JOIN

简化示例:

DECLARE @cmd NVARCHAR(MAX);
SET @cmd=N'
    SELECT
        *
    FROM
        ('+@pSQLA+') AS A
        FULL JOIN ('+@pSQLB+') AS B ON
            A.PDate=B.PDate;
';
EXECUTE sp_executesql @cmd;

你可以这样做。

DECLARE @Sql NVARCHAR(MAX),
        @Selects NVARCHAR(MAX),
        @Identifiers NVARCHAR(MAX) = 'SUM(CASE WHEN l.SecurityIdentifier = ''<ticker>>'' THEN l.Price END) AS ''<ticker>>'',
                                  SUM(CASE WHEN c.SecurityIdentifier = ''<ticker>>'' THEN c.Price END) AS ''<ticker>> (2)'''

SELECT  @Selects = COALESCE(@Selects + ',', '') + REPLACE(@Identifiers, '<ticker>>', SecurityIdentifier)
FROM    Bbg_PX_LAST
GROUP BY SecurityIdentifier

SET @Sql = '
SELECT
    COALESCE(l.PriceDate, c.PriceDate) PDate, '
    + @Selects + 
'FROM 
    Bbg_PX_LAST l
    FULL OUTER JOIN Bbg_CUR_PX c ON l.SecurityIdentifier = c.SecurityIdentifier AND l.PriceDate = c.PriceDate
GROUP BY 
    COALESCE(l.PriceDate, c.PriceDate)'

EXEC(@Sql)

这将基于 table 之一的 SecurityIdentifier 列动态构建 sql,在本例中为 table Bbg_PX_LAST。结果查询将如下所示。

SELECT  COALESCE(l.PriceDate,c.PriceDate) PDate,
        SUM(CASE WHEN l.SecurityIdentifier = 'ADDRC BDSR Curncy' THEN l.Price END) AS 'ADDRC BDSR Curncy',
        SUM(CASE WHEN c.SecurityIdentifier = 'ADDRC BDSR Curncy' THEN c.Price END) AS 'ADDRC BDSR Curncy (2)',
        SUM(CASE WHEN l.SecurityIdentifier = 'USDRC BDSR Curncy' THEN l.Price END) AS 'USDRC BDSR Curncy',
        SUM(CASE WHEN c.SecurityIdentifier = 'USDRC BDSR Curncy' THEN c.Price END) AS 'USDRC BDSR Curncy (2)'
FROM    Bbg_PX_LAST l
        FULL OUTER JOIN Bbg_CUR_PX c ON l.SecurityIdentifier = c.SecurityIdentifier
                                        AND l.PriceDate = c.PriceDate
GROUP BY COALESCE(l.PriceDate,c.PriceDate)