【问题标题】:Getting a Dynamically-Generated Pivot-Table into a Temp Table将动态生成的数据透视表放入临时表
【发布时间】:2009-04-22 16:20:03
【问题描述】:

我见过this,所以我知道如何使用一组动态生成的字段创建数据透视表。我现在的问题是我想将结果放入一个临时表中。

我知道为了从 EXEC 语句将结果集放入临时表中,您需要预定义临时表。如果是动态生成的数据透视表,则无法事先知道字段。

我能想到的获得此类功能的唯一方法是使用动态 SQL 创建一个永久表。有没有更好的办法?

【问题讨论】:

    标签: sql sql-server database pivot


    【解决方案1】:

    今天遇到这个问题,并发布在我的blog。解决方案的简短描述是创建一个包含一列的临时表,然后使用 sp_executesql 动态更改它。然后您可以将动态 PIVOT 的结果插入其中。下面的工作示例。

    CREATE TABLE #Manufacturers
    (
        ManufacturerID INT PRIMARY KEY,
        Name VARCHAR(128)
    )
    
    INSERT INTO #Manufacturers (ManufacturerID, Name)
    VALUES (1,'Dell')
    INSERT INTO #Manufacturers (ManufacturerID, Name)
    VALUES (2,'Lenovo')
    INSERT INTO #Manufacturers (ManufacturerID, Name)
    VALUES (3,'HP')
    
    CREATE TABLE #Years
    (YearID INT, Description VARCHAR(128))
    GO
    
    INSERT INTO #Years (YearID, Description) VALUES (1, '2014')
    INSERT INTO #Years (YearID, Description) VALUES (2, '2015')
    GO
    
    CREATE TABLE #Sales
    (ManufacturerID INT, YearID INT,Revenue MONEY)
    GO
    
    INSERT INTO #Sales (ManufacturerID, YearID, Revenue) VALUES(1,2,59000000000)
    INSERT INTO #Sales (ManufacturerID, YearID, Revenue) VALUES(2,2,46000000000)
    INSERT INTO #Sales (ManufacturerID, YearID, Revenue) VALUES(3,2,111500000000)
    INSERT INTO #Sales (ManufacturerID, YearID, Revenue) VALUES(1,1,55000000000)
    INSERT INTO #Sales (ManufacturerID, YearID, Revenue) VALUES(2,1,42000000000)
    INSERT INTO #Sales (ManufacturerID, YearID, Revenue) VALUES(3,1,101500000000)
    GO
    
    DECLARE @SQL AS NVARCHAR(MAX)
    DECLARE @PivotColumnName AS NVARCHAR(MAX)
    DECLARE @TempTableColumnName AS NVARCHAR(MAX)
    DECLARE @AlterTempTable AS NVARCHAR(MAX)
    
    --get delimited column names for various SQL statements below
    SELECT 
        -- column names for pivot
        @PivotColumnName= ISNULL(@PivotColumnName + N',',N'') + QUOTENAME(CONVERT(NVARCHAR(10),YearID)),
        -- column names for insert into temp table
        @TempTableColumnName = ISNULL(@TempTableColumnName + N',',N'') + QUOTENAME('Y' + CONVERT(NVARCHAR(10),YearID)),
        -- column names for alteration of temp table
        @AlterTempTable = ISNULL(@AlterTempTable + N',',N'') + QUOTENAME('Y' + CONVERT(NVARCHAR(10),YearID)) + ' MONEY' 
    FROM (SELECT DISTINCT [YearID] FROM #Sales) AS Sales
    
    CREATE TABLE #Pivot
    (
         ManufacturerID INT
    )
    
    -- Thats it! Because the following step will flesh it out.
    
    SET @SQL = 'ALTER TABLE #Pivot ADD ' + @AlterTempTable
    EXEC sp_executesql @SQL
    
    --execute the dynamic PIVOT query into the temp table 
    SET @SQL =  N'
        INSERT INTO #Pivot (ManufacturerID, ' + @TempTableColumnName + ')
        SELECT ManufacturerID, ' + @PivotColumnName + '
        FROM #Sales S
        PIVOT(SUM(Revenue) 
          FOR S.YearID IN (' + @PivotColumnName + ')) AS PivotTable'
    EXEC sp_executesql @SQL
    
    SELECT M.Name, P.*
    FROM #Manufacturers M
    INNER JOIN #Pivot P ON M.ManufacturerID = P.ManufacturerID
    

    【讨论】:

    • 良好的逐步完成案例研究。无论如何,您的博客链接都不起作用。
    【解决方案2】:

    你可以这样做:

    -- add 'loopback' linkedserver 
    if exists (select * from master..sysservers where srvname = 'loopback')
        exec sp_dropserver 'loopback'
    go
    exec sp_addlinkedserver @server = N'loopback',
        @srvproduct = N'',
        @provider = N'SQLOLEDB', 
        @datasrc = @@servername
    go
    
    declare @myDynamicSQL varchar(max)
    select @myDynamicSQL = 'exec sp_who'
    exec('
        select * into #t from openquery(loopback, ''' + @myDynamicSQL + ''');
        select * from #t
        ')
    

    编辑:添加动态 sql 以接受 openquery 的参数

    【讨论】:

    • 如何将动态 SQL 传递给 OPENQUERY?
    • 你没有。你也必须让它充满活力。
    • 不明白,请澄清
    • 在这种情况下,#t 超出了 EXEC 语句的范围
    • 那么你可以把它放到一个全局的##temp表中
    【解决方案3】:

    让我试试这个 select into 的解释。我也在运行 SQL Server 2005。因为您有 PIVOT 表,所以我将假设相同或 2008 年。

    select 
        o.*,
        OtherField1,
        OtherField2
    INTO #temp
    FROM
        OriginalOtherData as ood
    PIVOT (
        MAX([Value])
        FOR Field in (OtherField1, OtherField2)
    ) as piv
    RIGHT OUTER join
        Original o on o.OriginalSD = piv.OriginalSD
    
    select * from #temp
    Drop table #temp
    

    普通选择和选择进入之间的唯一区别在于 INTO #table 部分。

    【讨论】:

    • 请阅读链接到的问题。我正在使用动态 SQL 为透视表生成字段列表。除非您已经创建了一个表,否则您不能将 SELECT INTO 与 EXEC 一起使用。由于不知道EXEC结果的字段列表,所以无法预建表。
    • 您已经在动态生成字段列表。那么为什么不使用该代码来帮助生成表定义呢?另外,是否有什么东西可以阻止 MSSQL 在 EXEC 中而不是在它之外执行 SELECT INTO?
    • 这两个问题的答案是,在动态 SQL 查询中创建的临时表的范围将使其无法访问执行 EXEC 调用的过程/查询。
    • 还有全局临时表。只需在名称中使用 ## 而不是 #,但您又需要处理一个全局临时表。
    【解决方案4】:
    • 用于查询(从表名中选择 col1、col2、col3
    • col1 成为行标签
    • col2 成为列标题
    • col3 是数据集

    • 也摆脱了全局表

      if OBJECT_ID('tempdb..#3') is not null drop table #3
      if OBJECT_ID('tempdb..##3') is not null drop table ##3
      DECLARE @cols AS NVARCHAR(MAX),
          @query  AS NVARCHAR(MAX)
      select @cols = STUFF((SELECT distinct ',' + QUOTENAME(   col2    ) from    tablename    FOR XML PATH(''), col2).value('.', 'NVARCHAR(MAX)'),1,1,'')
      set @query = 'SELECT col1, ' + @cols + ' into ##3 from ( select col1, col2, col3 from tablename ) x  pivot (  max(col3)for col2 in (' + @cols + ')) p '
      execute(@query)   
      select * into #3 from ##3 if OBJECT_ID('tempdb..##3') -- is not null drop table ##3
      

    【讨论】:

      猜你喜欢
      • 2019-12-22
      • 2021-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-16
      • 1970-01-01
      相关资源
      最近更新 更多