SQL - 将 Dynamic SQL 与 Pivot 和 Full Join 相结合
SQL - Combining Dynamic SQL with Pivot and Full Join
我正在寻找 solution/suggestion。我不仅搜索了 Whosebug,而且搜索了好几天,但仍然没有找到 suitable 解决方案。
场景:
- 我有 2 个数据库 tables - A 和 B。
- 我需要根据相同的参数对 A 和 B 进行 select 查询。
- 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);
此代码将针对其中一个 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)
我正在寻找 solution/suggestion。我不仅搜索了 Whosebug,而且搜索了好几天,但仍然没有找到 suitable 解决方案。
场景:
- 我有 2 个数据库 tables - A 和 B。
- 我需要根据相同的参数对 A 和 B 进行 select 查询。
- 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);
此代码将针对其中一个 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)