2011-09-19 49 views
94

Tôi có một loạt các hàng mà tôi cần phải chèn vào bảng, nhưng các chèn này luôn được thực hiện theo lô. Vì vậy, tôi muốn kiểm tra xem một hàng duy nhất từ ​​lô tồn tại trong bảng bởi vì sau đó tôi biết tất cả họ đã được chèn vào.Kiểm tra nhanh nhất nếu hàng tồn tại trong PostgreSQL

Vì vậy, nó không phải là kiểm tra khóa chính, nhưng không quan trọng quá nhiều. Tôi chỉ muốn kiểm tra hàng duy nhất để count(*) có lẽ không tốt, vì vậy một cái gì đó giống như exists tôi đoán.

Nhưng vì tôi khá mới với PostgreSQL, tôi muốn hỏi những người biết.

batch My chứa hàng với cơ cấu như sau:

userid | rightid | remaining_count 

Vì vậy, nếu bảng chứa bất kỳ hàng với quy userid nó có nghĩa là tất cả họ đều có mặt ở đó.

+0

Bạn muốn xem bảng có BẤT CỨ hàng nào hay bất kỳ hàng nào trong hàng của bạn? – JNK

+0

bất kỳ hàng nào từ hàng loạt của tôi có. tất cả họ đều chia sẻ cùng một lĩnh vực bị chỉnh sửa một chút. –

+0

Vui lòng làm rõ câu hỏi của bạn. Bạn muốn thêm một loạt các bản ghi, tất cả hoặc không có gì? Có điều gì đặc biệt về tính không? (BTW một từ dành riêng, không thực tế như một tên cột) – wildplasser

Trả lời

174

Sử dụng EXISTS từ khóa cho TRUE/FALSE trở lại:

select exists(select 1 from contact where id=12) 
+9

Tiện ích mở rộng này , bạn có thể đặt tên cho cột được trả lại để dễ tham khảo. Ví dụ 'chọn tồn tại (chọn 1 từ số liên lạc trong đó id = 12) AS" tồn tại "' – Rowan

+3

Điều này là tốt hơn, vì nó sẽ luôn trả về giá trị (đúng hoặc sai) thay vì đôi khi Không (tùy thuộc vào ngôn ngữ lập trình của bạn) mở rộng cách bạn mong đợi. – isaaclw

+1

Tôi có Seq Scan với phương pháp này. Tôi làm gì sai? – FiftiN

0
SELECT 1 FROM user_right where userid = ? LIMIT 1 

Nếu kết quả của bạn chứa hàng thì bạn không phải chèn. Nếu không, hãy chèn bản ghi của bạn.

+0

nếu bó chứa 100 hàng nó sẽ trả lại cho tôi 100 hàng , bạn nghĩ đó là tốt? –

+0

Bạn có thể giới hạn nó thành 1 hàng. Nên thực hiện tốt hơn. Hãy xem câu trả lời đã chỉnh sửa từ @aix cho điều đó. –

0
select true from tablename where condition limit 1; 

Tôi tin rằng đây là truy vấn mà postgres sử dụng để kiểm tra khóa ngoại.

Trong trường hợp của bạn, bạn có thể làm điều này trong một đi quá:

insert into yourtable select $userid, $rightid, $count where not (select true from yourtable where userid = $userid limit 1); 
23

Làm thế nào về đơn giản:

select 1 from tbl where userid = 123 limit 1; 

nơi 123 là userid của hàng loạt mà bạn sắp chèn .

Truy vấn trên sẽ trả về tập hợp trống hoặc một hàng đơn, tùy thuộc vào việc có hồ sơ với userid đã cho hay không.

Nếu điều này trở nên quá chậm, bạn có thể xem xét tạo chỉ mục trên tbl.userid.

nếu ngay cả một hàng duy nhất từ ​​hàng loạt tồn tại trong bảng, trong trường hợp đó tôi không cần phải chèn hàng của tôi bởi vì tôi biết chắc chắn tất cả họ đều là chèn vào.

Đối với điều này vẫn đúng ngay cả khi chương trình của bạn bị gián đoạn giữa hàng loạt, tôi muốn khuyên bạn nên chắc chắn rằng bạn quản lý các giao dịch cơ sở dữ liệu một cách thích hợp (ví dụ rằng toàn bộ lô được đưa vào trong một giao dịch duy nhất).

+0

chắc chắn, sử dụng giao dịch –

+11

Đôi khi có thể dễ dàng lập trình hơn để "chọn số (\ *) từ (chọn 1 ... giới hạn 1)" vì đảm bảo luôn trả về hàng có giá trị đếm (\ *) 0 hoặc 1. –

+0

@DavidAldridge count (*) vẫn có nghĩa là tất cả các hàng phải được đọc, trong khi giới hạn 1 dừng tại bản ghi đầu tiên và trả về – Imraan

8
INSERT INTO target(userid, rightid, count) 
    SELECT userid, rightid, count 
    FROM batch 
    WHERE NOT EXISTS (
    SELECT * FROM target t2, batch b2 
    WHERE t2.userid = b2.userid 
    -- ... other keyfields ... 
    )  
    ; 

BTW: nếu bạn muốn toàn bộ lô hàng để thất bại trong trường hợp có trùng lặp, sau đó (được đưa ra một ràng buộc khoá chính)

INSERT INTO target(userid, rightid, count) 
SELECT userid, rightid, count 
FROM batch 
    ; 

sẽ làm chính xác những gì bạn muốn: hoặc nó thành công hoặc không thành công.

+0

Điều này sẽ kiểm tra mỗi hàng. Anh ta muốn kiểm tra một lần. – JNK

+0

Không, nó thực hiện một lần kiểm tra. Truy vấn phụ không tương quan. Nó sẽ bảo lãnh khi một cặp kết hợp được tìm thấy. – wildplasser

+0

Đúng vậy, tôi nghĩ nó được gọi là truy vấn bên ngoài. +1 cho bạn – JNK

0

Nếu bạn nghĩ về performace, có thể là bạn có thể sử dụng "thực hiện" trong một chức năng giống như này:

PERFORM 1 FROM skytf.test_2 WHERE id=i LIMIT 1; 
    IF FOUND THEN 
     RAISE NOTICE ' found record id=%', i; 
    ELSE 
     RAISE NOTICE ' not found record id=%', i; 
END IF; 
+0

không hoạt động với tôi: Tôi nhận được lỗi cú pháp gần thực hiện – Simon

+0

đó là pl/pgsql, chứ không phải SQL, do đó lỗi cú pháp cho "PERFORM" nếu cố gắng chạy nó dưới dạng SQL –

0

Rule of thumb

chọn tồn tại ( chọn đúng từ xx xx nơi ) là "Liệu 1 + 1 add s lên đến 2 ";

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