【问题标题】:SQL - Combining Dynamic SQL with Pivot and Full JoinSQL - 将动态 SQL 与 Pivot 和 Full Join 相结合
【发布时间】:2016-02-04 08:45:39
【问题描述】:

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

场景:

  • 我有 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 完全连接两个结果。

我这样做对吗?

编辑:

表 Bbg_PX_LAST =========================================== |安全标识符 |价格日期 |价格| ------------------------------------------ | ADDRC BDSR 货币 | 2016 年 3 月 2 日| 10.00| | ADDRC BDSR 货币 | 2016 年 4 月 2 日| 11.00| | ADDRC BDSR 货币 | 2016 年 5 月 2 日| 12.00| | ADDRC BDSR 货币 | 06/02/2016| 13.00| | USDRC BDSR 货币 | 2016 年 3 月 2 日| 20.00| | USDRC BDSR 货币 | 2016 年 4 月 2 日| 21.00| | USDRC BDSR 货币 | 2016 年 5 月 2 日| 22.00| | USDRC BDSR 货币 | 06/02/2016| 23.00| =========================================== 表 Bbg_CUR_PX =========================================== |安全标识符 |价格日期 |价格| ------------------------------------------ | ADDRC BDSR 货币 | 2016 年 3 月 2 日| 30.00| | ADDRC BDSR 货币 | 2016 年 4 月 2 日| 31.00| | ADDRC BDSR 货币 | 2016 年 5 月 2 日| 32.00| | ADDRC BDSR 货币 | 06/02/2016| 33.00| | USDRC BDSR 货币 | 2016 年 3 月 2 日| 40.00| | USDRC BDSR 货币 | 2016 年 4 月 2 日| 41.00| | USDRC BDSR 货币 | 2016 年 5 月 2 日| 42.00| =========================================== 结果: ==================================================== =============================== |日期 |地址 BDSR |地址 BDSR | USDRC BDSR | USDRC BDSR | ...... | |货币 |货币 (2) |货币 |货币 (2) | …… -------------------------------------------------- ------------------------------ | 2016 年 3 月 2 日 | 10.00 | 30.00 | 20.00 | 40.00 | ... | 2016 年 4 月 2 日 | 11.00 | 31.00 | 21.00 | 41.00 | ... | 2016 年 5 月 2 日 | 12.00 | 32.00 | 22.00 | 42.00 | ... | 2015 年 6 月 2 日 | 13.00 | 33.00 | 23.00 |空 | ... ==================================================== =============================== *ADDRC BDSR 货币 - 来自表 Bbg_PX_LAST *ADDRC BDSR 货币 (2) - 来自表 Bbg_CUR_PX *USDRC BDSR 货币 - 来自表 Bbg_PX_LAST *USDRC BDSR 货币 (2) - 来自表 Bbg_CUR_PX

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

【问题讨论】:

  • 您能添加一些示例数据和预期的输出吗?如果你需要一点灵感,SO 有一个 great guide 来编写这些东西。
  • 除了“我这样做是否正确?”之外,您还有其他具体问题吗?这将导致基于意见的答案。
  • 我觉得如果您描述了您试图解决的原始问题(以及示例数据等),我们可能会以更好的方式解决这个问题。您的方法可能有效(它甚至可能是最好的),但如果没有这种背景,我无法告诉您是否有更好的方法。
  • @ChrisPickford:这可能是真的 - 但由于枢轴使用带有动态值的字符串参数,我无法将这两个表连接在一起。我的 SQL 很生疏。
  • @Becuzz:我有一个 2 列的 Excel。一个包含 ID 和其他字段。此 Excel 将通过宏调用 SQL 存储过程。对于每个 ID,我需要提取 x 个字段的值。例如,如果我们有 ID (A,B,C) 和字段 (1,2,3) - 我的结果集应该是 A1, A2, A3, B1, B2, B3, C1,C2,C3 - 在上面的表格中格式。结果将反馈到 Excel。我认为通过在 SQL 级别进行连接,它比在可能运行很长时间(每个单元的单元)的宏中运行循环更容易。不确定这是否有帮助。但感谢您的意见。

标签: sql sql-server pivot dynamic-sql


【解决方案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;

【讨论】:

  • 那是完美的。正是我正在寻找的。感谢您的帮助。
【解决方案2】:

你可以这样做。

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)

【讨论】:

  • 查询运行至少需要 5 分钟。这可能是因为存储了一个大的记录集。不过谢谢你的建议。
猜你喜欢
  • 2016-04-17
  • 2013-06-24
  • 2012-06-28
  • 2016-10-04
  • 2011-07-09
  • 1970-01-01
  • 1970-01-01
  • 2020-06-08
  • 2013-06-01
相关资源
最近更新 更多