Unnest nhiều mảng thành hàng


8

Tôi đã được chỉ ra một cách tuyệt vời để bulkinsert với ví dụ này:

WITH p AS (
    INSERT INTO parent_table (column_1) 
    SELECT $1 
    RETURNING id) 
INSERT INTO child_table (parent_table_id, column_a) 
SELECT p.id, a 
FROM   p, unnest($2::text[]) AS a

Tuy nhiên, tôi cần chèn nhiều hàng từ nhiều mảng, vì vậy tôi đã thử cú pháp này:

WITH p AS (
    INSERT INTO parent_table (column_1) 
    SELECT $1 
    RETURNING id) 
INSERT INTO child_table (parent_table_id, column_a, column_b) 
SELECT p.id, a, b 
FROM   p, unnest($2::text[]) AS a, unnest($3::bigint[]) AS b

Tôi có một khóa chính parent_table_idcolumn_avà khi tôi cố gắng thực hiện truy vấn này, Postgres phàn nàn về vi phạm khóa trùng lặp.

Làm thế nào các mảng nên được mở ra để chúng tạo thành các hàng riêng lẻ?

Nói cách khác, nếu $2$3cả hai đều có hai mục nhập, làm thế nào mục nhập đầu tiên của $2chỉ có thể được chèn với mục nhập đầu tiên $3và giống nhau cho các mục nhập thứ hai tương ứng?

Nếu điều này là không thể, tôi có thể xây dựng một mảng nhiều chiều không? Nếu vậy, làm thế nào nó được truyền với nhiều loại mảng và cú pháp mảng đa chiều là gì?

Câu trả lời:


12

Điều này sẽ làm những gì bạn mong muốn:

WITH p AS (
    INSERT INTO parent_table (column_1) 
    SELECT $1 
    RETURNING id) 
INSERT INTO child_table (parent_table_id, column_a, column_b) 
SELECT p.id, t.a, t.b 
FROM   p, (SELECT unnest($2::text[]) AS a, unnest($3::bigint[]) AS b) t

Sự khác biệt tinh tế ở đây là unnest()các cuộc gọi trong cùng một SELECTdanh sách không được kiểm tra song song nếu số lượng phần tử giống hệt nhau . Mặc dù cẩn thận: Trong Postgres 9.6 trở lên, nếu số lượng không giống nhau, kết quả là sản phẩm của Cartesian thay thế. Hành vi đã được khử trùng trong Postgres 10 . Xem:

Bạn có thể sử dụng một hình thức sạch hơn với generate_subscripts()hoặc các kỹ thuật khác, nhưng những hình thức đó sẽ dài dòng hơn nhiều. Chi tiết trong câu hỏi liên quan này:

Hậu 9,4

Tính năng mới WITH ORDINALITYtrong Postgres 9.4 cho phép hình thức gọn gàng hơn (và chỉ dài hơn vừa phải) cho việc này:

WITH p AS (...)
INSERT INTO child_table (...)
SELECT p.id, ta.a, tb.b 
FROM   p
     , unnest($2::text[]) WITH ORDINALITY AS ta(a, rn)
JOIN   unnest($3::bigint[]) WITH ORDINALITY AS tb(b, rn) USING (rn);

Và trường hợp đặc biệt này có thể còn đơn giản hơn nữa với hình thức mới unnest()chấp nhận nhiều mảng:

WITH p AS (...)
INSERT INTO child_table (...)
SELECT p.id, t.a, t.b 
FROM   p, unnest($2::text[], $3::bigint[]) AS t(a, b);

Ví dụ trong câu trả lời liên quan này .


-1

Tôi đã giải quyết với:

INSERT INTO foo(Val,i,j)
SELECT myArr[i][j] ,i,j 
FROM Generate_Series(1,lbound) i 
JOIN Generate_Series(1,ubound) j
    ON true
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.