Transposer un ensemble de lignes sous forme de colonnes dans SQL Server 2000

StackOverflow https://stackoverflow.com/questions/152770

  •  02-07-2019
  •  | 
  •  

Question

Existe-t-il une possibilité de transposer des lignes en colonnes dans SQL Server (cela est possible dans MS-Access)? J'ai été embarrassé parce que cette installation est disponible dans MS-Access mais pas dans SQL Server. Est-ce que par sa conception même cette fonctionnalité n'a pas été incluse dans SQL Server?

Était-ce utile?

La solution

color red
size  big
city  Chicago

Je vais décrire une technique qui fonctionne. Je l'ai utilisé. Je ne fais pas la promotion, mais ça marche.

Pour faire pivoter les données là où vous ne savez pas ce que peuvent être les valeurs, créez une table temporaire à la volée, sans colonnes. Utilisez ensuite un curseur pour parcourir vos lignes et créer un "alter table" construit de manière dynamique. pour chaque variable, de sorte que votre table temporaire contienne les colonnes, la couleur, la taille, la ville.

Ensuite, vous insérez une ligne dans votre table temporaire, vous la mettez à jour via un autre curseur via la variable, paires de valeur, puis vous la sélectionnez, généralement jointe à son entité parente, ce qui donne l'impression que ces paires personnalisées de variable / valeur étaient comme des colonnes intégrées dans l'entité parent d'origine.

Autres conseils

La méthode du curseur décrite est probablement la moins compatible SQL à utiliser. Comme mentionné, SQL 2005 et sur PIVOT qui fonctionne très bien. Mais pour les anciennes versions et les serveurs SQL non-MS, la méthode Rozenshtein de "Optimzing Transact-SQL" (éditer: épuisé, mais disponible chez Amazon: http: //www.amazon .com / Optimizing-Transact-SQL-Techniques-de-programmation-avancées / dp / 0964981203 ), est excellent pour les données pivotantes et non pivotantes. Il utilise des caractéristiques de point pour transformer les données basées sur les lignes en colonnes. Rozenshtein décrit plusieurs cas. En voici un exemple:

SELECT
    RowValueNowAColumn = 
       CONVERT(varchar,
           MAX(
          SUBSTRING(myTable.MyVarCharColumn,1,DATALENGTH(myTable.MyVarCharColumn)
       * CHARINDEX(sa.SearchAttributeName,'MyRowValue'))))
FROM
    myTable

Cette méthode est beaucoup plus efficace que l'utilisation d'instructions case et fonctionne pour une variété de types de données et d'implémentations SQL (pas seulement MS SQL).

Il est préférable de limiter à petite échelle pour ce genre de chose. Si vous utilisez SQL 2k et que vous ne disposez pas des fonctionnalités PIVOT, j'ai rédigé un proc stocké qui devrait faire le travail à votre place. C'est un travail fastidieux, alors séparez-le autant que vous le souhaitez. Collez le ci-dessous dans une fenêtre SQL et éditez le fichier EXEC en bas, selon vos préférences. Si vous voulez voir ce qui est généré, supprimez le --s au milieu:

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'

Pour UNPIVOT dans SQL Server 2005, j’ai trouvé un bon article

colonnes-à-lignes-dans-serveur SQL

J'ai des données au format suivant

Survey_question_ID

Email (utilisateur )

Répondre

pour 1 enquête, il y a 13 questions et réponses la sortie souhaitée que je voulais était

Utilisateur --- Survey_question_ID1 --- Survey_question_ID2

e-mail --- réponses --- réponses ........ et ainsi de suite

Voici la solution pour SQL Server 2000 , le type de données du champ Cause est 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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top