【问题标题】:SQL pivot without dynamic sql没有动态 sql 的 SQL 透视
【发布时间】:2014-09-16 14:15:54
【问题描述】:

我想在我的 sql 查询中使用带有动态数据透视列的数据透视,但我不想使用动态 sql 查询然后执行它。因为我的要求是将结果存储到临时表中。

有没有办法在 pivot for 子句中使用动态列而不动态创建查询?

如果我正在动态准备查询,有没有办法将结果存储到临时表中?

请提出一些建议。

【问题讨论】:

  • 如果您想要动态列数作为结果,那么您将需要动态 SQL
  • 如果列未知,那么您必须使用动态 SQL。没有其他方法可以解决这个问题。 PIVOT 需要知道列,因此您必须提前创建一个 sql 字符串然后执行它。
  • 好的,有没有办法将结果存储在临时表中?
  • 那么您需要一个动态临时表吗?选择 #tempTable {dynamic query} 并在 where 子句中说 1=2,因此不会填充任何记录,并且临时表是使用相关列构建的
  • 你能把查询写给我吗?现在工作我不是在创建一个临时表,而是在 db 中创建一个具有动态名称的真实表(使用 NEWID()),当我处理完数据后,我需要删除该表。

标签: sql sql-server pivot


【解决方案1】:

这里有一个解决方案。我正在使用存储过程。主源表 DeptBudget 有各种列,例如用户、日期等,但我使用的列是 Status、HR_Budget 和 IT_Budget。我正在使用 9 种可能的状态,但可以修改更多。最好的部分是我不必知道状态的值!解决方案的关键是使用和 Identity 作为数据透视字段,然后根据需要重命名列并删除。无需动态 SQL!

-- STEP 1: Declare Column Name Variable
Declare @tnc varchar(50)

-- STEP 2: Create 2 temporay tables #StageA and #StageB.
CREATE TABLE #StageA (
ID int IDENTITY(1,1) NOT NULL,
Budget varchar(50), 
HR_Budget decimal(12,2),
IT_Budget decimal(12,2)
)
CREATE TABLE #StageB (
Budget varchar(50), 
[1] decimal(12,2),
[2] decimal(12,2),
[3] decimal(12,2),
[4] decimal(12,2),
[5] decimal(12,2),
[6] decimal(12,2),
[7] decimal(12,2),
[8] decimal(12,2),
[9] decimal(12,2)
)

-- STEP 3: Dump Aggregated data into #StageA
INsert Into #StageA (Budget, HR_Budget, IT_Budget)
Select [Status], Sum(HR_Budget), Sum(IT_Budget)
From DeptBudget
Group By [Status]


-- STEP 4: Pivot into #StageB
Insert into #StageB
    Select Budget,  SUM([1]) AS [1],SUM([2]) AS [2],SUM([3]) AS [3],SUM([4]) AS [4],SUM([5]) AS [5],SUM([6]) AS [6]
    ,SUM([7]) AS [7],SUM([8]) AS [8],SUM([9]) AS [9]
    from
    (
    Select   'IT Budget' As Budget,  ISNULL([1], 0) AS [1],ISNULL([2], 0) AS [2],ISNULL([3], 0) AS [3],ISNULL([4], 0) AS [4],ISNULL([5], 0) AS [5],ISNULL([6], 0) AS [6]
        ,ISNULL([7], 0) AS [7],ISNULL([8], 0) AS [8],ISNULL([9], 0) AS [9]
    from
        (
        Select ID, IT_Budget From #StageA 
                )
        pvt
        Pivot
        (
            Sum(IT_Budget) for [ID] in ([1],[2],[3],[4],[5],[6],[7],[8],[9])
        )   
    Pvttab   
Union
    Select   'HR Budget' As Budget,  ISNULL([1], 0) AS [1],ISNULL([2], 0) AS [2],ISNULL([3], 0) AS [3],ISNULL([4], 0) AS [4],ISNULL([5], 0) AS [5],ISNULL([6], 0) AS [6]
        ,ISNULL([7], 0) AS [7],ISNULL([8], 0) AS [8],ISNULL([9], 0) AS [9]
    from
    (
    Select ID, HR_Budget From #StageA
                )
        pvt
        Pivot
        (
            Sum(HR_Budget) for [ID] in ([1],[2],[3],[4],[5],[6],[7],[8],[9])
        )
        Pvttab   

Union
    Select   'Total Budget' As Budget,  ISNULL([1], 0) AS [1],ISNULL([2], 0) AS [2],ISNULL([3], 0) AS [3],ISNULL([4], 0) AS [4],ISNULL([5], 0) AS [5],ISNULL([6], 0) AS [6]
        ,ISNULL([7], 0) AS [7],ISNULL([8], 0) AS [8],ISNULL([9], 0) AS [9]
    from
    (
    Select ID, HR_Budget + IT_Budget AS BudgetTotal  From #StageA
    )
    pvt
    Pivot
    (
    Sum(BudgetTotal) for [ID] in ([1],[2],[3],[4],[5],[6],[7],[8],[9])
    )
    Pvttab   

) pVS
Group By Budget 

-- STEP 5: Rename The Columns and drop those not needed.
select @tnc  = Null
Select @tnc = Budget From #StageA Where ID=1
If @tnc IS Not NUll 
    Begin
        EXEC tempdb..sp_rename '#StageB.[1]', @tnc, 'COLUMN'
    End
    Else
    Begin
        ALTER TABLE #StageB
        DROP COLUMN  [1];       
    End
select @tnc  = Null
Select @tnc = Budget From #StageA Where ID=2
If @tnc IS Not NUll 
    Begin
        EXEC tempdb..sp_rename '#StageB.[2]', @tnc, 'COLUMN'
    End
    Else
    Begin
        ALTER TABLE #StageB
        DROP COLUMN  [2];       
    End

select @tnc  = Null
Select @tnc = Budget From #StageA Where ID=3
If @tnc IS Not NUll 
    Begin
        EXEC tempdb..sp_rename '#StageB.[3]', @tnc, 'COLUMN'
    End
    Else
    Begin
        ALTER TABLE #StageB
        DROP COLUMN  [3];       
    End

select @tnc  = Null
Select @tnc = Budget From #StageA Where ID=4
If @tnc IS Not NUll 
    Begin
        EXEC tempdb..sp_rename '#StageB.[4]', @tnc, 'COLUMN'
    End
    Else
    Begin
        ALTER TABLE #StageB
        DROP COLUMN  [4];       
    End

select @tnc  = Null
Select @tnc = Budget From #StageA Where ID=5
If @tnc IS Not NUll 
    Begin
        EXEC tempdb..sp_rename '#StageB.[5]', @tnc, 'COLUMN'
    End
    Else
    Begin
        ALTER TABLE #StageB
        DROP COLUMN  [5];       
    End

select @tnc  = Null
Select @tnc = Budget From #StageA Where ID=6
If @tnc IS Not NUll 
    Begin
        EXEC tempdb..sp_rename '#StageB.[6]', @tnc, 'COLUMN'
    End
    Else
    Begin
        ALTER TABLE #StageB
        DROP COLUMN  [6];       
    End

select @tnc  = Null
Select @tnc = Budget From #StageA Where ID=7
If @tnc IS Not NUll 
    Begin
        EXEC tempdb..sp_rename '#StageB.[7]', @tnc, 'COLUMN'
    End
    Else
    Begin
        ALTER TABLE #StageB
        DROP COLUMN  [7];       
    End

select @tnc  = Null
Select @tnc = Budget From #StageA Where ID=8
if @tnc IS Not NUll
    Begin
        EXEC tempdb..sp_rename '#StageB.[8]', @tnc, 'COLUMN'
    End
    Else
    Begin
        ALTER TABLE #StageB
        DROP COLUMN  [8];       
    End

select @tnc  = Null
Select @tnc = Budget From #StageA Where ID=9
If @tnc IS Not NUll 
    Begin
        EXEC tempdb..sp_rename '#StageB.[9]', @tnc, 'COLUMN'
    End
    Else
    Begin
        ALTER TABLE #StageB
        DROP COLUMN  [9];       
    End


-- Show The Data
Select * From #StageB

【讨论】:

    【解决方案2】:

    是的,您可以通过选择 ..into..statement 将其存储到 tmp 表中

    谢谢

    【讨论】:

    • 不过使用动态SQL没那么简单,至少如果他想重用那个临时表
    • 是的,@Lamak 是对的,我试过了,但是没有用。
    猜你喜欢
    • 1970-01-01
    • 2016-11-02
    • 2015-02-25
    • 2013-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多