2011-08-25 14 views
9

Izoluję problem ze znacznie bardziej złożonego zapytania. Oto scenariusz testowyNie można wybrać z klauzuli UPDATE RETURNING w postgresie

DROP TABLE test; 
CREATE TABLE test (
    id integer, 
    description varchar(100) 
); 

INSERT INTO test(id, description) VALUES (1,'new'); 
INSERT INTO test(id, description) VALUES (2,'new'); 

Jeśli uruchomić kwerendę:

SELECT * FROM test WHERE id IN (UPDATE test set description='test' RETURNING id) 

Dostaję następujący błąd:

BŁĄD: błąd składni na lub w pobliżu "test" Linia 1: SELECT * FROM test WHERE id (opis zestawu testów UPDATE = "test" RE ... ^

*** Fehler ** *

BŁĄD: błąd składni na lub w pobliżu "test" SQL Status: 42601 Zeichen: 37

Jednak jeśli tylko uruchomić statemennt

UPDATE test set value='test' RETURNING id 

uzyskać wynik z 2 rzędów:

Jeśli substitude że wynik bym zapytania jak:

SELECT * FROM test WHERE id IN (1,2); 

z wynikiem:

1; "test" 2, "test"

Dlaczego nie uzyskuję tego samego wyniku z moim początkowym stwierdzeniem?

+1

Muszą być jednostkowe sprawozdanie. Fakt, że dwa wiersze są aktualizowane, może powodować problemy, nigdy nie próbowano ZWRACAĆ, gdy wraca więcej niż jeden wiersz/wartość. –

Odpowiedz

23

Zanim PostgreSQL 9.1 INSERT/UPDATE/DELETE może być używany tylko jako instrukcje najwyższego poziomu. Właśnie dlatego otrzymujesz błąd składni.

Począwszy od wersji 9.1 można używać instrukcji modyfikujących dane ze wspólnymi wyrażeniami tabel.Twoja przykładowa kwerenda będzie wyglądać następująco:

WITH updated AS (UPDATE test SET description = 'test' RETURNING id) 
SELECT * FROM test WHERE id IN (SELECT id FROM updated); 

Należy zachować ostrożność wybierając z właśnie zmodyfikowanego tabeli. W ten sposób można uzyskać mylące wyniki. Gdy zapytania są wykonywane w tej samej migawce, SELECT nie zobaczy efektów instrukcji UPDATE.

+2

FYI, podejście CTE nie działa z INSERT –

+0

Więc to 'SELECT' zwróci identyfikator i starą wartość opisu' 'new'' zamiast zaktualizowanej wartości' 'test''? – Davos

6

Uaktualniasz dwa wiersze zapytania UPDATE, dodajesz klauzulę WHERE, aby ograniczyć liczbę dotkniętych wierszy.

UPDATE test SET description = 'test' WHERE id = 1 RETURNING id 

zwrócić pojedynczy rząd.

+0

SELECT * FROM test WHERE id IN (test UPDATE SET wartość = 'test' WHERE id = 1 ID TURNING) pokazuje ten sam błąd – markus

+0

zaktualizowano "wartość" do "opisu", ten sam problem – markus

3

Brakuje IN: ... WHERE id IN (UPDATE ...?

However if I only run the statemennt "UPDATE test set value='test' RETURNING id", I get a result with 2 rows. Why is that?

Twój UPDATE ma WHERE klauzuli i dlatego aktualizuje każdy rząd, którego istnieją dwa.

+0

tak, właśnie go zaktualizowano – markus

+0

Problem jest nie aktualizacja ZWRACAJĄCA, która działa z klauzulą ​​where i without. Problem dotyczy wyboru wokół niego. – markus

1

Nie ograniczasz swojej klauzuli where. Musisz mieć id = (blahblah) lub id IN (blahblah)

1
UPDATE test set description='test' RETURNING * 

dałby zestaw wyników, którego można oczekiwać od pierwszego zapytania.

Ale podejrzewam, że próbowałeś czegoś bardziej złożonego?

0
DROP TABLE IF EXISTS test_tab; 

CREATE TABLE test_tab (
    id integer, 
    description varchar(100) 
); 

INSERT INTO test_tab(id, description) VALUES (1,'new'); 
INSERT INTO test_tab(id, description) VALUES (2,'new'); 

SELECT * from test_tab; 

DO $$ 
DECLARE 
    myID test_tab.id%TYPE; 
    testID test_tab.id%TYPE; 
    cur_IDs CURSOR for select id from test_tab; 
BEGIN 
    OPEN cur_IDs; 
    LOOP 
     FETCH cur_IDs into testID; 
     EXIT WHEN testID is NULL; 

     UPDATE test_tab SET description='test' WHERE id = testID RETURNING id into myID; 
     raise notice 'myID %', myID; 
    END LOOP; 
    CLOSE cur_IDs; 
END$$; 


DROP TABLE IF EXISTS test_tab; 
-1

jestem dodatek przed mrówkami Aasma, jeśli select na tym samym stole, przy użyciu:

WITH updated AS (UPDATE test SET description = 'test' RETURNING id, description) 
SELECT * FROM updated; 
Powiązane problemy