2012-09-14 37 views
8

Tôi có một bảng có khóa chính SERIAL và cũng là cột ltree, có giá trị mà tôi muốn là nối của các khóa chính đó. ví dụ.Giá trị tham chiếu của cột nối tiếp trong cột khác trong cùng một INSERT

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

Tôi rất tò mò nếu có cách để thực hiện việc chèn như vậy trong một truy vấn, ví dụ:

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

Tôi có lẽ đang quá mức ở đây và cố gắng thực hiện trong một truy vấn những gì tôi nên làm trong hai (được nhóm trong giao dịch).

+0

Đường dẫn đó trông không thể truy vấn được .. –

+0

Giá trị đường dẫn của tôi dựa trên điều này: http://stackoverflow.com/a/607379/39529 –

+0

PostgreSQL có đệ quy, biểu thức bảng chung, dễ dàng hơn và nhanh hơn rất nhiều giải pháp/giải pháp đường dẫn của bạn. –

Trả lời

7

Bạn có thể sử dụng một subquery hoặc một CTE ghi để lấy giá trị từ chuỗi lần và sử dụng nó nhiều lần:

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

Data-modifying CTE yêu cầu Postgres 9.1 trở lên.

Nếu bạn không chắc chắn về tên của chuỗi bạn có thể sử dụng pg_get_serial_sequence() thay vì:

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

Nếu tên bảng "foo" có thể không phải là duy nhất trên tất cả các lược đồ trong DB, bạn có thể schema -qualify nó. Và nếu chính tả của tên bất kỳ là phi tiêu chuẩn, bạn phải tăng gấp đôi-quote:

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



xét nghiệm nhanh cho thấy @Mark's idea với lastval()thể công việc quá:

INSERT INTO foo (ltree) VALUES ('1.' || lastval()); 
  • Bạn chỉ có thể để lại id trong truy vấn, cột serial sẽ được chỉ định tự động. Làm cho không có sự khác biệt.

  • Không được có điều kiện chạy đua giữa các hàng. Tô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.

tôi nhấn mạnh Bold.

Nhưng, là @Bernard commented, nó có thể không thành công.Trên ý nghĩ thứ hai, điều này có ý nghĩa: không đảm bảo rằng giá trị mặc định được điền (và nextval() được gọi trong quá trình này) trướclastval() được gọi để điền vào cột thứ hai ltree. Vì vậy, hãy gắn bó với giải pháp đầu tiên và nextval() để chắc chắn.

+0

Chính xác những gì tôi đang tìm kiếm, cảm ơn! –

+0

Có đảm bảo rằng 'nextval()' sẽ được gọi đầu tiên để tìm khóa chính tiếp theo, vì vậy 'lastval()' sẽ không ném một lỗi? – Bernard

+1

Đề xuất thứ hai của bạn ném một '55000 ERROR: lastval chưa được định nghĩa trong phiên này' trên PostgreSQL 9.5. – Bernard

3

này làm việc trong thử nghiệm của tôi:

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

Tôi nghĩ rằng có một điều kiện chủng tộc ở đó nếu hai BIG đang xảy ra cùng một lúc, vì đây tham chiếu giá trị chuỗi cuối cùng, thay vì hàng hiện tại. Cá nhân tôi sẽ nghiêng nhiều hơn để làm điều này (pseudo-code):

my $id = SELECT nextval('foo_id_seq'); 
INSERT INTO foo (id, ltree) VALUES ($id, '$id'); 
Các vấn đề liên quan