2016-03-24 8 views
0

Hier ist eine vereinfachte Version einer Abfrage, die ich versuche zu schreiben. Es ist beabsichtigt, eine Zeile als eine Variable combine, dann UPDATE die Media_hashtags-Tabelle zu speichern, wenn ein bestimmter Eintrag vorhanden ist, andernfalls diesen Eintrag INSERT.Postgres Insert/Update-Abfrage funktioniert nicht wie erwartet

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 * 

Allerdings bekomme ich diesen Fehler:

ERROR: relation "combine" does not exist 
LINE 8:  SELECT 161, 58, (SELECT id FROM combine) 

Interessanterweise Wenn ich eine Abfrage nur mit den UPDATE oder nur die INSERT Befehle zu tun, dann ist es wie erwartet ausgeführt wird. Der Fehler tritt nur auf, wenn ich beides gleichzeitig mache. Irgendwelche Ideen, was das Problem ist, und eine Lösung?

+2

scheint Es getrennt zu sein zwei Abfragen hier (nach dem Semikolon suchen). Es ist natürlich, dass der zweite den "Mähdrescher" von der ersten – leonbloy

+0

nicht sieht. Das macht Sinn. Ich nehme an, ich könnte den Mähdrescher neu schreiben, aber das wäre ausführlich. Gibt es einen besseren Weg, um dieses Problem zu lösen? – dmwong2268

Antwort

1

Sie haben zwei Anfragen, die erste endet mit dem ; nach der UPDATE Aussage. Das folgende INSERT sieht das CTE nicht mehr, weil es eine neue Aussage ist.

Wenn Sie dies als eine einzelne Anweisung ausgeführt werden sollen, müssen Sie die UPDATE in seinem eigenen CTE bewegen:

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

Sie sollten auch nur die Spalten auswählen, die Sie in dem Anfang CTE benötigen. Die Tatsache, dass die nachfolgenden Anweisungen nur eine einzige Spalte von combine verwenden, wird nicht in die erste Abfrage eingefügt, sodass Postgres hashtags möglicherweise nicht so effizient abfragt, wie es möglicherweise möglich ist.


Wenn Sie Postgres 9.5 verwenden können Sie die Anweisung mit der on conflict-Klausel für die insert Anweisung vereinfachen:

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; 

Dieses auf einen eindeutigen Index erfordert media_hashtags(media_id, user_id)

1

Sie können die temporäre Tabelle verwenden, um Daten aus Hashtags zu speichern und dann Operationen einzufügen und zu aktualisieren. Hier

ist die Art und Weise:

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