Postgres: Riêng biệt nhưng chỉ dành cho một cột


120

Tôi có một bảng trên pgsql với các tên (có hơn 1 triệu hàng), nhưng tôi cũng có nhiều bản sao. Tôi chọn 3 lĩnh vực: id, name, metadata.

Tôi muốn chọn chúng ngẫu nhiên với ORDER BY RANDOM()LIMIT 1000, vì vậy tôi thực hiện nhiều bước này để tiết kiệm bộ nhớ trong tập lệnh PHP của mình.

Nhưng làm thế nào tôi có thể làm điều đó vì vậy nó chỉ cung cấp cho tôi một danh sách không có tên trùng lặp.

Ví dụ [1,"Michael Fox","2003-03-03,34,M,4545"]sẽ được trả lại nhưng không [2,"Michael Fox","1989-02-23,M,5633"]. Trường tên là quan trọng nhất và phải là duy nhất trong danh sách mỗi khi tôi thực hiện lựa chọn và nó phải ngẫu nhiên.

Tôi đã thử với GROUP BY name, bu thì nó cũng mong tôi có id và siêu dữ liệu trong GROUP BYhàm aggragate, nhưng tôi không muốn lọc chúng bằng cách nào đó.

Có ai biết cách tìm nạp nhiều cột nhưng chỉ làm một sự khác biệt trên một cột không?

Câu trả lời:


226

Để phân biệt chỉ trên một (hoặc n) cột:

select distinct on (name)
    name, col1, col2
from names

Điều này sẽ trả về bất kỳ hàng nào chứa tên. Nếu bạn muốn kiểm soát hàng nào sẽ được trả lại, bạn cần đặt hàng:

select distinct on (name)
    name, col1, col2
from names
order by name, col1

Sẽ trả về hàng đầu tiên khi được col1 sắp xếp.

distinct on:

CHỌN DISTINCT ON (biểu thức [, ...]) chỉ giữ hàng đầu tiên của mỗi tập hợp các hàng mà các biểu thức đã cho đánh giá là bằng nhau. Biểu thức DISTINCT ON được diễn giải bằng cách sử dụng các quy tắc tương tự như đối với ORDER BY (xem ở trên). Lưu ý rằng “hàng đầu tiên” của mỗi tập hợp là không thể đoán trước trừ khi ORDER BY được sử dụng để đảm bảo rằng hàng mong muốn xuất hiện trước.

(Các) biểu thức DISTINCT ON phải khớp với (các) biểu thức ORDER BY ngoài cùng bên trái. Mệnh đề ORDER BY thông thường sẽ chứa (các) biểu thức bổ sung xác định mức độ ưu tiên mong muốn của các hàng trong mỗi nhóm DISTINCT ON.


Bắt tốt để đặt hàng. Tôi đã không bao gồm nó vì họ đề cập đến việc muốn đặt hàng ngẫu nhiên, nhưng dù sao thì điều quan trọng là phải đề cập đến.
Craig Ringer

order by namebắt buộc? Nó sẽ tạo ra một kết quả khác với order by col1?
Elliot Chance

1
@elliot vâng namelà cần thiết. Kiểm tra distinct onhướng dẫn sử dụng.
Clodoaldo Neto

1
Tôi ước nhóm TSQL có thể cung cấp một cách hợp lý để thực hiện việc này.
JTW

Vui lòng thêm postgresql thích hợp tham khảo
Ogaga Uzoh

17

Có ai biết cách tìm nạp nhiều cột nhưng chỉ làm một sự khác biệt trên một cột không?

Bạn muốn các DISTINCT ONđiều khoản .

Bạn đã không cung cấp dữ liệu mẫu hoặc một truy vấn hoàn chỉnh nên tôi không có gì để hiển thị cho bạn. Bạn muốn viết một cái gì đó như:

SELECT DISTINCT ON (name) fields, id, name, metadata FROM the_table;

Điều này sẽ trả về một tập hợp các hàng không thể đoán trước (nhưng không phải "ngẫu nhiên"). Nếu bạn muốn làm cho nó có thể dự đoán được, hãy thêm ORDER BYmỗi câu trả lời của Clodaldo. Nếu bạn muốn làm cho nó thực sự ngẫu nhiên, bạn sẽ muốn ORDER BY random().


Chỉ cần lưu ý với điều khoản DISTINCT ON này, bạn chỉ có thể ĐẶT HÀNG BẰNG điều tương tự + hơn thế nữa. Vì vậy, nếu bạn nói DISTINCT ON (tên) bạn phải ĐẶT HÀNG BẰNG tên sau đó bạn muốn bất cứ điều gì khác. Hầu như không lý tưởng.
Kevin Parker

Kevin, bạn có thể chỉ cần sử dụng CTE hoặc truy vấn con trong TỪ và ĐẶT HÀNG BẰNG trong truy vấn bên ngoài
Craig Ringer

Có, và xem hiệu suất diễn ra ... Toàn bộ kết quả có thể có từ không gian chỉ mục sẽ được tìm kiếm. Nó biến những gì có thể là một truy vấn 10-20ms với chỉ mục phù hợp thành một 900ms chỉ vì posgres không thể xử lý một đơn hàng / khác biệt khác. Thậm chí không quan trọng thứ tự truy vấn bên ngoài là gì, nó sẽ sử dụng chỉ mục từ truy vấn con bên trong để tìm các kết quả phù hợp trước, sau đó sắp xếp lại. Vui lòng trả phí tư vấn cho các giải pháp thực sự cho các vấn đề của chúng tôi tại dba.stackexchange.com/questions/260852/…
Kevin Parker

4
SELECT NAME,MAX(ID) as ID,MAX(METADATA) as METADATA 
from SOMETABLE
GROUP BY NAME

2
Chỉ cần một lời cảnh báo: có thể không trả về giá trị ID hoặc giá trị siêu dữ liệu mà thuộc "với nhau"
a_horse_with_no_name

@Novum Không. Nó có nghĩa là nó lấy một giá trị id từ một trong các hàng của Michael và siêu dữ liệu từ một hàng khác khi nó được yêu cầu cho các giá trị tối đa của Michael.
Clodoaldo Neto

Vâng, nó phụ thuộc rất nhiều vào dữ liệu thực OP sử dụng, mà tôi hoàn toàn không biết. Bạn có thể cần sử dụng MIN hoặc bất cứ thứ gì. Vừa được chứng minh, làm thế nào bạn có thể bao gồm các trường không có trong một GROUP BYmệnh đề.
David Jashi

Đây không phải là một giải pháp tốt vì các giá trị khác nhau từ các hàng khác nhau sẽ bị trộn lẫn.
Elliot Chance
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.