Cách tạo bảng tạm thời bằng GIÁ TRỊ trong PostgreSQL


38

Tôi đang tìm hiểu PostgreSQL và cố gắng tìm ra cách tạo bảng tạm thời hoặc WITHkhai báo có thể được sử dụng thay cho bảng thông thường, cho mục đích gỡ lỗi.

Tôi đã xem tài liệu cho CREATE TABLE và nó nói VALUEScó thể được sử dụng như một truy vấn nhưng không đưa ra ví dụ nào; tài liệu cho VALUESmệnh đề được liên kết trong đó cũng không có ví dụ?

Vì vậy, tôi đã viết một bài kiểm tra đơn giản như sau:

DROP TABLE IF EXISTS lookup;
CREATE TEMP TABLE lookup (
  key integer,
  val numeric
) AS
VALUES (0,-99999), (1,100);

Nhưng PostgreSQL (9.3) đang phàn nàn về

lỗi cú pháp tại hoặc gần "AS"

Câu hỏi của tôi là:

  1. Làm thế nào tôi có thể sửa các tuyên bố trên?

  2. Làm thế nào tôi có thể thích ứng nó để được sử dụng trong một WITH block?

Cảm ơn trước.


Tôi đã cố gắng trả lời câu hỏi này bằng một số lời khuyên hiện đại hơn (vì câu trả lời được chọn là sử dụng cú pháp không được chuẩn hóa) dba.stackexchange.com/a/201575/2639
Evan Carroll

Câu trả lời:


46

EDIT: Tôi đang để lại câu trả lời được chấp nhận ban đầu, nhưng xin lưu ý rằng chỉnh sửa bên dưới, như được đề xuất bởi a_horse_with_no_name, là phương pháp ưa thích để tạo bảng tạm thời bằng cách sử dụng GIÁ TRỊ.

Nếu bạn chỉ muốn chọn từ một số giá trị, thay vì chỉ tạo một bảng và chèn vào nó, bạn có thể làm một cái gì đó như:

WITH  vals (k,v) AS (VALUES (0,-9999), (1, 100)) 
SELECT * FROM vals;

Để thực sự tạo một bảng tạm thời theo cách tương tự, hãy sử dụng:

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

EDIT: Như được chỉ ra bởi a_horse_with_no_name, trong các tài liệu có trạng thái CREATE TABLE AS...tương tự về chức năng SELECT INTO ..., nhưng cái trước là một superset của cái sau và SELECT INTOđược sử dụng trong plpgslq để gán giá trị cho biến tạm thời - vì vậy nó sẽ thất bại trường hợp. Do đó, trong khi các ví dụ trên là hợp lệ cho SQL đơn giản, CREATE TABLEbiểu mẫu nên được ưu tiên.

CREATE TEMP TABLE temp_table AS                                     
WITH t (k, v) AS (
 VALUES
 (0::int,-99999::numeric), 
 (1::int,100::numeric)
)
SELECT * FROM t;

Lưu ý, cũng từ các nhận xét của a_horse_with_no_name và trong câu hỏi ban đầu của OP, điều này bao gồm việc truyền vào các kiểu dữ liệu chính xác trong danh sách giá trị và sử dụng câu lệnh CTE (VỚI).

Ngoài ra, như đã chỉ ra trong câu trả lời của Evan Carrol, truy vấn CTE là một hàng rào tối ưu hóa , nghĩa là CTE luôn được cụ thể hóa. Có nhiều lý do tốt để sử dụng CTE, nhưng có thể có một hiệu suất đáng kể, nếu không được sử dụng cẩn thận. Tuy nhiên, có nhiều trường hợp trong đó hàng rào tối ưu hóa thực sự có thể nâng cao hiệu suất, vì vậy đây là điều cần lưu ý, không nên tránh một cách mù quáng.


12
từ các tài liệu : " CREATE TABLE AS có chức năng tương tự như CHỌN VÀO. CREATE TABLE AS là cú pháp được đề xuất "
a_horse_with_no_name 21/12/14

Hàng rào tối ưu hóa không nhất thiết là một điều xấu. Tôi đã thấy nhiều tuyên bố rằng tôi có thể điều chỉnh để chạy ồ ạt nhanh hơn vì điều đó.
a_horse_with_no_name

Chắc chắn, tôi cũng đã làm rõ điều đó. Tôi sử dụng CTE mọi lúc trong bối cảnh không gian. Nếu bạn có một mệnh đề where với một cái gì đó giống WHERE ST_Intersects(geom, (SELECT geom FROM sometable)hoặc WHERE ST_Intersects(geom, ST_Buffer(anothergeom, 10)thường thì trình hoạch định truy vấn không sử dụng chỉ mục không gian vì cột geom không còn có thể mở rộng được nữa. Nếu bạn tạo khu vực quan tâm của mình trong CTE ban đầu, vấn đề này sẽ biến mất. Nó cũng cực kỳ tiện lợi, nếu bạn muốn sử dụng cùng một aoi trong nhiều biểu thức tiếp theo trong cùng một truy vấn, điều này không phổ biến trong bối cảnh GIS.
John Powell

25

create table as cần một tuyên bố chọn:

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

Bạn cũng có thể viết lại phần này để sử dụng CTE:

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

1
Cảm ơn bạn đã bình luận. Bạn tiếp cận rõ ràng là tốt hơn vì những lý do được nêu trong các tài liệu. Tôi đã chỉnh sửa câu trả lời của mình, mặc dù đã trễ gần 5 năm.
John Powell

11

Vấn đề là các kiểu dữ liệu. Nếu bạn loại bỏ chúng, câu lệnh sẽ hoạt động:

CREATE TEMP TABLE lookup
  (key, val) AS
VALUES 
  (0, -99999), 
  (1, 100) ;

Bạn có thể xác định các loại bằng cách truyền các giá trị của hàng đầu tiên:

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

3

Bạn thực sự không cần tạo bảng cũng như không sử dụng CTE, nếu tất cả những gì bạn cần là sử dụng một vài giá trị trong các truy vấn của mình. Bạn có thể nội tuyến chúng:

SELECT  *
FROM    (VALUES(0::INT, -99999::NUMERIC), (1, 100)) AS lookup(key, val)

Sau đó, bạn có thể nhận được một sản phẩm của Cartesian với một CROSS JOIN(tất nhiên mối quan hệ khác có thể là một bảng thông thường, chế độ xem, v.v.). ví dụ:

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

mang lại:

key |val    |color |
----|-------|------|
0   |-99999 |Red   |
1   |100    |Red   |
0   |-99999 |White |
1   |100    |White |
0   |-99999 |Blue  |
1   |100    |Blue  |

Hoặc JOINcác giá trị với mối quan hệ khác (một lần nữa có thể là bảng thông thường, dạng xem, v.v.), ví dụ:

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;

mang lại:

key |val    |color |lookup_key |
----|-------|------|-----------|
1   |100    |Red   |1          |
0   |-99999 |White |0          |
1   |100    |Blue  |1          |

OK nhưng câu hỏi là "làm thế nào để tạo một bảng tạm thời với ...?"
ypercubeᵀᴹ

Có, nhưng tại sao bạn cần một bảng tạm thời với một vài giá trị tra cứu cố định nếu không tham gia vào một mối quan hệ khác? Giải pháp này tự giải quyết vấn đề, bất kể câu hỏi được diễn đạt như thế nào.
isapir

1
Có lẽ OP chỉ tình cờ đưa ra ví dụ cho một cái gì đó có thể dễ dàng đăng dưới dạng câu hỏi, nhưng dữ liệu thực có hàng ngàn giá trị?
stannius

OP đặc biệt tuyên bố sử dụng các giá trị để câu trả lời của tôi vẫn được áp dụng vì đó chính xác là những gì nó làm
isapir

2

Đầu tiên luôn luôn sử dụng tiêu chuẩn hóa CREATE TABLE AS, SELECT INTOnhư được đề xuất trong các câu trả lời khác là một cú pháp không dùng nữa trong hơn một thập kỷ. Bạn có thể sử dụngCREATE TABLE AS với CTE

Mặc dù nhiều câu trả lời ở đây đang đề xuất sử dụng CTE, nhưng điều đó không thích hợp. Trên thực tế, nó có khả năng chậm hơn một chút. Chỉ cần bọc nó như một cái bàn.

DROP TABLE IF EXISTS lookup;

CREATE TEMP TABLE lookup(key, value) AS
  VALUES
  (0::int,-99999::numeric),
  (1,100);

Nếu bạn phải viết một câu lệnh chọn, bạn cũng có thể làm điều đó (và bạn không cần 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);

Một CTE trong PostgreSQL buộc vật chất hóa. Đó là một hàng rào tối ưu hóa. Vì lý do đó, nói chung không nên sử dụng chúng ở bất cứ đâu trừ khi bạn hiểu chi phí và bạn biết điều đó để cải thiện hiệu suất. Bạn có thể thấy sự chậm lại ở đây, ví dụ,

\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

Tôi đã cập nhật câu trả lời để phản ánh tiêu chuẩn và chỉ ra làm thế nào câu trả lời được chấp nhận không phải lúc nào cũng tương đương với CREATE TABLE AS và thêm một nhận xét về hàng rào tối ưu hóa, đây là một điểm rất tốt để đưa ra. CTE mang lại rất nhiều lợi thế, nhưng đó là sự thật, nếu được sử dụng một cách mù quáng, có thể dẫn đến hiệu suất khủng khiếp.
John Powell

-2
WITH u AS (
    SELECT * FROM (VALUES (1, 'one'), (2, 'two'), (3, 'three')) AS account (id,name)
)
SELECT id, name, length(name) from u;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.