Biorąc pod uwagę dwie tabele z nieokreśloną liczbą wierszy z nazwą i wartością, w jaki sposób wyświetlać funkcję obrotową CROSS JOIN
funkcji nad ich wartościami.
CREATE TEMP TABLE foo AS
SELECT x::text AS name, x::int
FROM generate_series(1,10) AS t(x);
CREATE TEMP TABLE bar AS
SELECT x::text AS name, x::int
FROM generate_series(1,5) AS t(x);
Na przykład, jeśli tą funkcją byłoby mnożenie, jak wygenerowałbym tabelę (mnożenie) taką jak ta poniżej,
Wszystkie te (arg1,arg2,result)
wiersze można wygenerować za pomocą
SELECT foo.name AS arg1, bar.name AS arg2, foo.x*bar.x AS result
FROM foo
CROSS JOIN bar;
Więc to jest tylko kwestia prezentacji, chciałbym, aby to również działało z niestandardową nazwą - nazwą, która nie jest po prostu argumentem CAST
edytowanym w tekście, ale ustawionym w tabeli,
CREATE TEMP TABLE foo AS
SELECT chr(x+64) AS name, x::int
FROM generate_series(1,10) AS t(x);
CREATE TEMP TABLE bar AS
SELECT chr(x+72) AS name, x::int
FROM generate_series(1,5) AS t(x);
Myślę, że byłoby to łatwe do wykonania dzięki CROSSTAB zdolnemu do dynamicznego typu powrotu.
SELECT * FROM crosstab(
'
SELECT foo.x AS arg1, bar.x AS arg2, foo.x*bar.x
FROM foo
CROSS JOIN bar
', 'SELECT DISTINCT name FROM bar'
) AS **MAGIC**
Ale bez tego **MAGIC**
rozumiem
ERROR: a column definition list is required for functions returning "record" LINE 1: SELECT * FROM crosstab(
Dla porównania, używając powyższych przykładów z nazwami, jest to coś więcej niż to tablefunc
, czego crosstab()
chce.
SELECT * FROM crosstab(
'
SELECT foo.x AS arg1, bar.x AS arg2, foo.x*bar.x
FROM foo
CROSS JOIN bar
'
) AS t(row int, i int, j int, k int, l int, m int);
Ale teraz wróciliśmy do przyjmowania założeń dotyczących zawartości i wielkości bar
tabeli w naszym przykładzie. Więc jeśli,
- Tabele mają nieokreśloną długość,
- Następnie połączenie krzyżowe reprezentuje sześcian o nieokreślonym wymiarze (z powodu powyższego),
- Nazwy kategorii (język tabulatora) znajdują się w tabeli
Co możemy zrobić w PostgreSQL bez „listy definicji kolumn”, aby wygenerować tego rodzaju prezentację?
źródło
Odpowiedzi:
Prosta sprawa, statyczny SQL
Non-dynamiczne rozwiązanie z
crosstab()
tej prostej sprawy:Kolejne kolumny uporządkuję według
foo.name
, a niefoo.x
. Oba są sortowane równolegle, ale to tylko prosta konfiguracja. Wybierz odpowiednią kolejność sortowania dla swojej skrzynki. Rzeczywista wartość drugiej kolumny nie ma znaczenia w tym zapytaniu (forma 1-parametrowacrosstab()
).Nie potrzebujemy nawet
crosstab()
z 2 parametrami, ponieważ z definicji nie brakuje brakujących wartości. Widzieć:(Naprawiono zapytanie w tabeli przestawnej w pytaniu, zastępując
foo
jebar
w późniejszej edycji. To także naprawia zapytanie, ale nadal działa z nazwami odfoo
.)Nieznany typ zwrotu, dynamiczny SQL
Nazwy i typy kolumn nie mogą być dynamiczne. SQL wymaga znajomości liczby, nazw i typów wynikowych kolumn w czasie połączenia. Albo przez wyraźne oświadczenie, albo z informacji w katalogach systemowych (tak się dzieje
SELECT * FROM tbl
: Postgres sprawdza zarejestrowaną definicję tabeli).Chcesz, aby Postgres wyprowadzał wynikowe kolumny z danych w tabeli użytkowników. Nie zdarzy się.
Tak czy inaczej, potrzebujesz dwóch podróży w obie strony na serwer. Utwórz kursor, a następnie przejdź przez niego. Lub utworzysz tabelę tymczasową, a następnie wybierzesz z niej. Lub zarejestruj typ i użyj go w połączeniu.
Lub po prostu wygeneruj zapytanie w jednym kroku i wykonaj je w następnym:
To generuje powyższe zapytanie, dynamicznie. Wykonaj to w następnym kroku.
Korzystam z notowań dolarowych (
$$
), aby uprościć obsługę zagnieżdżonych cytatów. Widzieć:quote_ident()
jest niezbędny, aby uciec w przeciwnym razie niedozwolonym nazwom kolumn (i ewentualnie obronić się przed wstrzyknięciem SQL).Związane z:
źródło
Jeśli ujmujesz to jako problem z prezentacją, możesz rozważyć funkcję prezentacji po zapytaniu.
psql
Pochodzą nowsze wersje (9.6)\crosstabview
, pokazujące wynik w postaci tabeli przestawnej bez wsparcia SQL (ponieważ SQL nie może tego wygenerować bezpośrednio, jak wspomniano w odpowiedzi @ Erwin: SQL wymaga znajomości liczby, nazw i typów wynikowych kolumn w czasie połączenia )Na przykład pierwsze zapytanie daje:
Drugi przykład z nazwami kolumn ASCII podaje:
Więcej informacji można znaleźć w instrukcji psql i https://wiki.postgresql.org/wiki/Crosstabview .
źródło
To nie jest ostateczne rozwiązanie
To jest moje najlepsze podejście do tej pory. Nadal trzeba przekonwertować końcową tablicę na kolumny.
Najpierw mam kartezjański produkt z obu stołów:
Ale dodałem numer wiersza tylko w celu zidentyfikowania każdego wiersza pierwszej tabeli.
Następnie kupiłem wynik w tym formacie:
Konwertowanie go na ciąg rozdzielany przecinkami:
(Wypróbuj później: http://rextester.com/NBCYXA2183 )
źródło
Na marginesie, wydaje się, że SQL: 2016 uwzględni to dzięki funkcjom tabeli polimorficznej (ISO / IEC TR 19075-7: 2017)
Znalazłem link Co nowego w SQL: 2016, ale autor nie rozwija się tak bardzo.
źródło