Z samodzielnym VALUES
wyrażenie PostgreSQL nie ma pojęcia, jakie powinny być typy danych. Dzięki prostym literałom liczbowym system chętnie przyjmuje pasujące typy. Ale z innymi danymi wejściowymi (np. NULL
) musiałbyś rzucać jawnie - jak już się dowiedziałeś.
Możesz zapytać pg_catalog
(szybki, ale specyficzny dla PostgreSQL) lub information_schema
(powolny, ale standardowy SQL), aby znaleźć i przygotować zestawienie z odpowiednimi typami.
Możesz też użyć jednej z tych prostych „sztuczek” (najlepsze zapisałem na ostatni ):
0. Wybierz wiersz z LIMIT 0
, dołącz wiersze z UNION ALL VALUES
UPDATE foo f
SET x = t.x
, y = t.y
FROM (
(SELECT pkid, x, y FROM foo LIMIT 0) -- parenthesis needed with LIMIT
UNION ALL
VALUES
(1, 20, NULL) -- no type casts here
, (2, 50, NULL)
) t -- column names and types are already defined
WHERE f.pkid = t.pkid;
Pierwszy wybór podrzędny podzapytania:
(SELECT x, y, pkid FROM foo LIMIT 0)
pobiera nazwy i typy dla kolumn, ale LIMIT 0
zapobiega dodaniu rzeczywistego wiersza. Kolejne wiersze są przypisywane do dobrze zdefiniowanego typu wiersza - i natychmiast sprawdzane, czy pasują do typu. Powinno to być subtelne dodatkowe ulepszenie w stosunku do oryginalnego formularza.
Podczas podawania wartości dla wszystkich kolumny tabeli ta krótka składnia może być użyta w pierwszym wierszu:
(TABLE foo LIMIT 0)
Główne ograniczenie :Postgres rzutuje literały wejściowe niezależnych VALUES
wyrażenie do typu "najlepszego wysiłku" natychmiast. Kiedy później spróbuje rzutować na podane typy pierwszego SELECT
, może być już za późno dla niektórych typów, jeśli nie ma zarejestrowanego rzutowania przypisania między typem zakładanym a typem docelowym. Przykłady:text
-> timestamp
lub text
-> json
.
Pro:
- Minimalne obciążenie.
- Czytelny, prosty i szybki.
- Musisz tylko znać odpowiednie nazwy kolumn tabeli.
Wada:
- Rozdzielczość typów może się nie powieść w przypadku niektórych typów.
1. Wybierz wiersz z LIMIT 0
, dołącz wiersze za pomocą UNION ALL SELECT
UPDATE foo f
SET x = t.x
, y = t.y
FROM (
(SELECT pkid, x, y FROM foo LIMIT 0) -- parenthesis needed with LIMIT
UNION ALL SELECT 1, 20, NULL
UNION ALL SELECT 2, 50, NULL
) t -- column names and types are already defined
WHERE f.pkid = t.pkid;
Pro:
- Jak 0. , ale pozwala uniknąć błędów w rozwiązywaniu typów.
Wada:
UNION ALL SELECT
jest wolniejszy niżVALUES
wyrażenie dla długich list wierszy, jakie znalazłeś w teście.- Pełna składnia na wiersz.
2. VALUES
wyrażenie z typem na kolumnę
...
FROM (
VALUES
((SELECT pkid FROM foo LIMIT 0)
, (SELECT x FROM foo LIMIT 0)
, (SELECT y FROM foo LIMIT 0)) -- get type for each col individually
, (1, 20, NULL)
, (2, 50, NULL)
) t (pkid, x, y) -- columns names not defined yet, only types.
...
W przeciwieństwie do 0. pozwala to uniknąć przedwczesnego rozwiązywania typów.
Pierwszy wiersz w VALUES
wyrażenie jest wierszem NULL
wartości, które określają typ dla wszystkich kolejnych wierszy. Ten wiodący wiersz szumu jest filtrowany przez WHERE f.pkid = t.pkid
później, więc nigdy nie ujrzy światła dziennego. W innych celach możesz wyeliminować dodany pierwszy wiersz za pomocą OFFSET 1
w podzapytaniu.
Pro:
- Zazwyczaj szybciej niż 1. (lub nawet 0. )
- Krótka składnia tabel z wieloma kolumnami i tylko kilka ma znaczenie.
- Musisz tylko znać odpowiednie nazwy kolumn tabeli.
Wada:
- Pełna składnia tylko dla kilku wierszy
- Mniej czytelny (IMO).
3. VALUES
wyrażenie z typem wiersza
UPDATE foo f
SET x = (t.r).x -- parenthesis needed to make syntax unambiguous
, y = (t.r).y
FROM (
VALUES
('(1,20,)'::foo) -- columns need to be in default order of table
,('(2,50,)') -- nothing after the last comma for NULL
) t (r) -- column name for row type
WHERE f.pkid = (t.r).pkid;
Oczywiście znasz nazwę stołu. Jeśli znasz również liczbę kolumn i ich kolejność, możesz z tym pracować.
Dla każdej tabeli w PostgreSQL typ wiersza jest rejestrowany automatycznie. Jeśli dopasujesz liczbę kolumn w wyrażeniu, możesz rzutować na typ wiersza tabeli ('(1,50,)'::foo
), przypisując w ten sposób typy kolumn niejawnie. Nie umieszczaj nic za przecinkiem, aby wpisać NULL
wartość. Dodaj przecinek dla każdej nieistotnej końcowej kolumny.
W następnym kroku możesz uzyskać dostęp do poszczególnych kolumn z zademonstrowaną składnią. Więcej informacji o wybieraniu pól w instrukcji.
Możesz też dodać wiersz wartości NULL i użyj jednolitej składni dla rzeczywistych danych:
...
VALUES
((NULL::foo)) -- row of NULL values
, ('(1,20,)') -- uniform ROW value syntax for all
, ('(2,50,)')
...
Pro:
- Najszybszy (przynajmniej w moich testach z kilkoma wierszami i kolumnami).
- Najkrótsza składnia dla kilku wierszy lub tabel, w których potrzebne są wszystkie kolumny.
- Nie musisz przeliterować kolumn tabeli – wszystkie kolumny automatycznie mają pasującą nazwę.
Wada:
- Niezbyt dobrze znana składnia do wyboru pola z rekordu/wiersza/typu złożonego.
- Musisz znać liczbę i położenie odpowiednich kolumn w domyślnej kolejności.
4. VALUES
wyrażenie z rozłożonym typ wiersza
Jak 3. , ale z rozłożonymi wierszami w standardowej składni:
UPDATE foo f
SET x = t.x
, y = t.y
FROM (
VALUES
(('(1,20,)'::foo).*) -- decomposed row of values
, (2, 50, NULL)
) t(pkid, x, y) -- arbitrary column names (I made them match)
WHERE f.pkid = t.pkid; -- eliminates 1st row with NULL values
Lub ponownie z wiodącym wierszem wartości NULL:
...
VALUES
((NULL::foo).*) -- row of NULL values
, (1, 20, NULL) -- uniform syntax for all
, (2, 50, NULL)
...
Wady i zalety jak 3. , ale z bardziej znaną składnią.
I musisz przeliterować nazwy kolumn (jeśli ich potrzebujesz).
5. VALUES
wyrażenie z typami pobranymi z typu wiersza
Jak skomentował Unril, możemy połączyć zalety 2. i 4. podać tylko podzbiór kolumn:
UPDATE foo f
SET ( x, y)
= (t.x, t.y) -- short notation, see below
FROM (
VALUES
((NULL::foo).pkid, (NULL::foo).x, (NULL::foo).y) -- subset of columns
, (1, 20, NULL)
, (2, 50, NULL)
) t(pkid, x, y) -- arbitrary column names (I made them match)
WHERE f.pkid = t.pkid;
Wady i zalety jak 4. , ale możemy pracować z dowolnym podzbiorem kolumn i nie musimy znać pełnej listy.
Wyświetlam również krótką składnię UPDATE
samo w sobie jest wygodne w przypadku przypadków z wieloma kolumnami. Powiązane:
- Zbiorcza aktualizacja wszystkich kolumn
4. i 5. są moimi ulubionymi.
db<>graj tutaj - demonstrowanie wszystkich