2015-01-08 6 views
8

Ich weiß, viele von Ihnen haben dieses Verhalten beobachtet, aber ich frage mich, ob jemand warum erklären kann. Wenn ich eine kleine Tabelle erstellen, die ein Beispiel für die Verwendung der Pivot-Funktion zu erstellen, ich die Ergebnisse erhalten, würde ich erwarten:Warum Pivot mit "extra" Spalten kombiniert keine Ergebnisse

CREATE TABLE dbo.AverageFishLength 
    (
     Fishtype VARCHAR(50) , 
     AvgLength DECIMAL(8, 2) , 
     FishAge_Years INT 
    ) 
INSERT INTO dbo.AverageFishLength 
     (Fishtype, AvgLength, FishAge_Years) 
VALUES ('Muskie', 32.75, 3), 
     ('Muskie', 37.5, 4), 
     ('Muskie', 39.75, 5), 
     ('Walleye', 16.5, 3), 
     ('Walleye', 18.25, 4), 
     ('Walleye', 20.0, 5), 
     ('Northern Pike', 20.75, 3), 
     ('Northern Pike', 23.25, 4), 
     ('Northern Pike', 26.0, 5); 

Hier ist die Abfrage Dreh:

SELECT Fishtype , 
     [3] AS [3 Years Old] , 
     [4] AS [4 Years Old] , 
     [5] AS [5 Years Old] 
FROM dbo.AverageFishLength PIVOT(SUM(AvgLength) 
           FOR FishAge_Years IN ([3], [4], [5])) AS PivotTbl 

Hier sind die Ergebnisse:

enter image description here

Allerdings, wenn ich die Tabelle mit einer Identitätsspalte erstellen, erhalten die Ergebnisse in getrennte Linien getrennt:

DROP TABLE dbo.AverageFishLength 
CREATE TABLE dbo.AverageFishLength 
    (
     ID INT IDENTITY(1,1) , 
     Fishtype VARCHAR(50) , 
     AvgLength DECIMAL(8, 2) , 
     FishAge_Years INT 
    ) 
INSERT INTO dbo.AverageFishLength 
     (Fishtype, AvgLength, FishAge_Years) 
VALUES ('Muskie', 32.75, 3), 
     ('Muskie', 37.5, 4), 
     ('Muskie', 39.75, 5), 
     ('Walleye', 16.5, 3), 
     ('Walleye', 18.25, 4), 
     ('Walleye', 20.0, 5), 
     ('Northern Pike', 20.75, 3), 
     ('Northern Pike', 23.25, 4), 
     ('Northern Pike', 26.0, 5); 

Gleiche genaue Abfrage:

SELECT Fishtype , 
     [3] AS [3 Years Old] , 
     [4] AS [4 Years Old] , 
     [5] AS [5 Years Old] 
FROM dbo.AverageFishLength PIVOT(SUM(AvgLength) 
           FOR FishAge_Years IN ([3], [4], [5])) AS PivotTbl 

Unterschiedliche Ergebnisse:

enter image description here

Es erscheint mir, dass die ID-Spalte verwendet wird, in der Abfrage ist, auch wenn es nicht erscheint in der Abfrage überhaupt. Es ist fast so, als wäre es implizit in der Abfrage enthalten, aber nicht in der Ergebnismenge.

Kann jemand erklären, warum dies geschieht?

+1

Ich sollte hinzufügen, dass ich weiß, wie ich es umgehen kann, mit einer Unterabfrage oder row_number über ... Ich bin wirklich nur daran interessiert, warum es passiert ist. –

+2

Diese Frage hat mich hungrig gemacht – billinkc

Antwort

11

Es passiert, weil die ID Spalte für jede Zeile eindeutig ist und da Sie die Tabelle direkt abfragen (ohne eine Unterabfrage), die Spalte als Teil der GROUP BY die Aggregatfunktion benötigt.

Die docs die MSDN docs about FROM Zustand die folgenden:

table_source PIVOT <pivot_clause>

Gibt an, dass die table_source basierend auf dem pivot_column geschwenkt wird. table_source ist ein Tabellen- oder Tabellenausdruck. Die Ausgabe ist eine Tabelle, die alle Spalten der table_source außer pivot_column und value_column enthält. Die Spalten der table_source, außer der pivot_column und der value_column, heißen die Gruppierungsspalten des Pivot-Operators.

PIVOT führt eine Gruppierungsoperation auf der Eingangstabelle bezüglich der Gruppierungsspalten und gibt eine Zeile für jede Gruppe. Darüber hinaus enthält die Ausgabe eine Spalte für jeden Wert, der in der column_list in der pivot_column der input_table angegeben ist.

Ihre Version sagt im Grunde SELECT * FROM yourtable und PIVOT diese Daten. Obwohl die ID Spalte nicht in Ihrer endgültigen SELECT-Liste ist, ist es ein Gruppierungselement für die Abfrage. Wenn Sie den PIVOT mit einem "Pre-PIVOT" -Beispiel vergleichen, werden Sie sehen, was Ihre Version ist.Dieses Beispiel verwendet einen CASE-Ausdruck und eine Aggregatfunktion:

SELECT Fishtype, 
    sum(case when FishAge_Years = 3 then AvgLength else 0 end) as [3], 
    sum(case when FishAge_Years = 4 then AvgLength else 0 end) as [4], 
    sum(case when FishAge_Years = 5 then AvgLength else 0 end) as [5] 
FROM dbo.AverageFishLength 
GROUP BY Fishtype, ID; 

Das Ergebnis verzerrt werden, denn auch wenn Sie die ID in der endgültigen Liste nicht haben, ist es noch zu einer Gruppe verwendet wird, durch und da sind sie einzigartig , Sie erhalten mehrere Zeilen.

Der einfachste Weg, um diese bei der Verwendung von PIVOT wird mit einer Unterabfrage zu lösen:

SELECT Fishtype , 
     [3] AS [3 Years Old] , 
     [4] AS [4 Years Old] , 
     [5] AS [5 Years Old] 
FROM 
(
    SELECT Fishtype, 
    AvgLength, 
    FishAge_Years 
    FROM dbo.AverageFishLength 
) d 
PIVOT 
( 
    SUM(AvgLength) 
    FOR FishAge_Years IN ([3], [4], [5]) 
) AS PivotTbl; 

In dieser Version nur die Spalten der Rückkehr, die Sie tatsächlich benötigen und aus Ihrer Tabelle wollen - dies schließt ID so wird es nicht zum Gruppieren Ihrer Daten verwendet werden.

+0

Ok, ich verstehe. Es wäre nett, wenn es in der Syntax transparenter wäre oder wenn Sie bestimmte Spalten aus der Tabelle ausschließen könnten, indem Sie sie aus dem SELECT ausschließen, anstatt eine Unterabfrage durchführen zu müssen. Danke für deine gründliche Erklärung. –

+0

@ Dave.Gugg Es ist tatsächlich in der Dokumentation, siehe meine Bearbeitung. Es ist in den Dokumenten für ['FROM'] (http://technet.microsoft.com/en-us/library/ms177634%28v=sql.105%29.aspx) versteckt. – Taryn

+3

(+1) Ich benutze selten 'PIVOT' in diesen Tagen. Die manuelle Methode ist oft expliziter, leichter lesbar und führt zu exakt demselben Ausführungsplan. –

Verwandte Themen