- Krótko o tabelach przestawnych
- Obracanie danych za pomocą narzędzi (dbForge Studio dla MySQL)
- Przestawianie danych za pomocą SQL
- Przykład oparty na T-SQL dla SQL Server
- Przykład dla MySQL
- Automatyzacja przestawiania danych, dynamiczne tworzenie zapytań
Krótko o tabelach przestawnych
Ten artykuł dotyczy transformacji danych tabeli z wierszy na kolumny. Taka transformacja nazywana jest tabelami przestawnymi. Często wynikiem obrotu jest tabela podsumowująca, w której dane statystyczne prezentowane są w formie odpowiedniej lub wymaganej dla raportu.
Poza tym taka transformacja danych może być przydatna, jeśli baza danych nie jest znormalizowana, a informacje są w niej przechowywane w nieoptymalnej formie. Tak więc przy reorganizacji bazy danych i przenoszeniu danych do nowych tabel lub generowaniu wymaganej reprezentacji danych pomocny może być mechanizm obrotu danych, czyli przenoszenia wartości z wierszy do wynikowych kolumn.
Poniżej przykład starej tabeli produktów – ProductsOld oraz nowej – ProductsNew. Taki wynik można łatwo osiągnąć dzięki przekształceniu z wierszy na kolumny.
Oto przykład tabeli przestawnej.
Przestawianie danych za pomocą narzędzi (dbForge Studio dla MySQL)
Istnieją aplikacje, które posiadają narzędzia pozwalające na implementację obrotu danych w wygodnym środowisku graficznym. Na przykład dbForge Studio dla MySQL zawiera funkcjonalność tabel przestawnych, która zapewnia pożądany rezultat w zaledwie kilku krokach.
Spójrzmy na przykład z uproszczoną tabelą zamówień – PurchaseOrderHeader .
CREATE TABLE NagłówekZamówieniaZakupu (IdZamówieniaZakupu INT(11) NOT NULL, IDPracownika INT(11) NIEZEROWY,Identyfikator dostawcy INT(11) NIEZEROWY,KLUCZ PODSTAWOWY (IdZamówieniaZakupu));WSTAW nagłówekZamówieniaZakupu(IdZamówieniaZakupu,IdentyfikatorZakupu,IdentyfikatorDostawcy) , 258, 1580); WSTAW nagłówek zamówienia zakupu (IDZamówieniaZakupu, IDPracownika, IDDostawcy) VALUES (2, 254, 1496);WSTAW NagłówekZamówieniaZakupu (IDZamówieniaZakupu, IDPracownika, IDDostawcy) ) WARTOŚCI (4, 261, 1650); WSTAW nagłówek zamówienia zakupu (ID zamówienia zakupu, identyfikator pracownika, identyfikator dostawcy) WARTOŚCI (5, 251, 1654); WSTAW nagłówek zamówienia zakupu (identyfikator zamówienia zakupu, identyfikator pracownika, identyfikator dostawcy) WARTOŚCI (6, 253, 1664); , IDPracownika, IDDostawcy) WARTOŚCI (7, 255, 1678);WSTAW nagłówekZamówieniaZakupu (IDZamówieniaZakupu, IDPracownika, IDDostawcy) WSTAW nagłówek zamówienia zakupu (identyfikator zamówienia zakupu, IDPracownika, IDDostawcy) WARTOŚCI (10, 250, 1602); WSTAW nagłówekZamówieniaZakupu (IDZamówieniaZakupu, IDPracownika, IDDostawcy) WARTOŚCI (11, 258, 1540);...
Załóżmy, że musimy dokonać wyboru z tabeli i określić liczbę zamówień składanych przez poszczególnych pracowników u konkretnych dostawców. Lista pracowników, dla których potrzebne są informacje – 250, 251, 252, 253, 254.
Preferowany widok raportu jest następujący.
Lewa kolumna Identyfikator dostawcy pokazuje identyfikatory dostawców; kolumny Emp250 , Emp251 , Emp252 , Emp253 i Emp254 wyświetlić liczbę zamówień.
Aby to osiągnąć w dbForge Studio dla MySQL, musisz:
- Dodaj tabelę jako źródło danych dla reprezentacji dokumentu „Tabela przestawna”. W Eksploratorze bazy danych kliknij prawym przyciskiem myszy PurchaseOrderHeader tabeli i wybierz Wyślij do a następnie Tabela przestawna w wyskakującym menu.
- Określ kolumnę, której wartości będą wierszami. Przeciągnij ID dostawcy kolumnę do pola „Upuść pola wierszy tutaj”.
- Określ kolumnę, której wartości będą kolumnami. Przeciągnij Identyfikator pracownika kolumnę do pola „Upuść pola kolumn tutaj”. Możesz także ustawić filtr dla wymaganych pracowników (250, 251, 252, 253, 254).
- Określ kolumnę, której wartości będą danymi. Przeciągnij PurchaseOrderID kolumnę do pola „Upuść elementy danych tutaj”.
- We właściwościach PurchaseOrderID kolumna, określ typ agregacji – Liczba wartości .
Szybko uzyskaliśmy pożądany wynik.
Obracanie danych za pomocą SQL
Oczywiście transformację danych można przeprowadzić za pomocą bazy danych, pisząc zapytanie SQL. Ale jest mały problem, MySQL nie ma konkretnego oświadczenia, które pozwalałoby to zrobić.
Przykład oparty na T-SQL dla SQL Server
Na przykład SqlServer i Oracle mają operator PIVOT, który umożliwia taką transformację danych. Gdybyśmy pracowali z SqlServer, nasze zapytanie wyglądałoby tak.
SELECT ID dostawcy [250] AS Emp1 [251] AS Emp2 [252] AS Emp3 [253] AS Emp4 [254] AS Emp5FROM (SELECT ID zamówienia zakupu , ID pracownika , ID dostawcy FROM Purchasing.PurchaseOrderHeader) pPIVOT (COUNT) (PurchaseOrderID) FOR EmployeeID IN ([250], [251], [252], [253], [254])) AS TORDER BY t.VendorID;
Przykład dla MySQL
W MySQL będziemy musieli użyć środków SQL. Dane powinny być pogrupowane według kolumny dostawcy – VendorID , oraz dla każdego wymaganego pracownika (Identyfikator pracownika ), musisz utworzyć oddzielną kolumnę z funkcją agregującą.
W naszym przypadku musimy obliczyć liczbę zamówień, więc użyjemy funkcji agregującej COUNT.
W tabeli źródłowej informacje o wszystkich pracownikach są przechowywane w jednej kolumnie Identyfikator pracownika i musimy obliczyć liczbę zamówień dla konkretnego pracownika, więc musimy nauczyć naszą funkcję agregującą przetwarzania tylko niektórych wierszy.
Funkcja agregująca nie uwzględnia wartości NULL i używamy tej cechy do naszych celów.
Możesz użyć operatora warunkowego IF lub CASE, który zwróci określoną wartość dla żądanego pracownika, w przeciwnym razie po prostu zwróci NULL; w rezultacie funkcja COUNT zlicza tylko wartości inne niż NULL.
Wynikowe zapytanie jest następujące:
SELECT IDDostawcy, COUNT(IF(IdentyfikatorZakupu =250,IdZamówieniaZakupu,NULL)) AS Emp250, COUNT(IF(IdentyfikatorPracownika =251,IdentyfikatorZamówieniaZakupu,NULL)) AS Emp251, COUNT(IF(IdentyfikatorZamówienia =252,IdentyfikatorZamówieniaZakupu, NULL) ) AS Emp252, COUNT(IF(EmployeeID =253, PurchaseOrderID, NULL)) AS Emp253, COUNT(IF(EmployeeID =254, PurchaseOrderID, NULL)) AS Emp254FROM PurchaseOrderHeader pWHERE p. EmployeeID BETWEEN 250 A 254GROUP WEDŁUG ID dostawcy;>Lub nawet tak:
ID dostawcy, COUNT(IF(IdentyfikatorPracownika =250, 1, NULL)) AS Emp250, COUNT(IF(IdentyfikatorPracownika =251, 1, NULL)) AS Emp251, COUNT(IF(IdentyfikatorPracownika =252, 1, NULL)) AS Emp252, COUNT(IF(EmployeeID =253, 1, NULL)) AS Emp253, COUNT(IF(EmployeeID =254, 1, NULL)) AS Emp254FROM PurchaseOrderHeader pWHERE p. EmployeeID BETWEEN 250 A 254GROUP WEDŁUG ID dostawcy;Po wykonaniu uzyskuje się znajomy wynik.
Automatyzacja obrotu danych, dynamiczne tworzenie zapytań
Jak widać, zapytanie ma pewną spójność, tzn. wszystkie przekształcone kolumny powstają w podobny sposób, a żeby napisać zapytanie, trzeba znać konkretne wartości z tabeli. Aby utworzyć zapytanie przestawne, musisz przejrzeć wszystkie możliwe wartości i dopiero wtedy napisać zapytanie. Alternatywnie możesz przekazać to zadanie do serwera, powodując, że uzyska on te wartości i dynamicznie wykona rutynowe zadanie.
Wróćmy do pierwszego przykładu, w którym utworzyliśmy nową tabelę ProductsNew z Starych Produktów stół. Tam wartości właściwości są ograniczone i nie możemy nawet poznać wszystkich możliwych wartości; mamy tylko informacje o tym, gdzie przechowywane są nazwy właściwości i ich wartość. Oto Właściwość i Wartość odpowiednio kolumn.
Cały algorytm tworzenia zapytania SQL sprowadza się do uzyskania wartości, z których powstaną nowe kolumny i konkatenacje niezmiennych części zapytania.
SELECT GROUP_CONCAT(CONCAT(' MAX(IF(Property =''', t.Property, ''', Value, NULL)) AS ', t.Property ) ) INTO @PivotQueryFROM (SELECT właściwość FROM ProductOld GROUP BY Właściwość) t;SET @PivotQuery =CONCAT('SELECT IDProduktu', @PivotQuery, 'FROM ProductOld GROUP BY ProductID');Zmienna @PivotQuery będzie przechowywać nasze zapytanie, tekst został sformatowany dla przejrzystości.
SELECT IDProduktu, MAX(IF(Właściwość ='Kolor'; Wartość; NULL)) AS Kolor, MAX(IF(Właściwość ='Nazwa'; Wartość; NULL)) AS Nazwa, MAX(IF(Właściwość ='NumerProduktu) ', Wartość, NULL)) AS NumerProduktu, MAX(IF(Właściwość ='Rozmiar', Wartość, NULL)) AS Rozmiar, MAX(IF(Właściwość ='SizeUnitMeasureCode', Value, NULL)) AS RozmiarJednostkaMeasureCodeFROMProduktStaraGrupa BY ProductIDPo jego wykonaniu uzyskamy pożądany wynik odpowiadający schematowi tabeli ProductsNew.
Co więcej, zapytanie ze zmiennej @PivotQuery można wykonać w skrypcie za pomocą instrukcji MySQL EXECUTE.Oświadczenie PREPARE FROM @PivotQuery;Oświadczenie EXECUTE;Oświadczenie DEALLOCATE PREPARE;