2010-11-19 8 views
6

Dies wird die erste Frage sein, die ich hier gepostet habe, so entschuldigen Sie alle unbeabsichtigten Fehler in Bord Etikette."Pivoting" nicht aggregierte Daten in SQL Server

In meinem aktuellen Projekt habe ich eine große, nicht normalisierte Tabelle genommen und in vier separate, normalisierte Tabellen aufgeteilt. Mein ultimatives Ziel, das ich für dieses Board erreiche, besteht darin, eine Ansicht zu erstellen, die die nicht normalisierte Tabelle aus Gründen der Abwärtskompatibilität imitiert.

Um eine vereinfachte Momentaufnahme meines Szenario zu bieten, den Kern dessen, was ich versuche, liegt in zwei Tabellen zu tun:

ASSOC_ROLE   ASSOCIATE 
----------   ---------- 
assoc_id (fk)  assoc_id (pk) 
role_id (fk)  last_name 
org_nbr (fk) 

Also, wenn ich die folgende Abfrage ...

SELECT Assoc_Role.org_nbr, Assoc_Role.assoc_id, Associate.last_name, Assoc_Role.role_id 
FROM Assoc_Role INNER JOIN 
    Associate ON Assoc_Role.assoc_id = Associate.assoc_id 
WHERE Assoc_Role.org_nbr = '1AA' 

... ich erhalte das folgende Ergebnis

gesetzt
org_nbr  assoc_id  last_name  role_id 
-------  --------  ---------  ------- 
1AA   1447   Cooper  1 
1AA   1448   Collins  3 
1AA   1448   Collins  4 
1AA   1448   Collins  5 
1AA   1449   Lynch   6 

Letzten Endes der Ansicht ich mag würde wie folgt aussehen würde, konstruieren :

org_nbr role1_ID role1_name role2_ID role2_name role3_ID role3_name role4_ID role4_name role5_ID role5_name role6_ID role6_name 
------- -------- ---------- -------- ---------- -------- ---------- -------- ---------- -------- ---------- -------- ---------- 
1AA  1447  Cooper  NULL  NULL   1448  Collins  1448  Collins  1448  Collins  1449  Lynch 

Mein erster Gedanke war, zu versuchen, den PIVOT-Befehl zu verwenden, aber mein Verständnis ist, dass PIVOT eine Art von Aggregation erfordert, und dass mein Szenario nicht paßt. Ich habe auch mit dem CASE-Befehl in der SELECT-Klausel herumgewirbelt, aber meine Ergebnismenge wird nicht auf einen Datensatz reduziert.

Hoffentlich kann jemand etwas Licht darauf werfen, wie ich das erreichen kann. Lassen Sie mich wissen, wenn jemand mehr Informationen benötigt. Vielen Dank!

Scot

Antwort

2

Um die grundlegenden nummerierte-Rollendaten zu erhalten, könnten wir mit

SELECT 
    org_nbr 
    , r1.assoc_id role1_ID 
    , r1.last_name role1_name 
    , r2.assoc_id role2_ID 
    , r2.last_name role2_name 
    , r3.assoc_id role3_ID 
    , r3.last_name role3_name 
    , r4.assoc_id role4_ID 
    , r4.last_name role4_name 
    , r5.assoc_id role5_ID 
    , r5.last_name role5_name 
    , r6.assoc_id role6_ID 
    , r6.last_name role6_name 
FROM 
    ASSOC_ROLE ar 
    LEFT JOIN ASSOCIATE r1 ON ar.role_id = 1 AND ar.assoc_id = r1.assoc_id 
    LEFT JOIN ASSOCIATE r2 ON ar.role_id = 2 AND ar.assoc_id = r2.assoc_id 
    LEFT JOIN ASSOCIATE r3 ON ar.role_id = 3 AND ar.assoc_id = r3.assoc_id 
    LEFT JOIN ASSOCIATE r4 ON ar.role_id = 4 AND ar.assoc_id = r4.assoc_id 
    LEFT JOIN ASSOCIATE r5 ON ar.role_id = 5 AND ar.assoc_id = r5.assoc_id 
    LEFT JOIN ASSOCIATE r6 ON ar.role_id = 6 AND ar.assoc_id = r6.assoc_id 

ABER dies wird uns für jede org_nbr, eine separate Zeile für jede role_id beginnen, die Daten hat ! Was wir nicht wollen - also müssen wir GROUP BY org_nbr. Aber dann müssen wir entweder GROUP BY oder aggregieren über jede Spalte in der SELECT Liste! Der Trick ist dann, mit einer Aggregatfunktion zu kommen, die SQL Server und bringt uns die Ergebnisse, die wir wollen. In diesem Fall wird MIN die Arbeit machen:

SELECT 
    org_nbr 
    , MIN(r1.assoc_id) role1_ID 
    , MIN(r1.last_name) role1_name 
    , MIN(r2.assoc_id) role2_ID 
    , MIN(r2.last_name) role2_name 
    , MIN(r3.assoc_id) role3_ID 
    , MIN(r3.last_name) role3_name 
    , MIN(r4.assoc_id) role4_ID 
    , MIN(r4.last_name) role4_name 
    , MIN(r5.assoc_id) role5_ID 
    , MIN(r5.last_name) role5_name 
    , MIN(r6.assoc_id) role6_ID 
    , MIN(r6.last_name) role6_name 
FROM 
    ASSOC_ROLE ar 
    LEFT JOIN ASSOCIATE r1 ON ar.role_id = 1 AND ar.assoc_id = r1.assoc_id 
    LEFT JOIN ASSOCIATE r2 ON ar.role_id = 2 AND ar.assoc_id = r2.assoc_id 
    LEFT JOIN ASSOCIATE r3 ON ar.role_id = 3 AND ar.assoc_id = r3.assoc_id 
    LEFT JOIN ASSOCIATE r4 ON ar.role_id = 4 AND ar.assoc_id = r4.assoc_id 
    LEFT JOIN ASSOCIATE r5 ON ar.role_id = 5 AND ar.assoc_id = r5.assoc_id 
    LEFT JOIN ASSOCIATE r6 ON ar.role_id = 6 AND ar.assoc_id = r6.assoc_id 
GROUP BY 
    org_nbr 

Ausgang:

org_nbr role1_ID role1_name role2_ID role2_name role3_ID role3_name role4_ID role4_name role5_ID role5_name role6_ID role6_name 
---------- ----------- ---------- ----------- ---------- ----------- ---------- ----------- ---------- ----------- ---------- ----------- ---------- 
1AA  1447  Cooper  NULL  NULL  1448  Collins 1448  Collins 1448  Collins 1449  Lynch 
Warning: Null value is eliminated by an aggregate or other SET operation. 

Natürlich wird diese kurze fallen sollte die maximale role_id Anstieg ...

+0

Interessant ... Ich bin ziemlich neu in der Bildung von SQL-Abfragen auf dieser fortgeschrittenen Ebene, so hätte ich nie daran gedacht, hintereinander eine Tabelle mit sich selbst zu verbinden, aber kann klar sehen, wie das funktioniert. Meine nächste Herausforderung wird das in eine größere Anfrage einbeziehen, aber das gibt mir einen guten Start. Vielen Dank! Eine Frage obwohl, in Bezug auf: "Natürlich wird dies nicht reichen, sollte die maximale role_id erhöhen ..." Meinen Sie einfach zu sagen, wenn ich weitere role_ID hinzufügen würde, müsste ich sie in der Frage, oder schlägst du mehr vor? – ScottieByNature

+0

@ScottieByNature Wenn die maximale 'role_ID' steigt, haben Sie zwei Möglichkeiten. Wenn die Änderung in der Richtung von "es gab früher höchstens 6, aber jetzt sind es höchstens 9" ist, müssten Sie die Abfrage in dem, was ich hoffe, ist der klare Weg hinzufügen. Wenn jedoch "es wird jetzt eine beliebige Anzahl von möglichen Rollen geben", dann sollte ein anderer Ansatz gesucht werden - in diesem Fall kommen die Überlegungen von @Chris Lively ins Spiel, und Sie sollten darüber nachdenken, dies außerhalb von SQL zu tun oder dynamisch zu verwenden SQL, oder etwas ganz anderes - Sie könnten kommen und fragen Sie hier :) – AakashM

+0

Verstanden ... sehr geschätzt! – ScottieByNature

2

Wenn Sie können, würde ich empfehlen sehr, diese Art des Pivotierens in regulärem Code (C#, vb, was auch immer) zu machen.

Pivoting in SQL-Server hat eine Menge Nachteile. Erstens wird alles, was mehr als 7 oder 8 Elemente umfasst, die Zeit, die Ihre Abfragen benötigen, massiv erhöhen. Zweitens erfordert es, dass Sie entweder dynamische SQL oder alle potenziellen IDs vor der Zeit wissen. Drittens wird es schwierig zu erhalten sein.

Die gleichen Probleme existieren in AakashMs Antwort.

Wir haben viele verschiedene Möglichkeiten ausprobiert, um dies in einer reinen SQL-Umgebung zu ermöglichen. Bei kleinen Datensätzen mit sehr begrenzten Pivot-Werten funktioniert das problemlos. Die Anzahl der Rollen-IDs, die Sie bereits überschritten haben, geht jedoch darüber hinaus.

Stattdessen greifen Sie einfach die Daten und in Ihrer bevorzugten Sprache erstellen Sie die Tabelle, die Sie benötigen. Zu diesem Zeitpunkt entweder die Daten in eine andere SQL-Tabelle oder senden Sie es an wohin auch immer es gehen muss.

+0

Ein fairer Vorschlag ... Das System, für das ich diese abwärtskompatible Ansicht erstellen möchte, basiert jedoch auf Visual FoxPro. Ich nehme an, ich habe einfach angenommen, dass es mir leichter fallen würde, eine Sicht auf diese Komplexität in SQL Server vs FoxPro zu erstellen. Ich werde diese Überlegung unbedingt berücksichtigen, während ich weiter daran arbeite. Vielen Dank! – ScottieByNature

Verwandte Themen