web-dev-qa-db-fra.com

Faire pivoter les lignes en colonnes sans agrégat

Essayer de comprendre comment écrire une instruction SQL dynamique de type pivot. Où TEST_NAME pourrait avoir jusqu'à 12 valeurs différentes (donc avoir 12 colonnes). Certains des types VAL seront des types de données Int, Decimal ou Varchar. La plupart des exemples que j'ai vus ont certains des agrégats inclus. Je cherche un pivot direct.

Source Table 

╔═══════════╦══════╦═══════╗
║ TEST_NAME ║ SBNO ║  VAL  ║
╠═══════════╬══════╬═══════╣
║ Test1     ║    1 ║ 0.304 ║
║ Test1     ║    2 ║ 0.31  ║
║ Test1     ║    3 ║ 0.306 ║
║ Test2     ║    1 ║ 2.3   ║
║ Test2     ║    2 ║ 2.5   ║
║ Test2     ║    3 ║ 2.4   ║
║ Test3     ║    1 ║ PASS  ║
║ Test3     ║    2 ║ PASS  ║
╚═══════════╩══════╩═══════╝


Desired Output 
╔══════════════════════════╗
║ SBNO Test1 Test2   Test3 ║
╠══════════════════════════╣
║ 1    0.304  2.3    PASS  ║
║ 2    0.31   2.5    PASS  ║
║ 3    0.306  2.4    NULL  ║
╚══════════════════════════╝
17
jlimited

La fonction PIVOT nécessite une agrégation pour la faire fonctionner. Il semble que votre colonne VAL soit une varchar et vous devrez donc utiliser les fonctions d'agrégation MAX ou MIN.

Si le nombre de tests est limité, vous pouvez coder en dur les valeurs:

select sbno, Test1, Test2, Test3
from
(
  select test_name, sbno, val
  from yourtable
) d
pivot
(
  max(val)
  for test_name in (Test1, Test2, Test3)
) piv;

Voir SQL Fiddle avec Demo .

Dans votre PO, vous avez indiqué que vous aurez un plus grand nombre de lignes à transformer en colonnes. Si tel est le cas, vous pouvez utiliser le SQL dynamique:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT distinct ',' + QUOTENAME(TEST_NAME) 
                    from yourtable
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT sbno,' + @cols + '
             from 
             (
                select test_name, sbno, val
                from yourtable
            ) x
            pivot 
            (
                max(val)
                for test_name in (' + @cols + ')
            ) p '

execute(@query)

Voir SQL Fiddle avec Demo .

Les deux versions donneront le même résultat:

| SBNO | TEST1 | TEST2 |  TEST3 |
---------------------------------
|    1 | 0.304 |   2.3 |   PASS |
|    2 |  0.31 |   2.5 |   PASS |
|    3 | 0.306 |   2.4 | (null) |
27
Taryn

Il n’existe aucun moyen de PIVOT sans agrégation.

CREATE TABLE #table1
(
    TEST_NAME VARCHAR(10),
    SBNO VARCHAR(10),
    VAL VARCHAR(10)
);

INSERT INTO #table1 (TEST_NAME, SBNO, VAL)
VALUES ('Test1' ,'1', '0.304'),
       ('Test1' ,'2', '0.31'),
       ('Test1' ,'3', '0.306'),
       ('Test2' ,'1', '2.3'),
       ('Test2' ,'2', '2.5'),
       ('Test2' ,'3', '2.4'),
       ('Test3' ,'1', 'PASS'),
       ('Test3' ,'2', 'PASS')

WITH T AS
(
    SELECT SBNO, VAL, TEST_NAME    
      FROM #table1
) 
SELECT *
  FROM T
 PIVOT (MAX(VAL) FOR TEST_NAME IN([Test1], [Test2], [Test3])) P
4
Samina

Une solution de contournement pourrait consister à faire en sorte que l'agrégation obligatoire ne soit appliquée qu'à un seul enregistrement. Dans Excel par exemple, le résultat pourrait être: 

SO15674373 example

où Row Labels inclut au bas une colonne de cellules avec des numéros d'index uniques.

0
pnuts