Transpor um conjunto de linhas como colunas em SQL Server 2000
-
02-07-2019 - |
Pergunta
Existe alguma facilidade de transposição linhas para colunas no SQL Server (é possível em MS-Access)? Eu estava confuso, porque esta facilidade está disponível em MS-Access, mas não no SQL Server. É por design que este recurso não foi incluído no SQL Server?
Solução
O exemplo em http://jdixon.dotnetdevelopersjournal.com/pivot_table_data_in_sql_server_2000_and_2005.htm única funciona se você sabe de antemão o que os valores de linha pode ser. Por exemplo, digamos que você tem uma entidade com atributos personalizados e os atributos personalizados são implementados como linhas em uma tabela filho, onde tabela filho é basicamente pares de valores / variáveis, e essas variáveis ??pares / valor são configuráveis.
color red
size big
city Chicago
Eu estou indo para descrever uma técnica que funciona. Eu usei-o. Eu não estou a promovê-lo, mas ele funciona.
Para girar os dados em que você não sabe o que os valores podem ser adiantado, criar uma tabela temporária na mosca sem colunas. Em seguida, use um cursor para loop através de suas linhas, a emissão de um construído de forma dinâmica "ALTER TABLE" para cada variável, de modo que, no final, a sua tabela temporária tem a colunas, cor, tamanho, cidade.
Em seguida, você inserir uma linha na sua tabela temp, atualizá-lo através de outro cursor através da variável, valor pares, e, em seguida, selecione-o, geralmente se juntou com a sua empresa-mãe, na verdade fazendo parecer que os pares variável personalizada / valor foram como built-in colunas na entidade pai original.
Outras dicas
O método cursor descrito é provavelmente o menos SQL-like para uso. Como mencionado, o SQL 2005 e tem PIVOT que funciona muito bem. Mas para versões mais antigas e servidores SQL não-MS, o método Rozenshtein de "Optimzing Transact-SQL" (edit: fora de catálogo, mas aproveitar da Amazon:. http://www.amazon.com/Optimizing-Transact-SQL-Advanced-Programming-Techniques/dp/0964981203 ), é excelente para girar e dados unpivoting. Ele usa características de ponto de transformar dados com base linhas em colunas. Rozenshtein descreve vários casos, aqui está um exemplo:
SELECT
RowValueNowAColumn =
CONVERT(varchar,
MAX(
SUBSTRING(myTable.MyVarCharColumn,1,DATALENGTH(myTable.MyVarCharColumn)
* CHARINDEX(sa.SearchAttributeName,'MyRowValue'))))
FROM
myTable
Este método é muito mais eficiente do que o uso de declarações de caso e trabalhos para uma variedade de tipos de dados e implementações de SQL (não apenas MS SQL).
melhor limitar a escala pequena para este tipo de coisa. Se você estiver usando SQL 2k embora e não tem PIVOT recursos disponíveis, já elaborou um proc armazenado que deve fazer o trabalho para você. Bit de um trabalho falha crítica corrida tão puxá-lo para além, tanto quanto você gosta. Cole o abaixo em uma janela SQL e editar o EXEC na parte inferior como preferidos. Se você quiser ver o que está sendo gerado, retire as -S no meio:
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'
Para UNPIVOT no sql server 2005, eu encontrei um bom artigo
Eu tenho dados no seguinte formato
Survey_question_ID
E-mail (User )
Resposta ??strong>
para uma pesquisa há 13 perguntas e respostas a saída desejada que eu queria era
usuário --- Survey_question_ID1 --- Survey_question_ID2
e-mail --- respostas --- resposta ??strong> ........ assim por diante
Aqui está a solução para SQL Server 2000 , tipo Causa dados de campo é texto .
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