2015-05-15 10 views
7

Istnieją pewne ograniczenia:INSERT, jeśli nie istnieje, inny id powrót

  1. nie można modyfikować w bazie
  2. Kolumny nie są unikalne
  3. musi wrócić id ostatni wkładka (RETURNING id)
  4. Jeśli istnieje, return istniejący identyfikator
  5. Zostanie wywołany przez naszą niestandardową bibliotekę db (wartości w select będą jako parametry z PHP (?,?,?,!))

INSERT INTO tags (name, color, groupid) 
SELECT 'test', '000000', 56 
WHERE NOT EXISTS (
    SELECT text FROM tags WHERE name = 'test' AND groupid = 56 
) 
RETURNING id 

To działa - aż do punktu, w którym muszę się istniejący id również. Dzięki temu otrzymam tylko wstawiony identyfikator. Czy można zwrócić wartość instrukcji SELECT, jeśli nie zostanie ona wstawiona?

UPDATE:

DO $$ 
BEGIN 
    IF NOT EXISTS (
     SELECT text FROM tags WHERE name = 'test' AND groupid = 56 
    ) 
    THEN 
     INSERT INTO tags (name, color, groupid) 
      VALUES ('test', '000000', 56) RETURNING id; 
    ELSE 
     RETURN SELECT text FROM tags WHERE name = 'test' AND groupid = 56; 
    END IF; 
END 
$$ 

testował z takim formacie - jednak ten kończy się z kilkoma błędami:

RETURN cannot have a parameter in function returning void 
+0

Można uniknąć tego ostatniego błędu dokonując nazwie funkcji zamiast 'oświadczenie DO', z dokładnie to samo ciało, np 'UTWÓRZ FUNKCJĘ foo (tekst, tekst, int) POWRÓT int LANGUAGE plpgsql AS $$ ....'; następnie możesz wykonać go jako 'SELECT foo (?,?,?) AS id' – IMSoP

+0

Do testowania i stworzyłem go jako funkcję, wynik jest po prostu nieco inny bit:'ERROR: zapytanie nie ma miejsca docelowego dla danych wynikowych ' –

+0

Dzieje się tak dlatego, że 'RETURNING id' jest jak' SELECT', musisz powiedzieć funkcji 'RETURN' o wyniku całej instrukcji 'INSERT', jak sądzę. – IMSoP

Odpowiedz

3

Można to zrobić przy użyciu CTE.

Informacje cte zawiera dane źródłowe, dlatego należy zastąpić tam wartości zastępcze dla PHP.

CTE zwróci wyniki z pierwszej połowy unii, jeśli istniejący rekord istnieje (tak będzie wyświetlany stary identyfikator), a druga połowa, jeśli wstawiono insert (tak będzie wyświetlany nowy identyfikator). Przykładem

WITH info (name, color, groupid) AS 
    (values('test','000000',56)), 
    trial AS (
    INSERT INTO tags(name, color, groupid) 
     SELECT info.name, info.color, info.groupid 
     FROM info 
     WHERE NOT EXISTS (
     SELECT * FROM tags t2 
     WHERE t2.name = info.name AND t2.groupid= info.groupid) 
    RETURNING id) 
SELECT tags.id 
FROM tags 
INNER JOIN info ON tags.name = info.name AND tags.groupid= info.groupid 
UNION ALL 
SELECT trial.id 
FROM trial; 

SQL Fiddle: http://sqlfiddle.com/#!15/a7b0f/2

Postgres strona podręcznika dla korzystających współczynniki CTE

http://www.postgresql.org/docs/9.1/static/queries-with.html

+0

prawie - działa poprawnie w pgadmin, wywołując go przez php jednak: BŁĄD: kolumna " groupid " jest typu całkowitego, ale wyrażenie jest typu tekst LINIA 6: WYBIERZ info.nazwa, info.color, info.groupid^WSKAZ :WKA: Konieczne będzie przepisanie lub rzutowanie wyrażenia. I nie rozumiem, dlaczego. –

+0

Wygląda na to, że twój kod PHP wysyła ciąg tekstowy do kolumny id grupy. Jeśli jesteś pewny, że jest int i nie możesz zmienić PHP, aby wysłać int, można to naprawić, zmieniając linię wartości z czymś takim jak: (wartości (: nazwa,: kolor, rzut (: groupid jako int)) – Gary

+0

Rzeczywiście udało mu się wysłać go jako ciąg, aby upewnić się, że dodałem :: całkowite rzutowanie na każdym z nich. –

-2

Można użyć instrukcji jeśli to zrobić.

IF NOT EXISTS(SELECT text FROM tags WHERE name = 'test') 
BEGIN 
    INSERT INTO tags (name, color, groupid) 
    VALUES ('test', '000000', 56) 
    SET @textId = SCOPE_IDENTITY() 
END 
ELSE 
BEGIN 
    SELECT @textId = ID FROM tags WHERE name = 'test' 
END 

Należy wprowadzić niezbędne zmiany w powyższym zapytaniu zgodnie z wymaganiami.

+0

BŁĄD: błąd składniowy w lub w pobliżu "JEŻELI" To nawet nie wygląda na prawidłową składnię. Czy nie powinno to być JESZCZE NIŻ INNE? –

+1

Wygląda na to, że składnia Microsoft SQLServer – Gary

-3

jeśli name jest wyjątkowy:

INSERT INTO `tags` (name, color, groupid) VALUES ('test', '000000', 56) 
    ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), `name`='test'; 
SELECT LAST_INSERT_ID(); 
+0

Nazwa nie jest unikalna. Może istnieć wiele identycznych nazw, ALE mają różne groupid. Tak więc cała kontrola wstawiania/wyboru znajduje się w "zasięgu" tej grupy. –

+0

ON DUPLICATE KEY nie istnieje w PostgreSQL, twoje zapytanie zawiedzie. Byłoby to również niemożliwe w przypadku innych problemów związanych z konkretnym zapytaniem MySQL. –

Powiązane problemy