41

I have a table called map_tags:

map_id | map_license | map_desc

And another table (widgets) whose records contains a foreign key reference (1 to 1) to a map_tags record:

widget_id | map_id | widget_name

Given the constraint that all map_licenses are unique (however are not set up as keys on map_tags), then if I have a map_license and a widget_name, I'd like to perform an insert on widgets all inside of the same SQL statement:

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

I believe I'm on the right track but know right off the bat that this is incorrect SQL for Postgres. Does anybody know the proper way to achieve such a single query?

4

3 回答 3

55

使用INSERT INTO SELECT变体,包括SELECT语句中的任何常量。

PostgreSQLINSERT语法是:

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

记下上面第二行末尾的查询选项。

这是一个给你的例子。

INSERT INTO 
    widgets
    (
        map_id,
        widget_name
    )
SELECT 
   mt.map_id,
   'Bupo'
FROM
    map_tags mt
WHERE
    mt.map_license = '12345'
于 2012-10-22T17:50:51.267 回答
52
INSERT INTO widgets
(
    map_id,
    widget_name
)
SELECT
    mt.map_id, 'Bupo'
FROM
    map_tags mt
WHERE
    mt.map_license = '12345'
于 2012-10-22T17:51:30.367 回答
0

快速回答: 您没有“一条记录”,您有一个“设置有 1 条记录”如果这是 javascript:您有一个“具有 1 个值的数组”而不是“1 个值”。

在您的示例中,可能会在子查询中返回一条记录,但您仍在尝试将记录的“数组”解压缩为单独的实际参数,并将其放入仅接受 1 个参数的位置。

我花了几个小时来思考“为什么不”。当我试图做一些非常相似的事情时:

这是我的笔记:

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

基本上,不要将“ VALUES ”视为 可以解包记录数组的可变参数函数这里没有像在 javascript 函数中那样解包的参数。如:

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]

回到你的 SQL 问题:

此功能不存在的现实不会因为您的子选择仅包含一个结果而改变。它是“一个记录的集合”,而不是“一个记录”。

于 2018-07-30T00:17:48.787 回答