Có, toán tử chồng chéo &&
có thể sử dụng chỉ mục GIN trên mảng
. Rất hữu ích cho các truy vấn này để tìm các hàng có một người nhất định (1
) giữa một loạt các tác nhân:
SELECT * FROM eg_assoc WHERE actors && '{1}'::int[]
Tuy nhiên , logic truy vấn của bạn là ngược lại, tìm kiếm tất cả những người được liệt kê trong các mảng trong eg_assoc
. Chỉ số GIN là không giúp đỡ ở đây. Chúng tôi chỉ cần chỉ mục btree của PK person.id
.
Truy vấn thích hợp
Khái niệm cơ bản:
Các truy vấn sau bảo tồn các mảng ban đầu chính xác như đã cho , bao gồm các phần tử có thể trùng lặp và thứ tự ban đầu của các phần tử. Hoạt động cho mảng 1 chiều . Các kích thước bổ sung được gấp lại thành một chiều duy nhất. Việc bảo toàn nhiều thứ nguyên phức tạp hơn (nhưng hoàn toàn có thể):
WITH ORDINALITY
trong Postgres 9.4 trở lên
SELECT aid, actors
, ARRAY(SELECT name
FROM unnest(e.actors) WITH ORDINALITY a(id, i)
JOIN eg_person p USING (id)
ORDER BY a.i) AS act_names
, benefactors
, ARRAY(SELECT name
FROM unnest(e.benefactors) WITH ORDINALITY b(id, i)
JOIN eg_person USING (id)
ORDER BY b.i) AS ben_names
FROM eg_assoc e;
LATERAL
truy vấn
Đối với PostgreSQL 9.3+ .
SELECT e.aid, e.actors, a.act_names, e.benefactors, b.ben_names
FROM eg_assoc e
, LATERAL (
SELECT ARRAY( SELECT name
FROM generate_subscripts(e.actors, 1) i
JOIN eg_person p ON p.id = e.actors[i]
ORDER BY i)
) a(act_names)
, LATERAL (
SELECT ARRAY( SELECT name
FROM generate_subscripts(e.benefactors, 1) i
JOIN eg_person p ON p.id = e.benefactors[i]
ORDER BY i)
) b(ben_names);
db <> fiddle tại đây
với một số biến thể.
sqlfiddle
cũ
Chi tiết tinh tế:Nếu một người không được tìm thấy, nó chỉ bị rơi. Cả hai truy vấn này đều tạo ra một mảng trống ( '{}'
) nếu không tìm thấy người nào cho toàn bộ mảng. Các kiểu truy vấn khác sẽ trả về NULL
. Tôi đã thêm các biến thể vào fiddle.
Truy vấn phụ có liên quan
Đối với Postgres 8.4+ (trong đó generate_subsrcipts()
đã được giới thiệu):
SELECT aid, actors
, ARRAY(SELECT name
FROM generate_subscripts(e.actors, 1) i
JOIN eg_person p ON p.id = e.actors[i]
ORDER BY i) AS act_names
, benefactors
, ARRAY(SELECT name
FROM generate_subscripts(e.benefactors, 1) i
JOIN eg_person p ON p.id = e.benefactors[i]
ORDER BY i) AS ben_names
FROM eg_assoc e;
Vẫn có thể hoạt động tốt nhất, ngay cả trong Postgres 9.3.
ARRAY
phương thức khởi tạo
nhanh hơn array_agg()
. Xem:
Truy vấn không thành công của bạn
truy vấn được cung cấp bởi @a_horse dường như để thực hiện công việc, nhưng nó không đáng tin cậy, gây hiểu lầm, có khả năng không chính xác và không cần thiết phải trả giá đắt.
-
Tham gia chéo proxy vì hai liên kết không liên quan. Một mẫu chống lén lút. Xem:
Đã sửa bề ngoài với
DISTINCT
trongarray_agg()
để loại bỏ các bản sao được tạo ra, nhưng đó thực sự là việc tô son cho một con lợn. Nó cũng loại bỏ các bản sao trong bản gốc bởi vì không thể phân biệt được sự khác biệt vào thời điểm này - điều này có thể không chính xác. -
Biểu thức
a_person.id = any(eg_assoc.actors)
hoạt động , nhưng loại bỏ các bản sao từ kết quả (xảy ra hai lần trong truy vấn này), sai trừ khi được chỉ định. -
Thứ tự ban đầu của các phần tử mảng không được giữ nguyên . Điều này là khó khăn nói chung. Nhưng nó trở nên trầm trọng hơn trong truy vấn này, bởi vì các tác nhân và nhà hảo tâm được nhân lên và phân biệt một lần nữa, điều này đảm bảo đặt hàng tùy ý.
-
Không có bí danh cột nào trong
SELECT
bên ngoài dẫn đến các tên cột trùng lặp, điều này khiến một số ứng dụng khách bị lỗi (không hoạt động trong fiddle mà không có bí danh). -
min(actors)
vàmin(benefactors)
Vô dụng. Thông thường người ta sẽ chỉ thêm các cột vàoGROUP BY
thay vì giả-tập hợp chúng. Nhưngeg_assoc.aid
vẫn là cột PK (bao gồm toàn bộ bảng trongGROUP BY
), vì vậy điều đó thậm chí không cần thiết. Chỉ làactors, benefactors
.
Tổng hợp toàn bộ kết quả là lãng phí thời gian và công sức để bắt đầu. Sử dụng truy vấn thông minh hơn mà không nhân các hàng cơ sở, sau đó bạn không phải tổng hợp chúng lại.