在SQL Server 2000中将一组行转置为列
在SQL Server中是否有将行转换为列的功能(在MS-Access中是可能的)?
我很困惑,因为此功能在MS-Access中可用,但在SQL Server中不可用。是设计使然,此功能未包含在SQL Server中吗?
解决方案
http://jdixon.dotnetdevelopersjournal.com/pivot_table_data_in_sql_server_2000_and_2005.htm上的示例仅在事先知道行值可以为有效的情况下才有效。例如,假设我们有一个具有自定义属性的实体,并且自定义属性被实现为子表中的行,其中子表基本上是变量/值对,而这些变量/值对是可配置的。
color red size big city Chicago
我将描述一种有效的技术。我用过了我没有在推广它,但是它有效。
要将数据旋转到我们不知道可以预先设置什么值的位置,请在没有列的情况下动态创建一个临时表。然后使用游标遍历行,为每个变量发布一个动态构建的"更改表",以便最终临时表具有列,颜色,大小,城市。
然后,在临时表中插入一行,通过另一个游标通过变量,值对对其进行更新,然后选择它(通常与其父实体结合),实际上使这些自定义变量/值对看起来像是内置的,在原始父实体的列中。
所描述的游标方法可能是最少使用的类似SQL的方法。如前所述,SQL 2005及以后版本的PIVOT效果很好。但是对于旧版本和非MS SQL服务器,"优化Transact-SQL"中的Rozenshtein方法(编辑:已绝版,但可从亚马逊获得:http://www.amazon.com/Optimizing-Transact-SQL- Advanced-Programming-Techniques / dp / 0964981203)非常适合透视和透视数据。
它使用点特征将基于行的数据转换为列。 Rozenshtein描述了几种情况,这是一个示例:
SELECT RowValueNowAColumn = CONVERT(varchar, MAX( SUBSTRING(myTable.MyVarCharColumn,1,DATALENGTH(myTable.MyVarCharColumn) * CHARINDEX(sa.SearchAttributeName,'MyRowValue')))) FROM myTable
这种方法比使用case语句更有效,并且适用于各种数据类型和SQL实现(不仅限于MS SQL)。
对于SQL Server 2005中的UNPIVOT,我发现了一篇不错的文章
列到SQL Server中的行
最好将这种事情限制在小范围内。如果我们使用的是SQL 2k,但没有可用的PIVOT功能,则我已草拟了一份存储的proc,它可以为我们完成这项工作。有点麻烦的工作,所以要尽可能地将其拆开。将以下内容粘贴到sql窗口中,并根据需要在底部编辑EXEC。如果要查看正在生成的内容,请删除中间的--s:
IF EXISTS (SELECT * FROM SYSOBJECTS WHERE XTYPE = 'P' AND NAME = 'USP_LIST_CONCAT') DROP PROCEDURE USP_LIST_CONCAT GO CREATE PROCEDURE USP_LIST_CONCAT (@SourceTable NVARCHAR(1000) = '' ,@SplitColumn NVARCHAR(1000) = '' , @Deli NVARCHAR(10) = '', @KeyColumns NVARCHAR(2000) = '' , @Condition NVARCHAR(1000) = '') AS BEGIN SET NOCOUNT ON /* PROCEDURE CREATED 2010 FOR SQL SERVER 2000. SIMON HUGHES. */ /* NOTES: REMOVE --'s BELOW TO LIST GENERATED SQL. */ IF @SourceTable = '' OR @SourceTable = '?' OR @SourceTable = '/?' OR @SplitColumn = '' OR @KeyColumns = '' BEGIN PRINT 'Format for use:' PRINT ' USP_LIST_CONCAT ''SourceTable'', ''SplitColumn'', ''Deli'', ''KeyColumn1,...'', ''Column1 = 12345 AND ...''' PRINT '' PRINT 'Description:' PRINT 'The SourceTable should contain a number of records acting as a list of values.' PRINT 'The SplitColumn should be the name of the column holding the values wanted.' PRINT 'The Delimiter may be any single character or string ie ''/''' PRINT 'The KeyColumn may contain a comma separated list of columns that will be returned before the concatenated list.' PRINT 'The optional Conditions may be left blank or may include the following as examples:' PRINT ' ''Column1 = 12334 AND (Column2 = ''ABC'' OR Column3 = ''DEF'')''' PRINT '' PRINT 'A standard list in the format:' PRINT ' Store1, Employee1, Rabbits' PRINT ' Store1, Employee1, Dogs' PRINT ' Store1, Employee1, Cats' PRINT ' Store1, Employee2, Dogs' PRINT '' PRINT 'Will be returned as:' PRINT ' Store1, Employee1, Cats/Dogs/Rabbits' PRINT ' Store1, Employee2, Dogs' PRINT '' PRINT 'A full ORDER BY and DISTINCT is included' RETURN -1 END DECLARE @SQLStatement NVARCHAR(4000) SELECT @SQLStatement = ' DECLARE @DynamicSQLStatement NVARCHAR(4000) SELECT @DynamicSQLStatement = ''SELECT '+@KeyColumns+', SUBSTRING('' SELECT @DynamicSQLStatement = @DynamicSQLStatement + '' + '' + CHAR(10) + '' MAX(CASE WHEN '+@SplitColumn+' = ''''''+RTRIM('+@SplitColumn+')+'''''' THEN '''''+@Deli+'''+RTRIM('+@SplitColumn+')+'''''' ELSE '''''''' END)'' FROM '+ @SourceTable +' ORDER BY '+@SplitColumn+' SELECT @DynamicSQLStatement = @DynamicSQLStatement + '' ,2,7999) List'' + CHAR(10) + ''FROM '+ @SourceTable+''' + CHAR(10) +'''+CASE WHEN @Condition = '' THEN '/* WHERE */' ELSE 'WHERE '+@Condition END+ '''+ CHAR(10) + ''GROUP BY '+@KeyColumns+''' SELECT @DynamicSQLStatement = REPLACE(@DynamicSQLStatement,''( +'',''('') -- SELECT @DynamicSQLStatement -- DEBUG ONLY EXEC (@DynamicSQLStatement)' EXEC (@SQLStatement) END GO EXEC USP_LIST_CONCAT 'MyTableName', 'ColumnForListing', 'Delimiter', 'KeyCol1, KeyCol2', 'Column1 = 123456'
我有以下格式的数据
Survey_question_ID
电子邮件(用户)
回答
1次调查有13个问答
我想要的期望输出是
用户--- Survey_question_ID1 --- Survey_question_ID2
电子邮件---答案---答案........等等
这是SQL Server 2000的解决方案,因为字段数据类型为TEXT。
DROP TABLE #tmp DECLARE @tmpTable TABLE ( emailno NUMERIC, question1 VARCHAR(80), question2 VARCHAR(80), question3 VARCHAR(80), question4 VARCHAR(80), question5 VARCHAR(80), question6 VARCHAR(80), question7 VARCHAR(80), question8 VARCHAR(80), question9 VARCHAR(80), question10 VARCHAR(80), question11 VARCHAR(80), question12 VARCHAR(80), question13 VARCHAR(8000) ) DECLARE @tmpTable2 TABLE ( emailNumber NUMERIC ) DECLARE @counter INT DECLARE @Email INT SELECT @counter =COUNT(DISTINCT ans.email) FROM answers ans WHERE ans.surveyname=100430 AND ans.qnpkey BETWEEN 233702 AND 233714 SELECT * INTO #tmp FROM @tmpTable INSERT INTO @tmpTable2 (emailNumber) SELECT DISTINCT CAST(ans.email AS NUMERIC) FROM answers ans WHERE ans.surveyname=100430 AND ans.qnpkey BETWEEN 233702 AND 233714 WHILE @counter >0 BEGIN SELECT TOP 1 @Email= emailNumber FROM @tmpTable2 INSERT INTO @tmpTable (emailno) VALUES (@Email ) Update @tmpTable set question1=CAST(answer as VARCHAR(80)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233702 and ans.email=@Email Update @tmpTable set question2=CAST(answer as VARCHAR(80)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233703 and email=@email Update @tmpTable set question3=CAST(answer as VARCHAR(80)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233704 and email=@email Update @tmpTable set question4=CAST(answer as VARCHAR(80)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233705 and email=@email Update @tmpTable set question5=CAST(answer as VARCHAR(80)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233706 and email=@email Update @tmpTable set question6=CAST(answer as VARCHAR(80)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233707 and email=@email Update @tmpTable set question7=CAST(answer as VARCHAR(80)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233708 and email=@email Update @tmpTable set question8=CAST(answer as VARCHAR(80)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233709 and email=@email Update @tmpTable set question9=CAST(answer as VARCHAR(80)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233710 and email=@email Update @tmpTable set question10=CAST(answer as VARCHAR(80)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233711 and email=@email Update @tmpTable set question11=CAST(answer as VARCHAR(80)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233712 and email=@email Update @tmpTable set question12=CAST(answer as VARCHAR(80)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233713 and email=@email Update @tmpTable set question13=CAST(answer as VARCHAR(8000)) from answers ans where ans.surveyname=100430 and ans.qnpkey = 233714 and email=@email insert into #tmp select * from @tmpTable DELETE FROM @tmpTable DELETE FROM @tmpTable2 WHERE emailNumber= @Email set @counter =@counter -1 End select * from #tmp