2012-09-14 4 views
8

Mam tabelę z kluczem podstawowym SERIAL, a także kolumną ltree, której wartość chcę być połączeniem tych kluczy podstawowych. na przykładWartość odniesienia kolumny szeregowej w innej kolumnie podczas tego samego INSERT

id | path 
---------- 
1 1 
2 1.2 
3 1.2.3 
4 1.4 
5 1.5 

Jestem ciekawy, czy istnieje sposób na wykonanie takiej wstawki w jednym zapytaniu, np.

INSERT INTO foo (id, ltree) VALUES (DEFAULT, THIS.id::text) 

Prawdopodobnie przekraczam tutaj i próbuję zrobić w jednym zapytaniu, co powinienem robić w dwóch (zgrupowanych w transakcji).

+0

Ścieżka ta nie wygląda na bardzo podatną na zapytania. –

+0

Moje wartości ścieżek są oparte na tym: http://stackoverflow.com/a/607379/39529 –

+0

PostgreSQL ma rekursję, wspólne wyrażenie tabelowe, o wiele łatwiejsze i szybsze niż Twoje rozwiązanie ścieżki/obejście. –

Odpowiedz

7

można użyć podzapytania lub zapisu CTE aby pobrać wartość z sekwencji raz i używać go wielokrotnie:

wymaga PostgreSQL 9.1 lub nowszego.

Jeśli nie jesteś pewien co do nazwy sekwencji można użyć pg_get_serial_sequence() zamiast:

WITH i AS (
    SELECT nextval(pg_get_serial_sequence('foo', 'id')) AS id 
    ) 
INSERT INTO foo (id, ltree) 
SELECT id, '1.' || id 
FROM i; 

Jeśli nazwa tabeli „foo” nie może być unikatowa we wszystkich schematu w PB, można schematu - zakwalifikuj to. A jeśli pisownia każdej nazwy jest nietypowy, trzeba cudzysłów:

pg_get_serial_sequence('"My_odd_Schema".foo', 'id') 



Szybkie testy wskazany @Mark's idea z lastval()mógł pracy TOO:

INSERT INTO foo (ltree) VALUES ('1.' || lastval()); 
  • Możesz po prostu zostawić id z zapytania, kolumna serial zostanie przypisana automatycznie. Nie robi różnicy.

  • Nie powinno być warunków wyścigu między rzędami. I quote the manual:

currval

Return the value most recently obtained by nextval for this sequence in the current session. (An error is reported if nextval has never been called for this sequence in this session.) Because this is returning a session-local value, it gives a predictable answer whether or not other sessions have executed nextval since the current session did.

lastval

Return the value most recently returned by nextval in the current session. This function is identical to currval, except that instead of taking the sequence name as an argument it fetches the value of the last sequence used by nextval in the current session. It is an error to call lastval if nextval has not yet been called in the current session.

Bold kopalni nacisk.

Ale, jako @Bernard commented, może jednak zawieść.Po drugie, ma to sens: nie ma gwarancji, że domyślna wartość zostanie wypełniona (i nextval() wywołana w procesie) przedlastval() jest wywoływana, aby wypełnić drugą kolumnę ltree. Dlatego trzymaj się pierwszego rozwiązania i upewnij się, że jest to nextval().

+0

Dokładnie tego, czego szukałem, dzięki! –

+0

Czy jest zagwarantowane, że 'nextval()' zostanie wywołany jako pierwszy, aby znaleźć następny klucz podstawowy, tak aby 'lastval()' nie wygenerował błędu? – Bernard

+1

Twoja druga sugestia rzuca '55000 ERROR: lastval nie jest jeszcze zdefiniowany w tej sesji' na PostgreSQL 9.5. – Bernard

3

To działało w moim teście:

INSERT INTO foo (id, ltree) VALUES (DEFAULT, (SELECT last_value from foo_id_seq)); 

myślę, że jest to warunek, jeśli wyścig tam dwie wkładki są dzieje się w tym samym czasie, ponieważ odwołuje się do ostatniej wartości sekwencji, zamiast bieżącego wiersza. Chciałbym osobiście być bardziej skłonny to zrobić (pseudo-kod):

my $id = SELECT nextval('foo_id_seq'); 
INSERT INTO foo (id, ltree) VALUES ($id, '$id'); 
Powiązane problemy