Jak po prostu zamienić kolumny z wierszami w języku SQL? Czy jest jakieś proste polecenie do transpozycji?
czyli włącz ten wynik:
Paul | John | Tim | Eric
Red 1 5 1 3
Green 8 4 3 5
Blue 2 2 9 1
zaangażowany w to:
Red | Green | Blue
Paul 1 8 2
John 5 4 2
Tim 1 3 9
Eric 3 5 1
PIVOT
wydaje się zbyt skomplikowany dla tego scenariusza.
sql
sql-server
tsql
pivot
edezzie
źródło
źródło
Odpowiedzi:
Dane te można przekształcić na kilka sposobów. W swoim oryginalnym poście stwierdziłeś, że
PIVOT
wydaje się to zbyt skomplikowane dla tego scenariusza, ale można go bardzo łatwo zastosować za pomocą funkcjiUNPIVOT
iPIVOT
w SQL Server.Jeśli jednak nie masz dostępu do tych funkcji, można to zreplikować za pomocą
UNION ALL
do,UNPIVOT
a następnie funkcji agregującej zCASE
instrukcją doPIVOT
:Utwórz tabelę:
Wersja Union All, Aggregate i CASE:
Zobacz SQL Fiddle with Demo
Do
UNION ALL
wykonujeUNPIVOT
danych poprzez przekształcenie kolumnyPaul, John, Tim, Eric
w osobnych wierszach. Następnie stosujesz funkcję agregującąsum()
zcase
instrukcją, aby uzyskać nowe kolumny dla każdej z nichcolor
.Wersja statyczna Unpivot i Pivot:
Zarówno
UNPIVOT
iPIVOT
funkcje w serwerze SQL dokonać tej przemiany jest znacznie łatwiejsze. Jeśli znasz wszystkie wartości, które chcesz przekształcić, możesz zakodować je na stałe do wersji statycznej, aby uzyskać wynik:Zobacz SQL Fiddle with Demo
Zapytanie wewnętrzne z
UNPIVOT
operatorem spełnia tę samą funkcję coUNION ALL
. Pobiera listę kolumn i zamienia ją na wiersze, aPIVOT
następnie wykonuje ostateczną transformację w kolumny.Wersja Dynamic Pivot:
Jeśli masz nieznaną liczbę kolumn (
Paul, John, Tim, Eric
w twoim przykładzie), a następnie nieznaną liczbę kolorów do przekształcenia, możesz użyć dynamicznego sql do wygenerowania listy,UNPIVOT
a następniePIVOT
:Zobacz SQL Fiddle with Demo
Wersja dynamiczna wysyła zapytanie zarówno
yourtable
dosys.columns
tabeli, jak i do tabeli, aby wygenerować listę elementów doUNPIVOT
iPIVOT
. To jest następnie dodawane do ciągu zapytania do wykonania. Zaletą wersji dynamicznej jest to, że masz listę zmiancolors
i / lubnames
spowoduje to wygenerowanie listy w czasie wykonywania.Wszystkie trzy zapytania dadzą ten sam wynik:
źródło
Zwykle wymaga to wcześniejszej znajomości WSZYSTKICH kolumn ORAZ etykiet wierszy. Jak widać w poniższym zapytaniu, wszystkie etykiety są wymienione w całości zarówno w operacjach UNPIVOT, jak i (re) PIVOT.
Konfiguracja schematu MS SQL Server 2012 :
Zapytanie 1 :
Wyniki :
Dodatkowe uwagi:
źródło
Chciałbym wskazać jeszcze kilka rozwiązań transpozycji kolumn i wierszy w SQL.
Pierwsza to - użycie CURSORA. Chociaż ogólna zgoda społeczności zawodowej polega na trzymaniu się z daleka od kursorów SQL Server, nadal istnieją przypadki, w których zalecane jest użycie kursorów. W każdym razie Cursors daje nam inną opcję transpozycji wierszy na kolumny.
Ekspansja pionowa
Podobnie jak PIVOT, kursor ma dynamiczną możliwość dołączania większej liczby wierszy, gdy zestaw danych rozszerza się, aby objąć więcej numerów zasad.
Ekspansja pozioma
W przeciwieństwie do PIVOT, kursor wyróżnia się w tym obszarze, ponieważ może rozszerzać się, aby objąć nowo dodany dokument, bez zmiany skryptu.
Zestawienie wydajności
Głównym ograniczeniem transpozycji wierszy do kolumn za pomocą CURSOR jest wada związana z ogólnym użyciem kursorów - wiąże się to ze znacznym kosztem wydajności. Dzieje się tak, ponieważ Cursor generuje oddzielne zapytanie dla każdej operacji FETCH NEXT.
Innym sposobem transpozycji wierszy do kolumn jest użycie XML.
Rozwiązanie XML do transpozycji wierszy na kolumny jest w zasadzie optymalną wersją PIVOT, ponieważ rozwiązuje dynamiczne ograniczenie kolumn.
Wersja XML skryptu rozwiązuje to ograniczenie, używając kombinacji ścieżki XML, dynamicznego języka T-SQL i niektórych wbudowanych funkcji (np. STUFF, QUOTENAME).
Ekspansja pionowa
Podobnie jak w przypadku PIVOT i Cursor, nowo dodane polityki można pobrać w wersji XML skryptu bez zmiany oryginalnego skryptu.
Ekspansja pozioma
W przeciwieństwie do PIVOT, nowo dodane dokumenty mogą być wyświetlane bez zmiany skryptu.
Zestawienie wydajności
Jeśli chodzi o IO, statystyki wersji XML skryptu są prawie podobne do PIVOT - jedyną różnicą jest to, że XML ma drugie skanowanie tabeli dtTranspose, ale tym razem z logicznego odczytu - pamięci podręcznej danych.
Więcej informacji na temat tych rozwiązań (w tym kilka rzeczywistych przykładów T-SQL) można znaleźć w tym artykule: https://www.sqlshack.com/multiple-options-to-transposing-rows-into-columns/
źródło
Na podstawie tego rozwiązania od bluefeet jest tutaj procedura składowana, która używa dynamicznego sql do generowania transponowanej tabeli. Wymaga, aby wszystkie pola były numeryczne z wyjątkiem transponowanej kolumny (kolumny, która będzie nagłówkiem w wynikowej tabeli):
Możesz to przetestować za pomocą tabeli dostarczonej z tym poleceniem:
źródło
Robię
UnPivot
pierwszy i przechowywania wyników wCTE
i pomocąCTE
wPivot
pracy.Próbny
źródło
Dodając do wspaniałej odpowiedzi @Paco Zarate powyżej, jeśli chcesz transponować tabelę, która ma wiele typów kolumn, dodaj to na końcu linii 39, aby transponowała tylko
int
kolumny:Oto pełne zapytanie, które jest zmieniane:
Aby znaleźć inne
system_type_id
, uruchom to:źródło
Lubię udostępniać kod, którego używam do transpozycji podzielonego tekstu na podstawie odpowiedzi + bluefeet. W tym podejściu zostałem zaimplementowany jako procedura w MS SQL 2005
Łączę to rozwiązanie z informacjami o tym, jak porządkować wiersze bez kolejności według ( SQLAuthority.com ) i funkcją podziału na MSDN ( social.msdn.microsoft.com )
Kiedy wykonujesz procedurę
uzyskasz następny wynik
źródło
W ten sposób przekonwertuj wszystkie dane z plików (kolumn) w tabeli na rekord (wiersz).
źródło
Udało mi się zastosować rozwiązanie Paco Zarate i działa pięknie. Musiałem dodać jedną linię („SET ANSI_WARNINGS ON”), ale może to być coś unikalnego w sposobie, w jaki go użyłem lub nazwałem. Wystąpił problem z moim użytkowaniem i mam nadzieję, że ktoś może mi w tym pomóc:
Rozwiązanie działa tylko z rzeczywistą tabelą SQL. Wypróbowałem to z tabelą tymczasową, a także tabelą w pamięci (zadeklarowaną), ale nie działa z nimi. Więc w moim kodzie wywołującym tworzę tabelę w mojej bazie danych SQL, a następnie wywołuję SQLTranspose. Znowu działa świetnie. Właśnie tego chcę. Oto mój problem:
Aby całe rozwiązanie było naprawdę dynamiczne, muszę utworzyć tabelę, w której tymczasowo przechowuję przygotowane informacje, które wysyłam do SQLTranspose „w locie”, a następnie usunąć tę tabelę po wywołaniu SQLTranspose. Usunięcie tabeli stanowi problem z moim ostatecznym planem wdrożenia. Kod musi być uruchamiany z aplikacji użytkownika końcowego (przycisk w formularzu / menu programu Microsoft Access). Kiedy używam tego procesu SQL (tworzenie tabeli SQL, wywołanie SQLTranspose, usuwanie tabeli SQL), aplikacja użytkownika końcowego napotyka błąd, ponieważ używane konto SQL nie ma uprawnień do usuwania tabeli.
Więc myślę, że jest kilka możliwych rozwiązań:
Znajdź sposób, aby SQLTranspose działał z tabelą tymczasową lub zadeklarowaną zmienną tabeli.
Wymyśl inną metodę transpozycji wierszy i kolumn, która nie wymaga rzeczywistej tabeli SQL.
Wymyśl odpowiednią metodę zezwalania kontu SQL używanemu przez moich użytkowników końcowych na upuszczenie tabeli. To pojedyncze współdzielone konto SQL zakodowane w mojej aplikacji Access. Wygląda na to, że uprawnienie jest uprawnieniem typu dbo, którego nie można nadać.
Zdaję sobie sprawę, że niektóre z tego mogą uzasadniać inny, oddzielny wątek i pytanie. Jednakże, ponieważ istnieje możliwość, że jednym rozwiązaniem może być po prostu inny sposób na transpozycję wierszy i kolumn, zrobię mój pierwszy post tutaj w tym wątku.
EDYCJA: Zamieniłem również sumę (wartość) na max (wartość) w szóstej linii od końca, jak zasugerował Paco.
EDYTOWAĆ:
Wymyśliłem coś, co mi pasuje. Nie wiem, czy to najlepsza odpowiedź, czy nie.
Mam konto użytkownika tylko do odczytu, które jest używane do wykonywania procedur strored, a tym samym generowania danych wyjściowych raportu z bazy danych. Ponieważ utworzona przeze mnie funkcja SQLTranspose będzie działać tylko z "legalną" tabelą (nie z zadeklarowaną tabelą ani z tabelą tymczasową) Musiałem znaleźć sposób na utworzenie (a następnie późniejsze usunięcie) konta użytkownika tylko do odczytu .
Doszedłem do wniosku, że dla moich celów jest w porządku, aby konto użytkownika mogło utworzyć tabelę. Jednak użytkownik nadal nie mógł usunąć tabeli. Moim rozwiązaniem było stworzenie schematu, w którym konto użytkownika jest autoryzowane. Następnie za każdym razem, gdy tworzę, używam lub usuwam tę tabelę, odwołuję się do niej z określonym schematem.
Najpierw wydałem to polecenie z konta „sa” lub „sysadmin”: TWORZENIE SCHEMATU ro AUTORYZACJA
Kiedy kiedykolwiek odwołuję się do mojej tabeli „tmpoutput”, określam ją w następujący sposób:
drop table ro.tmpoutput
źródło