Postgres插入/更新查询无法按预期工作

时间:2016-03-24 02:43:43

标签: postgresql sql-update sql-insert

这是我正在尝试编写的查询的简化版本。它旨在将一行保存为变量name,然后将combine存储在media_hashtags表中,如果存在特定条目,则INSERT该条目。

UPDATE

然而,我收到此错误:

    WITH 
      combine AS (
        SELECT * FROM hashtags WHERE hashtag_text='HOPPA'
      )
    UPDATE media_hashtags SET hashtag_id = (SELECT id FROM combine) WHERE user_id = 58 AND media_id=161;
      INSERT INTO media_hashtags (media_id, user_id, hashtag_id)
    SELECT 161, 58, (SELECT id FROM combine)
    WHERE NOT EXISTS (
      SELECT * FROM media_hashtags
      WHERE (
        user_id = 58 AND
        media_id = 161
      )
    )

    RETURNING *

有趣的是,如果我只使用ERROR: relation "combine" does not exist LINE 8: SELECT 161, 58, (SELECT id FROM combine) 或仅使用UPDATE命令进行查询,则会按预期执行。只有在我同时执行这两项操作时才会出现错误。关于问题是什么和修复的任何想法?

2 个答案:

答案 0 :(得分:1)

您可以使用临时表来存储来自主题标签的数据,然后插入和更新操作。

这是方法:

DROP TABLE IF EXISTS temp_hashtags;
CREATE TEMP TABLE temp_hashtags AS
SELECT * FROM hashtags WHERE hashtag_text='HOPPA';

UPDATE media_hashtags 
    SET hashtag_id = (SELECT id FROM temp_hashtags) 
WHERE user_id = 58 AND media_id=161;

INSERT INTO media_hashtags (media_id, user_id, hashtag_id)
SELECT 161, 58, (SELECT id FROM temp_hashtags)
WHERE NOT EXISTS (
        SELECT * FROM media_hashtags
        WHERE user_id = 58 AND media_id = 161
        );

答案 1 :(得分:1)

您有两个查询,第一个查询以;语句之后的UPDATE结尾。以下INSERT不再看到CTE,因为它是一个新的声明。

如果您想将此作为单个语句运行,则需要将UPDATE移入其自己的CTE中:

WITH combine AS (
    SELECT id 
    FROM hashtags 
    WHERE hashtag_text='HOPPA'
), changed AS (
  UPDATE media_hashtags 
     SET hashtag_id = (SELECT id FROM combine) 
  WHERE user_id = 58 
    AND media_id=161
)  
INSERT INTO media_hashtags (media_id, user_id, hashtag_id)
SELECT 161, 58, (SELECT id FROM combine)
WHERE NOT EXISTS (
  SELECT * FROM media_hashtags
  WHERE (
    user_id = 58 AND
    media_id = 161
  )
)
RETURNING *;

您还应该只选择初始CTE中需要的列。后续语句仅使用combine中的单个列的事实不会被推送到第一个查询中,因此Postgres可能不会尽可能高效地查询hashtags

如果您使用的是Postgres 9.5,则可以使用on conflict语句的insert子句简化语句:

INSERT INTO media_hashtags (media_id, user_id, hashtag_id)
SELECT 161, 58, id
FROM hashtags 
WHERE hashtag_text='HOPPA'
ON CONFLICT (media_id, user_id) DO UPDATE 
  SET hashtag_id = excluded.hashtag_id;

这需要media_hashtags(media_id, user_id)

上的唯一索引