私はPostgreSQLを学び、デバッグのために、通常のテーブルの代わりに使用できる一時テーブルまたはWITH
宣言を作成する方法を理解しようとしています。
CREATE TABLE のドキュメントを調べたところ、VALUES
はクエリとして使用できますが、例はありません。そこにリンクされているVALUES
句のドキュメントにも例はありませんか?
そこで、次のように簡単なテストを作成しました。
DROP TABLE IF EXISTS lookup;
CREATE TEMP TABLE lookup (
key integer,
val numeric
) AS
VALUES (0,-99999), (1,100);
しかしPostgreSQL(9.3)は不満を言っています
「AS」またはその近くの構文エラー
私の質問は:
上記のステートメントをどのように修正できますか?
WITH block
での使用にどのように適応できますか?
前もって感謝します。
EDIT:元の承認された回答をそのままにしますが、a_horse_with_no_nameで提案されている以下の編集は、作成に推奨される方法です。 VALUESを使用する一時テーブル。
単にテーブルを作成してそれに挿入するのではなく、いくつかの値から選択するだけの場合は、次のようにすることができます。
_WITH vals (k,v) AS (VALUES (0,-9999), (1, 100))
SELECT * FROM vals;
_
同様の方法で一時テーブルを実際に作成するには、以下を使用します。
_WITH vals (k,v) AS (VALUES (0,-9999), (1, 100))
SELECT * INTO temporary table temp_table FROM vals;
_
EDIT:a_horse_with_no_nameで指摘されているように、 the docs で_CREATE TABLE AS...
_は_SELECT INTO ...
_、ただし前者は後者のスーパーセットであり、_SELECT INTO
_は一時変数に値を割り当てるためにplpgslqで使用されるため、その場合は失敗します。したがって、上記の例はプレーンSQLに有効ですが、_CREATE TABLE
_形式が推奨されます。
_CREATE TEMP TABLE temp_table AS
WITH t (k, v) AS (
VALUES
(0::int,-99999::numeric),
(1::int,100::numeric)
)
SELECT * FROM t;
_
また、a_horse_with_no_nameによるコメントから、およびOPの元の質問では、値リスト内の正しいデータ型へのキャストが含まれ、CTE(WITH)ステートメントが使用されています。
また、Evan Carrolの回答で指摘されているように、CTEクエリは最適化フェンスです。つまり、CTEは常に具体化されます。 CTEを使用することには多くの理由がありますが、慎重に使用しないと、パフォーマンスに大きな影響を与える可能性があります。ただし、最適化フェンスが実際にパフォーマンスを向上させることができる多くのインスタンスがあるため、これは盲目的に回避するのではなく、認識しておくべきことです。
create table as
にはselectステートメントが必要です:
DROP TABLE IF EXISTS lookup;
CREATE TEMP TABLE lookup
as
select *
from (
VALUES
(0::int,-99999::numeric),
(1::int, 100::numeric)
) as t (key, value);
CTEを使用するようにこれを書き換えることもできます。
create temp table lookup
as
with t (key, value) as (
values
(0::int,-99999::numeric),
(1::int,100::numeric)
)
select * from t;
問題はデータ型です。それらを削除すると、ステートメントは機能します。
CREATE TEMP TABLE lookup
(key, val) AS
VALUES
(0, -99999),
(1, 100) ;
最初の行の値をキャストすることでタイプを定義できます。
CREATE TEMP TABLE lookup
(key, val) AS
VALUES
(0::bigint, -99999::int),
(1, 100) ;
クエリでいくつかの値を使用するだけの場合は、テーブルを作成したり、CTEを使用したりする必要はありません。あなたはそれらをインライン化することができます:
SELECT *
FROM (VALUES(0::INT, -99999::NUMERIC), (1, 100)) AS lookup(key, val)
次に、CROSS JOIN
を使用してデカルト積を取得できます(もちろん、他の関係は通常のテーブルやビューなどでもかまいません)。例えば。:
SELECT *
FROM (VALUES(0::int, -99999::numeric), (1, 100)) AS lookup(key, val)
,(VALUES('Red'), ('White'), ('Blue')) AS colors(color);
これにより、
key |val |color |
----|-------|------|
0 |-99999 |Red |
1 |100 |Red |
0 |-99999 |White |
1 |100 |White |
0 |-99999 |Blue |
1 |100 |Blue |
またはJOIN
別の関係を持つ値(これも通常のテーブル、ビューなどにすることができます)。例:
SELECT *
FROM (VALUES(0::int, -99999::numeric), (1, 100)) AS lookup(key, val)
JOIN (VALUES('Red', 1), ('White', 0), ('Blue', 1)) AS colors(color, lookup_key)
ON colors.lookup_key = lookup.key;
これにより、
key |val |color |lookup_key |
----|-------|------|-----------|
1 |100 |Red |1 |
0 |-99999 |White |0 |
1 |100 |Blue |1 |
最初に常に標準化されたCREATE TABLE AS
、SELECT INTO
を使用してください。他の回答で提案されているように、10年以上にわたって非推奨の構文でした。 CTEで CREATE TABLE AS
を使用できます
ここでの多くの回答はCTEの使用を示唆していますが、それは好ましくありません。実際、それはおそらく多少遅くなります。表としてまとめるだけです。
DROP TABLE IF EXISTS lookup;
CREATE TEMP TABLE lookup(key, value) AS
VALUES
(0::int,-99999::numeric),
(1,100);
selectステートメントを記述する必要がある場合は、それも可能です(CTEは必要ありません)。
CREATE TEMP TABLE lookup(key, value) AS
SELECT key::int, value::numeric
FROM ( VALUES
(0::int,-99999::numeric),
(1,100)
) AS t(key, value);
PostgreSQLのCTEは強制的に実体化します。それは最適化フェンスです。そのため、コストを理解し、パフォーマンスを向上させるためにそれを知っている場合を除いて、どこでもそれらを使用することは一般的にはお勧めできません。たとえば、ここでスローダウンを確認できます
\timing
CREATE TABLE foo AS
SELECT * FROM generate_series(1,1e7);
Time: 5699.070 ms
CREATE TABLE foo AS
WITH t AS ( SELECT * FROM generate_series(1,1e7) )
SELECT * FROM t;
Time: 6484.516 ms