MS SQL 转置 Like Excel 转置(动态 SQL)

MS SQL Transpose Like Excel Transpose (Dynamic SQL)

我需要类似于 excel 转置操作的动态 SQL 代码。 我试过将 table 转置为 Dynamic SQL。 我尝试过 Pivot/XML、Dynamic SQL。整理。我失败了。 我尝试了 CAST(column collate database_default AS NVARCHAR(MAX)) 次转换。

我哪里做错了?我该如何编写代码?

我的最终目标是创建一个复合 table,它是作为以下查询的结果获得的。如您所见,此 table 中的样本列为空。我想做一个“while 循环”查询来填充这些值。在创建循环之前,我需要一个类似于 excel 转置操作的代码。通过此操作,我可以将结果复制到复合 table.

SELECT A.TABLE_CATALOG, A. TABLE_SCHEMA, B.COLUMN_CNT,B.DUM_TABLE_POSITION,
A.ORDINAL_POSITION AS DEF_COLUMN_POSITION, A.TABLE_NAME, A.COLUMN_NAME,
SAMPLE_1=NULL,SAMPLE_2=NULL,SAMPLE_3=NULL,SAMPLE_4=NULL,SAMPLE_5=NULL,
SAMPLE_6=NULL,SAMPLE_7=NULL,SAMPLE_8=NULL,SAMPLE_9=NULL,SAMPLE_10=NULL
FROM INFORMATION_SCHEMA.COLUMNS A,
(SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME,COUNT(*) AS COLUMN_CNT,
ROW_NUMBER() OVER (ORDER BY TABLE_NAME) AS DUM_TABLE_POSITION
FROM INFORMATION_SCHEMA.COLUMNS
GROUP BY TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME
HAVING COUNT(*)>0 ) B
WHERE A.TABLE_CATALOG=B.TABLE_CATALOG
AND A.TABLE_SCHEMA=B.TABLE_SCHEMA
AND A.TABLE_NAME=B.TABLE_NAME
AND A.TABLE_CATALOG='DWH_PROD'
AND A.TABLE_SCHEMA='dbo'
AND A.TABLE_NAME IN (N'DWH_PROD.dbo.MY_TABLE_1', N'DWH_PROD.dbo.MY_TABLE_2')

enter image description here

............................

示例数据

CREATE TABLE #temporary_table 
(CUS_ID INT, 
TITLE NVARCHAR (50), 
PROMOTER NVARCHAR (50), 
CUS_STATUS NVARCHAR (50))
;

INSERT INTO #temporary_table 
VALUES
(11,'A',NULL,'PASSIVE'),
(22,'B',NULL,'ACTIVE'),
(33,'D',NULL,'ACTIVE'),
(44,'B',NULL,'ACTIVE'),
(55,'B',NULL,'ACTIVE'),
(66,'C',NULL,'ACTIVE'),
(77,'D',NULL,'ACTIVE'),
(88,'D',NULL,'ACTIVE'),
(101,'D',NULL,'ACTIVE'),
(123,'D',NULL,'ACTIVE'),
(200,'D',NULL,'ACTIVE'),
(300,'A',NULL,'PASSIVE')
;

SELECT TOP 10 CONCAT('SAMPLE_', ROW_NUMBER() OVER( ORDER BY (SELECT 1) ) ) AS AAA,*
FROM #temporary_table

我可以使用下面的单个代码分别获得结果。但是这个结果不符合我的要求。

DECLARE @sql nvarchar(max) = N'';
SELECT @sql += N'
SELECT TOP (10) [table] = N''' + REPLACE(name, '''','') + ''', * 
FROM ' + QUOTENAME(SCHEMA_NAME([schema_id]))
+ '.' + QUOTENAME(name) + ';'
FROM sys.tables AS t
WHERE name IN (N'DWH_PROD.dbo.MY_TABLE_1', N'DWH_PROD.dbo.MY_TABLE_2')
EXEC sys.sp_executesql @sql;

编辑::::::::::::::::::::::::::::

非常感谢@John Cappelletti,我几乎完成了查询。该代码适用于 Server 2014。我没有测试所有其他方案。如果一列的前 10 行只有 NULL 值,则第二个 Table 名称将被视为 NULL。

-- DROP TABLE #HamdullahUstadKacincidir2
-- DROP TABLE #HamdullahUstadKacincidir
CREATE TABLE #HamdullahUstadKacincidir2 
(COLUMN_NAME NVARCHAR (MAX),
SAMPLE_1 NVARCHAR (MAX),
SAMPLE_2 NVARCHAR (MAX),
SAMPLE_3 NVARCHAR (MAX),
SAMPLE_4 NVARCHAR (MAX),
SAMPLE_5 NVARCHAR (MAX),
SAMPLE_6 NVARCHAR (MAX),
SAMPLE_7 NVARCHAR (MAX),
SAMPLE_8 NVARCHAR (MAX),
SAMPLE_9 NVARCHAR (MAX),
SAMPLE_10 NVARCHAR (MAX))

CREATE TABLE #HamdullahUstadKacincidir 
(TABLE_NAME NVARCHAR (MAX),
COLUMN_NAME NVARCHAR (MAX),
SAMPLE_1 NVARCHAR (MAX),
SAMPLE_2 NVARCHAR (MAX),
SAMPLE_3 NVARCHAR (MAX),
SAMPLE_4 NVARCHAR (MAX),
SAMPLE_5 NVARCHAR (MAX),
SAMPLE_6 NVARCHAR (MAX),
SAMPLE_7 NVARCHAR (MAX),
SAMPLE_8 NVARCHAR (MAX),
SAMPLE_9 NVARCHAR (MAX),
SAMPLE_10 NVARCHAR (MAX))


DECLARE @SourceTableName AS NVARCHAR (MAX)
DECLARE @SourceTableSql AS NVARCHAR (MAX)
DECLARE @SourceTableSql22 AS NVARCHAR (MAX)
DECLARE @SourceTableSql333 AS NVARCHAR (MAX)
DECLARE @TableI INT
DECLARE @TableIN NVARCHAR(MAX)
DECLARE @SampleSize INT
DECLARE @TableCount INT 
SET @TableI=1
SET @SampleSize= 10
SET @TableCount= (SELECT COUNT(*) AS MAX_TABLE_CNT
FROM
(SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME,COUNT(*) AS COLUMN_CNT
FROM INFORMATION_SCHEMA.COLUMNS 
WHERE CONCAT(TABLE_CATALOG,'.', TABLE_SCHEMA,'.', TABLE_NAME) NOT IN --Has at Least One Geography Data_Type Column
(SELECT CONCAT(C.TABLE_CATALOG,'.', C.TABLE_SCHEMA,'.', C.TABLE_NAME) AS TABLE_HAS_GEOGRAPHY_DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS C
WHERE DATA_TYPE='Geography')
AND CONCAT(TABLE_CATALOG,'.', TABLE_SCHEMA,'.', TABLE_NAME) NOT IN --Eliminate Empty Tables
(SELECT CONCAT(C.TABLE_CATALOG,'.', C.TABLE_SCHEMA,'.', C.TABLE_NAME) AS EMPTY_TABLE
FROM sys.tables t
join sys.schemas s on (t.schema_id = s.schema_id)
join sys.partitions p on (t.object_id = p.object_id)
join INFORMATION_SCHEMA.COLUMNS c on (s.name=c.TABLE_SCHEMA and t.name=c.TABLE_NAME)
WHERE p.index_id in (0,1)
GROUP BY C.TABLE_CATALOG, C.TABLE_SCHEMA, C.TABLE_NAME
HAVING SUM(p.rows) = 0)
AND CONCAT(TABLE_CATALOG,'.', TABLE_SCHEMA,'.', TABLE_NAME) NOT IN --Black List Tables
('DWH_PROD.dbo._tmp_retro')
GROUP BY TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME) T ) 

WHILE @TableI<=@TableCount
BEGIN
SET @TableIN=CAST(@TableI AS NVARCHAR(MAX))
SET @SourceTableSql=
'SELECT @SourceTableTemp=CONCAT(TABLE_CATALOG,''.'',TABLE_SCHEMA,''.'',TABLE_NAME)
FROM
(SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME,COUNT(*) AS COLUMN_CNT,
ROW_NUMBER() OVER (ORDER BY TABLE_NAME) AS DUM_TABLE_POSITION
FROM INFORMATION_SCHEMA.COLUMNS
WHERE CONCAT(TABLE_CATALOG,''.'', TABLE_SCHEMA,''.'', TABLE_NAME) NOT IN --Has at Least One Geography Data_Type Column
(SELECT CONCAT(C.TABLE_CATALOG,''.'', C.TABLE_SCHEMA,''.'', C.TABLE_NAME) AS TABLE_HAS_GEOGRAPHY_DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS C
WHERE DATA_TYPE=''Geography'')
AND CONCAT(TABLE_CATALOG,''.'', TABLE_SCHEMA,''.'', TABLE_NAME) NOT IN --Eliminate Empty Tables
(SELECT CONCAT(C.TABLE_CATALOG,''.'', C.TABLE_SCHEMA,''.'', C.TABLE_NAME) AS EMPTY_TABLE
FROM sys.tables t
join sys.schemas s on (t.schema_id = s.schema_id)
join sys.partitions p on (t.object_id = p.object_id)
join INFORMATION_SCHEMA.COLUMNS c on (s.name=c.TABLE_SCHEMA and t.name=c.TABLE_NAME)
WHERE p.index_id in (0,1)
GROUP BY C.TABLE_CATALOG, C.TABLE_SCHEMA, C.TABLE_NAME
HAVING SUM(p.rows) = 0)
AND CONCAT(TABLE_CATALOG,''.'', TABLE_SCHEMA,''.'', TABLE_NAME) NOT IN --Black List Tables
(''DWH_PROD.dbo._tmp_retro'')
GROUP BY TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME) K
WHERE DUM_TABLE_POSITION=@TableIN'

EXECUTE sp_executesql @SourceTableSql, N'@TableIN NVARCHAR(MAX),@SourceTableTemp NVARCHAR (MAX) OUTPUT', 
@TableIN=@TableIN, @SourceTableTemp = @SourceTableName OUTPUT

DELETE #HamdullahUstadKacincidir2

SET @SourceTableSql22 ='INSERT INTO #HamdullahUstadKacincidir2
SELECT *
FROM ( SELECT A.AAA,C.*
FROM ( SELECT TOP '+CONCAT('',@SampleSize)+' AAA = CONCAT(''SAMPLE_'', ROW_NUMBER() OVER( ORDER BY (SELECT 1) ) ),* 
FROM '+@SourceTableName+' SRC ) A
CROSS APPLY ( VALUES ((Select A.* FOR XML RAW,Type)) )B(XMLData)
CROSS APPLY ( SELECT COLUMN_NAME  = xAttr.value(''local-name(.)'', ''VARCHAR(MAX)''),VALUE = xAttr.value(''.'',''VARCHAR(MAX)'')
FROM XMLData.nodes(''//@*'') xNode(xAttr)
WHERE xAttr.value(''local-name(.)'', ''varchar(100)'')  not in (''AAA'')) C ) SRC
PIVOT (MAX(VALUE) FOR [AAA] IN (' + STUFF((SELECT TOP (@SampleSize) ','+CONCAT('SAMPLE_', ROW_NUMBER() OVER( ORDER BY (SELECT 1) )) 
FROM master..spt_values FOR XML Path('')),1,1,'')  + ') ) P'

EXECUTE(@SourceTableSql22)

INSERT INTO #HamdullahUstadKacincidir
SELECT TABLE_NAME=@SourceTableName,* FROM #HamdullahUstadKacincidir2

SET @TableI=@TableI+1

END 


SELECT E.*,K.*,H.*
FROM
(SELECT CONCAT(TABLE_CATALOG,'.',TABLE_SCHEMA,'.',TABLE_NAME) AS TABLE_NAME,COLUMN_NAME,DATA_TYPE,
ROW_NUMBER() OVER (PARTITION BY TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME ORDER BY ORDINAL_POSITION ) AS COLUMN_POSITION
FROM INFORMATION_SCHEMA.COLUMNS
) K
LEFT JOIN
#HamdullahUstadKacincidir H
ON K.TABLE_NAME COLLATE DATABASE_DEFAULT=H.TABLE_NAME COLLATE DATABASE_DEFAULT
AND K.COLUMN_NAME COLLATE DATABASE_DEFAULT=H.COLUMN_NAME COLLATE DATABASE_DEFAULT
LEFT JOIN
(SELECT CONCAT(C.TABLE_CATALOG,'.', C.TABLE_SCHEMA,'.', C.TABLE_NAME) AS EMPTY_TABLE
FROM sys.tables t
join sys.schemas s on (t.schema_id = s.schema_id)
join sys.partitions p on (t.object_id = p.object_id)
join INFORMATION_SCHEMA.COLUMNS c on (s.name=c.TABLE_SCHEMA and t.name=c.TABLE_NAME)
WHERE p.index_id in (0,1)
GROUP BY C.TABLE_CATALOG, C.TABLE_SCHEMA, C.TABLE_NAME
HAVING SUM(p.rows) = 0) E
ON K.TABLE_NAME=EMPTY_TABLE
ORDER BY K.TABLE_NAME,K.COLUMN_POSITION

更新 - 一个更动态的版本。只需提供 table 名称(或查询)和 SampleSize

这将动态反透视您的数据,然后对结果进行透视

示例或dbFiddle

Declare @Source     varchar(500) = '#temporary_table'
Declare @SampleSize int = 10

Declare @SQL varchar(max) = '
Select *
From (
        Select A.AAA 
              ,B.*
         From ( 
                SELECT TOP '+concat('',@SampleSize)+'
                       AAA = CONCAT(''SAMPLE_'', ROW_NUMBER() OVER( ORDER BY (SELECT 1) ) )
                      ,* 
                 FROM '+ @Source +' src
              ) A
         Cross Apply (
                        Select [Key]
                              ,Value
                         From OpenJson((Select A.* For JSON Path,Without_Array_Wrapper,INCLUDE_NULL_VALUES )) 
                         Where [Key] not in (''AAA'')
                     ) B
    ) src
 Pivot (max(Value) For [AAA] in (' + Stuff((Select top (@SampleSize) ','+CONCAT('SAMPLE_', ROW_NUMBER() OVER( ORDER BY (SELECT 1) )) From master..spt_values For XML Path('')),1,1,'')  + ') ) p
'

Exec(@SQL)

结果

纯属娱乐

您还可以提供查询作为 @Source

Set @Source = '( Select * from [dbo].[ZIPCodes] where StateCode=''RI'') '