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 ║
╚══════════════════════════╝
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) |
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
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:
où Row Labels inclut au bas une colonne de cellules avec des numéros d'index uniques.