SQL - 将动态SQL与数据透视和完全连接相结合

时间:2016-02-04 08:45:40

标签: sql sql-server pivot dynamic-sql

我正在寻找解决方案/建议。我不仅搜索了Stackoverflow,而且搜索了几天,仍然没有找到合适的解决方案。

情景:

  • 我有2个数据库表--A和B.
  • 我需要根据相同的参数对A和B进行选择查询。
  • A和B的结果集需要单独旋转。
  • 旋转后,需要执行完整连接。
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);

此代码将针对其中一个表生成一个透视结果集。我需要对第二个表执行相同的操作,然后根据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)来展示我想要实现的目标。

2 个答案:

答案 0 :(得分:1)

你能做什么:

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

简化示例:

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;

答案 1 :(得分:0)

你可以这样做。

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)

这将基于其中一个表的SecurityIdentifier列动态构建一个sql,在本例中为表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)