Se samostatným VALUES
výraz PostgreSQL nemá ponětí, jaké by měly být datové typy. S jednoduchými číselnými literály systém rád předpokládá odpovídající typy. Ale s jiným vstupem (jako NULL
) budete muset vrhnout explicitně - jak jste již zjistili.
Můžete se zeptat na pg_catalog
(rychlé, ale specifické pro PostgreSQL) nebo information_schema
(pomalé, ale standardní SQL), abyste zjistili a připravili svůj příkaz s vhodnými typy.
Nebo můžete použít jeden z těchto jednoduchých „triků“ (to nejlepší jsem si nechal naposled ):
0. Vyberte řádek s LIMIT 0
, připojte k řádkům řetězec 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;
První dílčí výběr poddotazu:
(SELECT x, y, pkid FROM foo LIMIT 0)
získá názvy a typy sloupců, ale LIMIT 0
zabrání přidání skutečného řádku. Následující řádky jsou vynuceny na nyní dobře definovaný typ řádku - a okamžitě kontrolovány, zda odpovídají typu. Mělo by jít o další jemné vylepšení oproti původní podobě.
Při zadávání hodnot pro vše sloupce tabulky tuto krátkou syntaxi lze použít pro první řádek:
(TABLE foo LIMIT 0)
Hlavní omezení :Postgres přenáší vstupní literály volně stojícího VALUES
výraz okamžitě na typ "nejlepší úsilí". Když se později pokusí přetypovat na dané typy prvního SELECT
, může být pro některé typy již příliš pozdě, pokud mezi předpokládaným typem a cílovým typem není žádné registrované přiřazení. Příklady:text
-> timestamp
nebo text
-> json
.
Pro:
- Minimální režie.
- Čtivé, jednoduché a rychlé.
- Potřebujete znát pouze relevantní názvy sloupců tabulky.
Con:
- U některých typů může rozlišení typu selhat.
1. Vyberte řádek s LIMIT 0
, připojte řádky 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:
- Jako 0. , ale zabrání selhání rozlišení typu.
Con:
UNION ALL SELECT
je pomalejší nežVALUES
výraz pro dlouhé seznamy řádků, jak jste našli ve svém testu.- Podrobná syntaxe na řádek.
2. VALUES
výraz s typem na sloupec
...
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.
...
Na rozdíl od 0. tím se zabrání předčasnému rozlišení typu.
První řádek v VALUES
výraz je řádek NULL
hodnoty, které definují typ pro všechny následující řádky. Tento úvodní řádek šumu je filtrován podle WHERE f.pkid = t.pkid
později, takže nikdy nespatří světlo světa. Pro jiné účely můžete odstranit přidaný první řádek pomocí OFFSET 1
v dílčím dotazu.
Pro:
- Obvykle rychlejší než 1. (nebo dokonce 0. )
- Krátká syntaxe pro tabulky s mnoha sloupci, z nichž je relevantních pouze několik.
- Potřebujete znát pouze relevantní názvy sloupců tabulky.
Con:
- Úplná syntaxe pouze pro několik řádků
- Méně čitelné (IMO).
3. VALUES
výraz s typem řádku
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;
Jméno stolu evidentně znáte. Pokud znáte také počet sloupců a jejich pořadí, můžete s tím pracovat.
Pro každou tabulku v PostgreSQL je automaticky registrován typ řádku. Pokud odpovídáte počtu sloupců ve výrazu, můžete přetypovat na typ řádku tabulky ('(1,50,)'::foo
), čímž se implicitně přiřadí typy sloupců. Chcete-li zadat NULL
, za čárku nedávejte nic hodnota. Přidejte čárku pro každý irelevantní koncový sloupec.
V dalším kroku můžete přistupovat k jednotlivým sloupcům s demonstrovanou syntaxí. Další informace o Výběru polí v návodu.
Nebo můžete přidat řádek hodnot NULL a pro skutečná data použijte jednotnou syntaxi:
...
VALUES
((NULL::foo)) -- row of NULL values
, ('(1,20,)') -- uniform ROW value syntax for all
, ('(2,50,)')
...
Pro:
- Nejrychlejší (alespoň v mých testech s několika řádky a sloupci).
- Nejkratší syntaxe pro několik řádků nebo tabulek, kde potřebujete všechny sloupce.
- Sloupce tabulky nemusíte hláskovat – všechny sloupce mají automaticky odpovídající název.
Con:
- Ne příliš známá syntaxe pro výběr polí ze záznamu / řádku / složeného typu.
- Musíte znát počet a pozici příslušných sloupců ve výchozím pořadí.
4. VALUES
výraz s rozloženým typ řádku
Jako 3. , ale s rozloženými řádky ve standardní syntaxi:
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
Nebo opět s úvodní řadou hodnot NULL:
...
VALUES
((NULL::foo).*) -- row of NULL values
, (1, 20, NULL) -- uniform syntax for all
, (2, 50, NULL)
...
Pro a proti jako 3. , ale s běžněji známou syntaxí.
A musíte vyhláskovat názvy sloupců (pokud je potřebujete).
5. VALUES
výraz s typy načtenými z typu řádku
Jak uvedl Unril, můžeme kombinovat přednosti 2. a 4. poskytnout pouze podmnožinu sloupců:
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;
Pro a proti jako 4. , ale můžeme pracovat s jakoukoli podmnožinou sloupců a nemusíme znát úplný seznam.
Také se zobrazuje krátká syntaxe pro UPDATE
to je vhodné pro případy s mnoha sloupci. Související:
- Hromadná aktualizace všech sloupců
4. a 5. jsou mé oblíbené.
db<>zde hrajte - předvedení všech