如何在 PostgreSQL 中使用 VALUES 创建临时表

tin*_*lyx 54 postgresql syntax

我正在学习 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);
Run Code Online (Sandbox Code Playgroud)

但是 PostgreSQL (9.3) 抱怨

“AS”处或附近的语法错误

我的问题是:

  1. 我怎样才能修正上面的说法?

  2. 我如何调整它以用于WITH block?

提前致谢。

Joh*_*ell 68

编辑:我将保留原来接受的答案,但请注意,下面的编辑,如a_horse_with_no_name所建议的,是使用 VALUES 创建临时表的首选方法。

如果您只想从某些值中进行选择,而不仅仅是创建一个表并插入其中,您可以执行以下操作:

WITH  vals (k,v) AS (VALUES (0,-9999), (1, 100)) 
SELECT * FROM vals;
Run Code Online (Sandbox Code Playgroud)

要以类似的方式实际创建临时表,请使用:

WITH  vals (k,v) AS (VALUES (0,-9999), (1, 100)) 
SELECT * INTO temporary table temp_table FROM vals;
Run Code Online (Sandbox Code Playgroud)

编辑:正如 a_horse_with_no_name 所指出的,在文档中它指出它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;
Run Code Online (Sandbox Code Playgroud)

请注意,同样来自 a_horse_with_no_name 的评论,以及在 OP 的原始问题中,这包括对值列表中正确数据类型的强制转换,并使用 CTE (WITH) 语句。

此外,正如 Evan Carrol 的回答中所指出的,在 12 版之前的 Postgres 中,CTE 查询始终是优化栅栏,即 CTE 始终是物化的。使用 CTE 有很多很好的理由,但如果不小心使用,可能会对性能造成相当大的影响。然而,在很多情况下,优化栅栏实际上可以提高性能,所以这是需要注意的,而不是盲目地避免。

  • [来自文档](http://www.postgresql.org/docs/current/static/sql-selectinto.html):“*CREATE TABLE AS 在功能上类似于 SELECT INTO。CREATE TABLE AS 是推荐的语法*” (12认同)

a_h*_*ame 31

create table as 需要一个选择语句:

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);
Run Code Online (Sandbox Code Playgroud)

您还可以重新编写它以使用 CTE:

create temp table lookup 
as 
with t (key, value) as (
  values 
    (0::int,-99999::numeric), 
    (1::int,100::numeric)
)
select * from t;
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你的评论。由于文档中所述的原因,您的方法显然更好。我已经编辑了我的答案,尽管晚了将近 5 年。 (2认同)

ype*_*eᵀᴹ 15

问题是数据类型。如果您删除它们,该语句将起作用:

CREATE TEMP TABLE lookup
  (key, val) AS
VALUES 
  (0, -99999), 
  (1, 100) ;
Run Code Online (Sandbox Code Playgroud)

您可以通过转换第一行的值来定义类型:

CREATE TEMP TABLE lookup 
  (key, val) AS
VALUES 
  (0::bigint, -99999::int), 
  (1, 100) ;
Run Code Online (Sandbox Code Playgroud)


isa*_*pir 7

如果您只需要在查询中使用一些值,您就真的不需要创建表或使用 CTE。您可以内联它们:

SELECT  *
FROM    (VALUES(0::INT, -99999::NUMERIC), (1, 100)) AS lookup(key, val)
Run Code Online (Sandbox Code Playgroud)

然后你可以得到一个笛卡尔积CROSS JOIN(当然,其他关系可以是一个普通的表、视图等)。例如:

SELECT  *
FROM    (VALUES(0::int, -99999::numeric), (1, 100)) AS lookup(key, val)
       ,(VALUES('Red'), ('White'), ('Blue')) AS colors(color);
Run Code Online (Sandbox Code Playgroud)

产生:

key |val    |color |
----|-------|------|
0   |-99999 |Red   |
1   |100    |Red   |
0   |-99999 |White |
1   |100    |White |
0   |-99999 |Blue  |
1   |100    |Blue  |
Run Code Online (Sandbox Code Playgroud)

或者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;
Run Code Online (Sandbox Code Playgroud)

产生:

key |val    |color |lookup_key |
----|-------|------|-----------|
1   |100    |Red   |1          |
0   |-99999 |White |0          |
1   |100    |Blue  |1          |
Run Code Online (Sandbox Code Playgroud)