2011-08-19 29 views
8

Tôi có cơ sở dữ liệu PostgreSQL 9 sử dụng các số nguyên tăng dần tự động làm khóa chính. Tôi muốn sao chép một số hàng trong bảng (dựa trên một số tiêu chí lọc), trong khi thay đổi một hoặc hai giá trị, tức là sao chép tất cả các giá trị cột, ngoại trừ ID (được tạo tự động) và có thể là một cột khác. Tuy nhiên, tôi cũng muốn lấy ánh xạ từ ID cũ đến ID mới. Có cách nào tốt hơn để làm điều đó sau đó chỉ cần truy vấn cho các hàng để sao chép đầu tiên và sau đó chèn các hàng mới một tại một thời điểm?Sao chép một số hàng một cách hiệu quả trong bảng PostgreSQL

Về cơ bản tôi muốn làm một cái gì đó như thế này:

INSERT INTO my_table (col1, col2, col3) 
SELECT col1, 'new col2 value', col3 
FROM my_table old 
WHERE old.some_criteria = 'something' 
RETURNING old.id, id; 

Tuy nhiên, điều này không thành công với ERROR: missing FROM-clause entry for table "old" và tôi có thể thấy lý do tại sao: Postgres phải làm SELECT đầu tiên và sau đó chèn nó và RETURNING khoản chỉ có quyền truy cập vào hàng mới được chèn vào.

+0

Bạn có xảy ra để có ý tưởng làm thế nào để làm truy vấn của bạn w/o gọi tên tất cả các thuộc tính tôi muốn sao chép? Tôi có bảng khá lớn (với rất nhiều thuộc tính) và gõ tất cả chúng và không quên một là một nỗi đau ... –

+0

lý do tại sao hai câu hỏi về cùng một điều? http://stackoverflow.com/questions/29256888/insert-into-from-select-returning-id-mappings – murison

Trả lời

8

RETURNING chỉ có thể tham chiếu đến các cột trong hàng cuối cùng được chèn vào. Bạn không thể tham chiếu đến id "OLD" theo cách này trừ khi có một cột trong bảng chứa cả id và id mới.

Cố gắng chạy này mà nên làm việc và sẽ hiển thị tất cả các giá trị có thể mà bạn có thể nhận được thông qua LẠI:

INSERT INTO my_table (col1, col2, col3) 
    SELECT col1, 'new col2 value', col3 
    FROM my_table AS old 
    WHERE old.some_criteria = 'something' 
RETURNING *; 

Nó sẽ không giúp bạn có được hành vi mà bạn muốn, nhưng nên minh họa rõ hơn về cách quay trở lại là thiết kế làm việc.

+0

Cảm ơn - nhưng tôi tin rằng tôi đã hiểu cách hoạt động của RETURNING. – EMP

0

'cũ' là từ dành riêng, được sử dụng bởi hệ thống viết lại quy tắc. [Tôi cho rằng đoạn truy vấn này không phải là một phần của quy tắc; trong trường hợp đó, bạn sẽ đặt câu hỏi theo cách khác nhau]

+0

Có, bạn nói đúng - Tôi đã tạo truy vấn cho bài đăng vì bài đăng thực sự phức tạp hơn. – EMP

2

Tốt! Tôi kiểm tra mã này, nhưng tôi thay đổi này (FROM my_table AS old) trong (FROM my_table) và này (WHERE old.some_criteria = 'something') trong (WHERE some_criteria = 'something')

Đây là mã cuối cùng mà tôi sử dụng

INSERT INTO my_table (col1, col2, col3) 
    SELECT col1, 'new col2 value', col3 
    FROM my_table AS old 
    WHERE some_criteria = 'something' 
RETURNING *; 

Cảm ơn!

0
DROP TABLE IF EXISTS tmptable; 
CREATE TEMPORARY TABLE tmptable as SELECT * FROM products WHERE id = 100; 
UPDATE tmptable SET id = sbq.id from (select max(id)+1 as id from products) as sbq; 
INSERT INTO products (SELECT * FROM tmptable); 
DROP TABLE IF EXISTS tmptable; 

thêm bản cập nhật khác trước khi chèn để sửa đổi một lĩnh vực

UPDATE tmptable SET another = 'data'; 
+0

'UPDATE tmptable SET id =' chỉ hoạt động nếu id là một số nguyên, không phải nếu nó là nối tiếp – DarkMukke

2

Điều này có thể được thực hiện với sự giúp đỡ của CTEs dữ liệu modifiying (Postgres 9.1+):

WITH sel AS (
    SELECT id, col1, col3 
     , row_number() OVER (ORDER BY id) AS rn -- order any way you like 
    FROM my_table 
    WHERE some_criteria = 'something' 
    ORDER BY id -- match order or row_number() 
    ) 
, ins AS (
    INSERT INTO my_table (col1, col2, col3) 
    SELECT col1, 'new col2 value', col3 
    FROM sel 
    ORDER BY id -- redundant to be sure 
    RETURNING id 
) 
SELECT s.id AS old_id, i.id AS new_id 
FROM (SELECT id, row_number() OVER (ORDER BY id) AS rn FROM ins) i 
JOIN sel s USING (rn); 

SQL Fiddle trình diễn.

Điều này dựa trên chi tiết triển khai không có giấy tờ mà các hàng từ SELECT được chèn vào theo thứ tự được cung cấp (và được trả lại theo thứ tự được cung cấp). Nó hoạt động trong tất cả các phiên bản hiện tại của Postgres và sẽ không bị phá vỡ.Liên quan:

chức năng Window không được phép trong mệnh đề RETURNING, vì vậy tôi áp dụng row_number() trong subquery khác.

Nhiều lời giải thích trong câu trả lời sau đó liên quan này:

Các vấn đề liên quan