自动生成unpivot,方便table展示字符度量

本文介绍了一个SQL过程,用于通过输入表名和模式动态生成视图,实现表中列的数据从宽格式转换为长格式的功能,即列转行操作。此过程适用于需要灵活处理不同表结构的场景。
DECLARE @TBLNAME NVARCHAR(100),@SCHEMA NVARCHAR(100)
 
--SELECT @TBLNAME='T_ORGAN_OUTLET_WEEKLY_REPORT',@SCHEMA='DBO'

CREATE PROC up_auto_create_unpivot( @TBLNAME NVARCHAR(100),@SCHEMA NVARCHAR(100))
as
--SELECT @TBLNAME='V_RELATION2',@SCHEMA='DBO'
SET NOCOUNT ON
DECLARE @SQLSTR NVARCHAR(500)=N''
DECLARE @SQL NVARCHAR(MAX)=N''

DECLARE MY_CURSOR CURSOR FAST_FORWARD READ_ONLY FOR
WITH GENSQL AS(
		SELECT 
		C.ORDINAL_POSITION,
		CASE WHEN ROW_NUMBER()OVER(ORDER BY C.ORDINAL_POSITION)=1 THEN ' WITH TEMP AS(SELECT TOP 11 ROW_NUMBER()OVER(ORDER BY '+C.COLUMN_NAME+')ID ,' ELSE ',' END +
		CASE WHEN DATA_TYPE LIKE 'DATE%' THEN ' CAST( CONVERT(NVARCHAR(10),'+C.COLUMN_NAME+',120) AS NVARCHAR(50))' ELSE ' CAST('+C.COLUMN_NAME+' AS NVARCHAR(50))' END +'AS '+C.COLUMN_NAME+''
		+ CASE WHEN ROW_NUMBER()OVER(ORDER BY C.ORDINAL_POSITION DESC)=1 THEN ' FROM  '+C.TABLE_SCHEMA+'.'+C.TABLE_NAME +')'ELSE ' ' END SQLSTR
		FROM INFORMATION_SCHEMA.[COLUMNS] AS C WHERE C.TABLE_NAME=@TBLNAME AND C.TABLE_SCHEMA=@SCHEMA
		--ORDER BY C.ORDINAL_POSITION  
		UNION ALL
		SELECT 
		C.ORDINAL_POSITION+1000 ORDINAL_POSITION,
		CASE WHEN ROW_NUMBER()OVER(ORDER BY C.ORDINAL_POSITION)=1 THEN 'SELECT * FROM  TEMP UNPIVOT ( VAL FOR KPI IN ('+C.COLUMN_NAME  ELSE ','+C.COLUMN_NAME END 
		+ CASE WHEN ROW_NUMBER()OVER(ORDER BY C.ORDINAL_POSITION DESC)=1 THEN ') )UPVT INNER JOIN TEMP T1 ON T1.ID=UPVT.ID' ELSE ' ' END SQLSTR
		FROM INFORMATION_SCHEMA.[COLUMNS] AS C WHERE C.TABLE_NAME=@TBLNAME AND C.TABLE_SCHEMA=@SCHEMA
	--ORDER BY C.ORDINAL_POSITION     	
)
SELECT SQLSTR FROM GENSQL ORDER BY  ORDINAL_POSITION 

OPEN MY_CURSOR

FETCH FROM MY_CURSOR INTO @SQLSTR

WHILE @@FETCH_STATUS = 0
BEGIN
	/*{ ... CURSOR LOGIC HERE ... }*/
	SET @SQL+=@SQLSTR+' '
	PRINT @SQLSTR
	FETCH FROM MY_CURSOR INTO @SQLSTR
END

CLOSE MY_CURSOR
DEALLOCATE MY_CURSOR
SELECT 'CREATE VIEW V_AUTO_'+@TBLNAME+'AS '+@SQL AS [SQL]
--EXEC(@SQL) 
 
 
 
 --SELECT * FROM INFORMATION_SCHEMA.[COLUMNS] AS C 



ALTER PROC UP_AUTO_CREATE_UNPIVOT( @TBLNAME NVARCHAR(100)=NULL,@WHERESQL NVARCHAR(500)='',@SCHEMA NVARCHAR(10)='DBO',@TOP INT=10)
AS
--SELECT @TBLNAME='V_RELATION2',@SCHEMA='DBO'
SET NOCOUNT ON
IF @TBLNAME IS NOT NULL AND  @WHERESQL IS NOT NULL
BEGIN
	
DECLARE @SQLSTR NVARCHAR(500)=N''
DECLARE @SQL NVARCHAR(MAX)=N''

DECLARE MY_CURSOR CURSOR FAST_FORWARD READ_ONLY FOR
WITH GENSQL AS(
		SELECT 
		C.ORDINAL_POSITION,
		CASE WHEN ROW_NUMBER()OVER(ORDER BY C.ORDINAL_POSITION)=1 THEN ' WITH TEMP AS(SELECT  '+CASE WHEN @top >=0 THEN ' top '+cast( @TOP AS NVARCHAR(10)) ELSE '' END +' ROW_NUMBER()OVER(ORDER BY '+C.COLUMN_NAME+')[ID#] ,' ELSE ',' END +
		CASE WHEN DATA_TYPE LIKE 'DATE%' THEN ' CAST( CONVERT(NVARCHAR(10),'+C.COLUMN_NAME+',120) AS NVARCHAR(50))' ELSE ' CAST('+C.COLUMN_NAME+' AS NVARCHAR(50))' END +'AS '+C.COLUMN_NAME+''
		+ CASE WHEN ROW_NUMBER()OVER(ORDER BY C.ORDINAL_POSITION DESC)=1 THEN ' FROM  '+C.TABLE_SCHEMA+'.'+C.TABLE_NAME +' '+@WHERESQL+')'ELSE ' ' END SQLSTR
		FROM INFORMATION_SCHEMA.[COLUMNS] AS C WHERE C.TABLE_NAME=@TBLNAME AND C.TABLE_SCHEMA=@SCHEMA
		--ORDER BY C.ORDINAL_POSITION  
		UNION ALL
		SELECT 
		  
		C.ORDINAL_POSITION+1000 ORDINAL_POSITION,
		CASE WHEN ROW_NUMBER()OVER(ORDER BY C.ORDINAL_POSITION)=1 THEN 'SELECT '+QUOTENAME(@TBLNAME,'''' )+' TBLNAME,'+QUOTENAME(@SCHEMA,'''' )+' TABLE_SCHEMA, UPVT.[ID#] [IDD#],ORDINAL_POSITION,KPI [KPI#],VAL [VAL#],T1.* FROM  TEMP UNPIVOT ( VAL FOR KPI IN ('+C.COLUMN_NAME  ELSE ','+C.COLUMN_NAME END 
		+ CASE WHEN ROW_NUMBER()OVER(ORDER BY C.ORDINAL_POSITION DESC)=1 THEN ') )UPVT INNER JOIN TEMP T1 ON T1.[ID#]=UPVT.[ID#]'+
		' INNER JOIN INFORMATION_SCHEMA.[COLUMNS] AS C ON C.TABLE_NAME='+QUOTENAME(@TBLNAME,'''' )+' AND C.TABLE_SCHEMA='+QUOTENAME(@SCHEMA,'''' )+' AND C.COLUMN_NAME=KPI ' ELSE ' ' END SQLSTR
		FROM INFORMATION_SCHEMA.[COLUMNS] AS C WHERE C.TABLE_NAME=@TBLNAME AND C.TABLE_SCHEMA=@SCHEMA
	--ORDER BY C.ORDINAL_POSITION     	
)
SELECT SQLSTR FROM GENSQL ORDER BY  ORDINAL_POSITION 

OPEN MY_CURSOR

FETCH FROM MY_CURSOR INTO @SQLSTR

WHILE @@FETCH_STATUS = 0
BEGIN
	/*{ ... CURSOR LOGIC HERE ... }*/
	SET @SQL+=@SQLSTR+' '
	PRINT @SQLSTR
	FETCH FROM MY_CURSOR INTO @SQLSTR
END

CLOSE MY_CURSOR
DEALLOCATE MY_CURSOR
--SELECT 'CREATE VIEW V_AUTO_'+@TBLNAME+'AS '+@SQL AS [SQL]
EXEC(@SQL) 
 
END
ELSE
BEGIN
	PRINT '@TBLNAME IS NULL'
END
 
GO

EXEC UP_AUTO_CREATE_UNPIVOT 't_orderheader','','dbo' ,1


04-25
<think>好的,我现在需要详细思考如何回答用户关于UNPIVOT SQL用法及示例的问题。首先,用户明确提到了UNPIVOT,并希望了解其用法和示例,可能还涉及到与PIVOT的对比。根据提供的引用内容,用户已经有一些关于PIVOT和UNPIVOT的基本信息,但需要更具体的指导。 首先,我应该回顾UNPIVOT的基本概念。UNPIVOT是将列转换为行的操作,通常用于数据规范化,将多列合并成两列:一列存储原来的列名,另一列存储对应的值。这适用于将宽表转换为长表的情况,比如处理多个指标分布在不同列中的情况。 接下来,我需要考虑如何用示例来说明。用户提供的引用中有一个示例表结构,即DeptKPI表,包含MonthName、DeptName和KPIValue。可能用户希望看到如何将多个KPIValue相关的列进行UNPIVOT操作。不过原表结构中的KPIValue是单列,可能需要调整示例,假设存在多个指标列,比如Sales、Cost、Profit等,这样更适合UNPIVOT的应用场景。 比如,假设原表结构有多个指标列,如下: CREATE TABLE DeptKPI ( MonthName NVARCHAR(10), DeptName NVARCHAR(50), Sales FLOAT, Cost FLOAT, Profit FLOAT ); 这时,使用UNPIVOT可以将Sales、Cost、Profit这三列转换为行,每个行对应一个指标及其值。示例SQL语句应该是怎样的呢?根据引用中的Oracle示例,可能需要使用UNPIVOT函数,但用户可能使用的是SQL Server,因为原表结构中有dbo架构,这是SQL Server的典型用法。不过SQL Server和Oracle的UNPIVOT语法可能有所不同,需要确认。 在SQL Server中,UNPIVOT的语法通常是使用UNPIVOT关键字,而Oracle则是使用UNPIVOT子句。需要分别给出两种数据库的示例吗?用户的问题没有明确指定数据库,但引用的引用1是SQL Server,引用2是Oracle。因此,可能需要分别说明两种环境下的用法。 另外,需要确保示例的准确性和可理解性。例如,在SQL Server中,UNPIVOT的基本结构是: SELECT ... FROM 表 UNPIVOT ( 值列 FOR 列名 IN (列1, 列2, 列3) ) AS 别名 在Oracle中,语法类似,但可能需要使用INCLUDE NULLS或EXCLUDE NULLS选项,不过根据引用2的描述,可能不需要特别处理。 此外,需要解释UNPIVOT的作用,可能用户需要知道何时使用它,比如数据需要规范化、转换为更适合分析的格式,或者需要与其他表进行JOIN操作等场景。 另外,用户可能想知道UNPIVOT与PIVOT的区别,比如PIVOT是将行转为列,而UNPIVOT是逆过程。但用户的问题集中在UNPOVOT上,所以可能需要重点讲解UNPIVOT,但可以简要对比。 还需要注意示例中的表结构是否合理。原引用中的DeptKPI表结构可能不适合直接用于UNPIVOT示例,因为它只有KPIValue一列。可能需要调整表结构,假设有多个指标列,如前面的Sales、Cost、Profit,这样UNPIVOT才有意义。 总结下来,回答的结构应该是: 1. 定义UNPIVOT的作用和适用场景。 2. 提供SQL Server和Oracle的语法示例。 3. 对比UNPIVOT和PIVOT的区别。 4. 可能的应用场景和注意事项。 同时,需要确保示例代码正确无误,符合对应数据库的语法规范。例如,在SQL Server中,正确的UNPIVOT写法,以及如何处理列名和值。在Oracle中,可能需要使用不同的语法结构。 另外,需要检查用户提供的引用内容,引用1中的表结构可能需要调整,以适配UNPIVOT示例。例如,假设该表有多个数值列,而用户可能需要将这些列转换为行。因此,可能需要修改表结构,但必须明确说明这是假设的情况,以避免误导用户。 最后,生成相关问题,可能涉及UNPIVOT与PIVOT的区别、性能优化、处理NULL值的方法,以及在不同数据库中的具体实现差异等。</think>### UNPIVOT用法详解 UNPIVOT是SQL中将**列转换为行**的操作,常用于数据规范化场景。它可将多个列合并为两列:一列存储原始列名(指标名称),另一列存储对应的值(指标数值)。以下是详细说明及示例: --- #### 一、基本语法(以SQL Server为例) 假设表`DeptKPI`包含多个月份、部门的多个指标列(如销售额、成本、利润): ```sql CREATE TABLE DeptKPI ( MonthName NVARCHAR(10), DeptName NVARCHAR(50), Sales FLOAT, Cost FLOAT, Profit FLOAT ); ``` **目标**:将`Sales`、`Cost`、`Profit`三列转为行格式。 **UNPIVOT实现**: ```sql SELECT MonthName, DeptName, KPI_Name, KPI_Value FROM DeptKPI UNPIVOT ( KPI_Value FOR KPI_Name IN (Sales, Cost, Profit) ) AS UnpivotedData; ``` **结果**: | MonthName | DeptName | KPI_Name | KPI_Value | |-----------|----------|----------|-----------| | Jan | Sales | Sales | 5000 | | Jan | Sales | Cost | 3000 | | ... | ... | ... | ... | --- #### 二、Oracle中的UNPIVOT语法 Oracle语法类似,但需显式定义列名和值列[^2]: ```sql SELECT MonthName, DeptName, KPI_Name, KPI_Value FROM DeptKPI UNPIVOT ( KPI_Value FOR KPI_Name IN (Sales AS 'Sales', Cost AS 'Cost', Profit AS 'Profit') ); ``` --- #### 三、核心作用与场景 1. **数据规范化**:将宽表转为长表,便于分析工具处理。 2. **动态列处理**:当列数量不确定时,可配合动态SQL实现灵活查询。 3. **与PIVOT对比**: - **PIVOT**:行转列(如按月份横向展示销售额)。 - **UNPIVOT**:列转行(如纵向存储多指标数据)。 --- #### 四、注意事项 1. **数据类型一致**:所有被UNPIVOT的列需为相同类型。 2. **NULL值处理**:默认排除含NULL的行,可通过`INCLUDE NULLS`保留(Oracle支持)[^2]。 3. **性能优化**:对大数据表建议添加索引或分阶段处理。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值