Comment PIVOTer les données de la requête MSSQL et les récupérer en vue PHP

Dec 04 2020

J'ai une base de données MSSQL 2005 avec un contenu de requête comme celui-ci:

nopas code Nom ordre
00115301 D031 ADAM 1
00130015 D031 ADAM 2
00149998 D026 JAMES 1
00149970 D028 FIKI 1
00142641 D028 FIKI 2
00127700 D028 FIKI 3

Pour des raisons de rapport, j'ai besoin de produire un tableau comme:

ADAM JAMES FIKI ... (nouvel enregistrement basé sur un contenu dynamique)
00115301 00149998 00149970 ...
00130015 - 00142641 ...
- - 00127700 ...

Quelqu'un peut-il m'aider??

Réponses

Jason Dec 04 2020 at 16:46

Vous pouvez faire un pivot avec des CASEinstructions. C'est fondamentalement la manière manuelle de pivoter et si vous utilisiez une version de SQL Server avant 2005, vous auriez besoin d'emprunter cette voie. SQL Server 2005 a ajouté la fonction PIVOT .

Parce que vous en avez besoin pour être dynamique, vous devrez utiliser du SQL dynamique . C'est beaucoup de travail pour les jambes, mais c'est certainement faisable.

Je vais créer le contenu de votre table dans une table temporaire globale (doit être globale pour fonctionner en SQL dynamique).

-- CREATE GLOBAL TEMPORARY TABLE
CREATE TABLE ##tablename (
  [nopas] VARCHAR(8),
  [code] VARCHAR(4),
  [name] VARCHAR(64),
  [order] SMALLINT
);

INSERT INTO ##tablename
  ([nopas], [code], [name], [order])
VALUES
 ('00115301','D031','ADAM',  1)
,('00130015','D031','ADAM',  2)
,('00149998','D026','JAMES', 1)
,('00149970','D028','FIKI',  1)
,('00142641','D028','FIKI',  2)
,('00127700','D028','FIKI',  3);

Ensuite, je vais SELECTsimplement placer les noms uniques dans une autre table temporaire et les associer à un IDENTITYavec lequel je peux parcourir dans une boucle for.

SELECT IDENTITY(INT, 1,1) as [id], [name] 
INTO #temp
FROM ##tablename
GROUP BY [name];

Vient maintenant la partie difficile. Le PRINT @dynSQLgénère ce que j'essaie de réaliser dynamiquement (ci-dessous). Nous devons SELECTle [order], [name]et [nopas]pour le résultat final. Nous pivotons sur le [name]dans la deuxième partie de l'énoncé et agrégons par MAX([nopas]); mais comme nous contenons un [order]regroupement dans le contenu de votre table d'origine, il ne récupérera que la MAX([nopas])base de la MAXvaleur d'une seule ligne. Ainsi, le résultat est qu'il supprime l'agrégation. Si vous n'avez pas une [order]colonne dans votre contenu original, nous aurions besoin d'utiliser la fonction ROW_NUMBER () * PARTITIONED BYle [name]pour produire que [order].

EDIT: J'ai découvert que la ROW_NUMBER()fonction n'est disponible que dans SQL Server 2012 et plus récent.

-- PRINT @dynSQL result
SELECT * FROM
(SELECT [order], [name], [nopas]
  FROM ##tablename) AS sourceTable
PIVOT(
MAX([nopas])
FOR [name] IN ([ADAM],[FIKI],[JAMES])
) AS pivotTable;
-- The leg work to create the dynamic SQL.
DECLARE @count INT = 1;
DECLARE @max INT = (SELECT MAX(id) FROM #temp);
DECLARE @dynSQL VARCHAR(2048) = 'SELECT * FROM
(SELECT [order], [name], [nopas]
  FROM ##tablename) AS sourceTable
PIVOT(
MAX([nopas])
FOR [name] IN (';

SET @count = 1;
WHILE(@count <= @max)
BEGIN
  SET @dynSQL += '[' + (SELECT [name] FROM #temp WHERE id = @count) + '],';
  SET @count += 1;
END

SET @dynSQL = LEFT(@dynSQL, DATALENGTH(@dynSQL) -1) + ')
) AS pivotTable;';

PRINT @dynSQL;
EXEC (@dynSQL);

DROP TABLE ##tablename;
DROP TABLE #temp;

Oh, si vous voulez supprimer la [order]colonne, du résultat. Vous pouvez utiliser SELECT * INTO ##newGlobalTabledans le SQL dynamique, puis ALTERla nouvelle table et DROPla colonne.