PostgreSQL에서 VALUES를 사용하여 임시 테이블을 생성하는 방법


38

PostgreSQL을 배우고 WITH디버깅을 위해 임시 테이블 또는 일반 테이블 대신 사용할 수 있는 선언 을 만드는 방법을 알아 내려고 노력 중 입니다.

나는 설명서 보았다 표를 작성 하고 그것을 말한다 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"근처 또는 근처의 구문 오류

내 질문은 :

  1. 위의 진술을 어떻게 고칠 수 있습니까?

  2. 에 사용되도록 어떻게 조정할 수 WITH block있습니까?

미리 감사드립니다.


선택한 답변이 더 이상 사용되지 않는 비표준 구문을 사용하므로 더 현대적인 조언 으로이 질문에 대답하려고했습니다 dba.stackexchange.com/a/201575/2639
Evan Carroll

답변:


46

편집 : 원래 허용 된 답변을 그대로두고 있지만 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;

편집 : 로는에, 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;

또한 a_horse_with_no_name의 의견과 OP의 원래 질문에서 값 목록 내의 올바른 데이터 유형으로의 캐스트가 포함되며 CTE (WITH) 문을 사용합니다.

또한 Evan Carrol의 답변에서 지적했듯이 CTE 쿼리는 최적화 펜스입니다 . 즉, CTE는 항상 구체화됩니다. CTE를 사용하는 데는 여러 가지 이유가 있지만주의해서 사용하지 않으면 성능이 크게 저하 될 수 있습니다. 그러나 최적화 펜스가 실제로 성능을 향상시킬 수있는 경우가 많기 때문에 맹목적으로 피할 수는 없습니다.


12
문서에서 : " CREATE TABLE AS는 기능적으로 SELECT INTO와 유사합니다. CREATE TABLE AS는 권장되는 구문입니다. "
a_horse_with_no_name

최적화 펜스가 반드시 나쁜 것은 아닙니다. 나는 그 때문에 엄청나게 빨리 달릴 수있는 많은 말을 보았습니다.
a_horse_with_no_name

물론, 나는 그것을 명확히했다. 나는 항상 공간적 맥락에서 CTE를 사용한다. geose 열이 더 이상 sargable이 아니기 때문에 where WHERE ST_Intersects(geom, (SELECT geom FROM sometable)또는 where가있는 where 절이있는 WHERE ST_Intersects(geom, ST_Buffer(anothergeom, 10)경우 쿼리 플래너는 공간 인덱스를 사용하지 않습니다. 초기 CTE에 관심 영역을 만들면이 문제는 사라집니다. 동일한 쿼리에서 여러 추가 표현식에 동일한 aoi를 사용하려는 경우에도 매우 편리합니다. 이는 GIS 컨텍스트에서 일반적이지 않습니다.
존 파월

25

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;

1
의견 주셔서 감사합니다. 문서에 명시된 이유로 접근 방식이 더 좋습니다. 거의 5 년 늦었지만 답변을 편집했습니다.
존 파월

11

문제는 데이터 유형입니다. 그것들을 제거하면 진술이 작동합니다.

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) ;

3

쿼리에 몇 가지 값을 사용하는 것만으로도 테이블을 만들거나 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          |

문제는 "...로 임시 테이블을 만드는 방법"
ypercubeᵀᴹ

예, 그러나 다른 관계에서 조인하지 않는 경우 고정 된 조회 값이 몇 개인 임시 테이블이 필요한 이유는 무엇입니까? 이 솔루션은 질문의 표현 방식에 관계없이 문제 자체를 해결합니다.
isapir

1
아마도 OP는 예를 질문으로 게시하기 쉬운 것으로 요약했지만 실제 데이터에는 수천 개의 값이 있습니까?
stannius

OP는 구체적으로 값을 사용하여 명시 했으므로 내 대답은 그대로 그대로 적용됩니다
isapir

2

먼저 항상 표준화 사용 CREATE TABLE AS, SELECT INTO10 년 이상 사용되지 않는 구문되었습니다 다른 답변에 제안. 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는 materialization을 강제합니다. 최적화 펜스입니다. 따라서 비용을 이해하고 성능 향상을 제공 할 수있는 경우를 제외하고는 어느 곳에서나 사용하는 것이 일반적으로 좋지 않습니다. 예를 들어 여기에서 느려진 것을 볼 수 있습니다.

\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

표준을 반영하기 위해 답변을 업데이트했으며 허용 된 답변이 CREATE TABLE AS와 항상 동등한 것은 아니며 최적화 펜스에 대한 의견을 추가했습니다. 이는 매우 좋은 시점입니다. CTE는 많은 이점을 제공하지만, 맹목적으로 사용하면 끔찍한 성능으로 이어질 수 있습니다.
존 파월

-2
WITH u AS (
    SELECT * FROM (VALUES (1, 'one'), (2, 'two'), (3, 'three')) AS account (id,name)
)
SELECT id, name, length(name) from u;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.