从 SELECT 与单个值组合的 INSERT

mam*_*aye 10 postgresql insert postgresql-9.1

我有这个查询返回几行item_id

select item_id from properties where name like 'body';   
Run Code Online (Sandbox Code Playgroud)

我有第二个返回 1 行的tag_id

select id from tags where name ilike '%hoax%';   
Run Code Online (Sandbox Code Playgroud)

我想使用这两个结果在第三个表中创建新行,item_tags以便我可以将item_id第一个查询中的每个结果插入tag_id到第二个查询中。

我会有类似的东西:

INSERT INTO item_tags (item_id, tag_id) VALUES (item_id1, tag_id);  
INSERT INTO item_tags (item_id, tag_id) VALUES (item_id2, tag_id);
INSERT INTO item_tags (item_id, tag_id) VALUES (item_id3, tag_id);   
 ...     
Run Code Online (Sandbox Code Playgroud)

第一个查询返回超过 800 行。如何自动化插入?
psql 9.1.11,Postgres 9.1.4。

Erw*_*ter 11

基本的 INSERT

INSERT INTO item_tags (item_id, tag_id)
SELECT p.item_id, t.id
FROM  (SELECT item_id FROM properties WHERE name LIKE 'body') p
    , (SELECT id FROM tags WHERE name ILIKE '%hoax%') t
Run Code Online (Sandbox Code Playgroud)

其中,,FROM 子句中的逗号 ( ) 是CROSS JOIN.

这是建立在您的断言之上的,即第二个查询tags...

返回 1 行 tag_id

您从 a 中获得笛卡尔积CROSS JOIN,即 n*m 组合。
如果连接的两边返回多于一行,它们就会相乘。
如果任何一方都没有返回一行,则总体结果是没有行,什么也没有发生。
如果您不想要这两种效果,一侧必须至少返回一行,而另一侧正好返回一行。

对于您的特定组合,您还可以使用嵌套子选择:

INSERT INTO item_tags (item_id, tag_id)
SELECT item_id 
     , (SELECT id FROM tags WHERE name ILIKE '%hoax%') AS tag_id  -- single result!
FROM   properties
WHERE  name LIKE 'body';
Run Code Online (Sandbox Code Playgroud)

细微的差别:这会插入从外部返回的所有行SELECT,即使子选择tags没有返回任何行,这将被转换为NULLfortag_id

大部分 INSERT

要一次处理大量此类插入,您将使用经过大量修改的 query。但是与上面第一个查询相同的规则适用于两个连接表中的基数。

INSERT INTO item_tags (item_id, tag_id)
SELECT p.item_id, t.id
FROM  (
   VALUES
      ('body',  'hoax')
    , ('body2', 'fun')
    , ('body3', 'love')
  ) AS it(item, tag)
JOIN   properties p ON p.name LIKE it.item
JOIN   tags t ON t.name ILIKE ('%' || it.tag ||'%');
Run Code Online (Sandbox Code Playgroud)

你看逻辑对不对?就个人而言,我称之为“CROSS JOIN代理”。