Câu hỏi PostgreSQL: Chọn phụ bên trong chèn


Tôi có một cái bàn gọi là map_tags:

map_id | map_license | map_desc

Và một bảng khác (widgets) có hồ sơ chứa tham chiếu khóa ngoài (từ 1 đến 1) cho map_tags ghi lại:

widget_id | map_id | widget_name

Với ràng buộc rằng tất cả map_licenses là duy nhất (tuy nhiên không được thiết lập làm khóa map_tags), sau đó nếu tôi có map_license và một widget_name, Tôi muốn thực hiện chèn widgets tất cả bên trong cùng câu lệnh SQL:

INSERT INTO
    widgets w
(
    map_id,
    widget_name
)
VALUES (
    (
        SELECT
            mt.map_id
        FROM
            map_tags mt
        WHERE
            // This should work and return a single record because map_license is unique
            mt.map_license = '12345'
    ),
    'Bupo'
)

tôi tin Tôi đang đi đúng hướng nhưng biết ngay dơi rằng đây là SQL không chính xác cho Postgres. Có ai biết cách thích hợp để đạt được một truy vấn như vậy?


18
2017-10-22 17:46


gốc


Chưa bao giờ làm điều đó với PostgreSQL, nhưng nó không giống như INSERT INTO widgets SELECT NULL, map_id, 'Bupo' FROM map_tags WHERE map_license = '12345'? - raina77ow
Cảm ơn @ raina77ow (+1) - Tôi không chắc đó có phải là điều bạn nên làm hay không. Các SELECT tuyên bố thay cho (...) VALUES(...) cú pháp chắc chắn là ném tôi đi mặc dù. Bạn có thể giải thích cho tôi như thế nào mà nên làm việc? Cảm ơn một lần nữa! - Bantha Fodder
Vâng, tôi chỉ sử dụng nó như điều này trong MySQL ... Lý do, tôi giả sử, là bạn phải xây dựng toàn bộ tập hợp dữ liệu sẽ được chèn vào - và VALUES ((SELECT smth), 'smth_else') không làm điều đó. ) - raina77ow
Bạn không thực sự cần phải sử dụng các giá trị theo cú pháp này: INSERT INTO table2 (column_name (s)) SELECT column_name (s) FROM table1; - de.la.ru


Các câu trả lời:


INSERT INTO widgets
(
    map_id,
    widget_name
)
SELECT
    mt.map_id, 'Bupo'
FROM
    map_tags mt
WHERE
    mt.map_license = '12345'

21
2017-10-22 17:51



Đây là cú pháp cực kỳ hữu ích khi bảng bạn muốn chèn vào có một SERIAL PK hoặc tương tự - dougajmcdonald


Sử dụng INSERT INTO SELECT biến thể, bao gồm bất kỳ hằng số nào ngay vào SELECT tuyên bố.

PostgreSQL INSERT cú pháp là:

INSERT INTO table [ ( column [, ...] ) ]
 { DEFAULT VALUES | VALUES ( { expression | DEFAULT } [, ...] ) [, ...] | query }
 [ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]

Lưu ý về truy vấn ở cuối dòng thứ hai ở trên.

Đây là một ví dụ cho bạn.

INSERT INTO 
    widgets
    (
        map_id,
        widget_name
    )
SELECT 
   mt.map_id,
   'Bupo'
FROM
    map_tags mt
WHERE
    mt.map_license = '12345'

26
2017-10-22 17:50



Tại sao câu trả lời gần như giống hệt nhau nhưng ít hoàn thành hơn và một phút sau đó lại được bầu chọn nhiều hơn và được chấp nhận? - Chris Peacock


Câu trả lời nhanh: Bạn không có "một bản ghi duy nhất" bạn có một "thiết lập với 1 bản ghi" Nếu đây là javascript: Bạn có một "mảng có 1 giá trị" không phải là "1 giá trị".

Trong ví dụ của bạn, một bản ghi có thể được trả lại trong truy vấn phụ, nhưng bạn vẫn đang cố gắng giải nén một "mảng" các bản ghi vào riêng các thông số thực tế vào một địa điểm chỉ lấy 1 tham số.

Phải mất một vài giờ để quấn đầu của tôi xung quanh "tại sao không". Khi tôi đang cố gắng làm điều gì đó rất giống nhau:

Đây là ghi chú của tôi:

tb_table01: (no records)
+---+---+---+
| a | b | c | << column names
+---+---+---+

tb_table02:
+---+---+---+
| a | b | c | << column names
+---+---+---+
|'d'|'d'|'d'| << record #1
+---+---+---+
|'e'|'e'|'e'| << record #2
+---+---+---+
|'f'|'f'|'f'| << record #3
+---+---+---+

--This statement will fail:
INSERT into tb_table01
    ( a, b, c )
VALUES
    (  'record_1.a', 'record_1.b', 'record_1.c' ),
    (  'record_2.a', 'record_2.b', 'record_2.c' ),

    -- This sub query has multiple
    -- rows returned. And they are NOT
    -- automatically unpacked like in 
    -- javascript were you can send an
    -- array to a variadic function.
    (
        SELECT a,b,c from tb_table02
    ) 
    ;

Về cơ bản, không nghĩ về "GIÁ TRỊ" như một variadic chức năng có thể giải nén một mảng các bản ghi. Có không có đối số giải nén ở đây như bạn sẽ có trong một javascript chức năng. Nhu la:

function takeValues( ...values ){ 
    values.forEach((v)=>{ console.log( v ) });
};

var records = [ [1,2,3],[4,5,6],[7,8,9] ];
takeValues( records );

//:RESULT:
//: console.log #1 : [1,2,3]
//: console.log #2 : [4,5,7]
//: console.log #3 : [7,8,9]

Quay lại câu hỏi SQL của bạn:

Thực tế của chức năng này không tồn tại không thay đổi chỉ vì lựa chọn phụ của bạn chỉ chứa một kết quả. Nó là một "thiết lập với một bản ghi" không phải "một bản ghi duy nhất".


0
2017-07-30 00:17