Jika saya menggunakan array_agg
untuk mengumpulkan nama, saya mendapatkan nama saya dipisahkan dengan koma, tetapi jika ada null
nilai, null itu juga diambil sebagai nama dalam agregat. Sebagai contoh :
SELECT g.id,
array_agg(CASE WHEN g.canonical = 'Y' THEN g.users ELSE NULL END) canonical_users,
array_agg(CASE WHEN g.canonical = 'N' THEN g.users ELSE NULL END) non_canonical_users
FROM groups g
GROUP BY g.id;
itu kembali ,Larry,Phil
bukan hanya Larry,Phil
(di 9.1.2 saya, itu menunjukkan NULL,Larry,Phil
). seperti di biola ini
Sebaliknya, jika saya menggunakan string_agg()
, ini hanya menunjukkan nama (tanpa koma kosong atau null) seperti di sini
Masalahnya adalah saya telah Postgres 8.4
menginstal di server, dan string_agg()
tidak berfungsi di sana. Apakah ada cara untuk membuat array_agg berfungsi mirip dengan string_agg ()?
Jawaban:
SQL Fiddle
select id, (select array_agg(a) from unnest(canonical_users) a where a is not null) canonical_users, (select array_agg(a) from unnest(non_canonical_users) a where a is not null) non_canonical_users from ( SELECT g.id, array_agg(CASE WHEN g.canonical = 'Y' THEN g.users ELSE NULL END) canonical_users, array_agg(CASE WHEN g.canonical = 'N' THEN g.users ELSE NULL END) non_canonical_users FROM groups g GROUP BY g.id ) s
Atau, lebih sederhana dan mungkin lebih murah, menggunakan
array_to_string
yang menghilangkan nulls:SELECT g.id, array_to_string( array_agg(CASE WHEN g.canonical = 'Y' THEN g.users ELSE NULL END) , ',' ) canonical_users, array_to_string( array_agg(CASE WHEN g.canonical = 'N' THEN g.users ELSE NULL END) , ',' ) non_canonical_users FROM groups g GROUP BY g.id
SQL Fiddle
sumber
array_to_string(array_agg(...))
Anda mungkin juga menggunakanstring_agg
.Dengan postgresql-9.3 seseorang dapat melakukan ini;
SELECT g.id, array_remove(array_agg(CASE WHEN g.canonical = 'Y' THEN g.users ELSE NULL END), NULL) canonical_users, array_remove(array_agg(CASE WHEN g.canonical = 'N' THEN g.users ELSE NULL END), NULL) non_canonical_users FROM groups g GROUP BY g.id;
Perbarui : dengan postgresql-9.4;
SELECT g.id, array_agg(g.users) FILTER (WHERE g.canonical = 'Y') canonical_users, array_agg(g.users) FILTER (WHERE g.canonical = 'N') non_canonical_users FROM groups g GROUP BY g.id;
sumber
Jika Anda mencari jawaban modern untuk pertanyaan umum tentang cara menghapus NULL dari array , itu adalah:
Saya secara khusus ingin tahu tentang kinerja dan ingin membandingkannya dengan alternatif terbaik:
CREATE OR REPLACE FUNCTION strip_nulls( IN array_in ANYARRAY ) RETURNS anyarray AS ' SELECT array_agg(a) FROM unnest(array_in) a WHERE a IS NOT NULL ; ' LANGUAGE sql ;
Melakukan uji pgbench membuktikan (dengan keyakinan tinggi) bahwa array_remove () sedikit lebih dari dua kali lebih cepat . Saya melakukan pengujian pada angka presisi ganda dengan berbagai ukuran larik (10, 100, dan 1000 elemen) dan NULL acak di antaranya.
Perlu juga dicatat bahwa ini dapat digunakan untuk menghapus blank (''! = NULL). Tetapi parameter kedua menerima
anyelement
, dan karena kemungkinan besar mereka Anda akan menunjukkan kosong dengan literal string, pastikan untuk mentransmisikannya ke formulir yang Anda inginkan, biasanya non-array.Sebagai contoh:
select array_remove(array['abc', ''], ''::text);
Jika kamu mencoba:
select array_remove(array['abc', ''], '');
itu akan berasumsi bahwa '' adalah TEXT [] (array) dan akan menampilkan kesalahan ini:
sumber
Dalam menyelesaikan pertanyaan umum untuk menghapus null dari agregat array, ada dua cara utama untuk mengatasi masalah: melakukan array_agg (tidak terkendali (array_agg (x)) atau membuat agregat kustom.
Yang pertama adalah dari bentuk yang ditunjukkan di atas :
SELECT array_agg(u) FROM ( SELECT unnest( array_agg(v) ) as u FROM x ) un WHERE u IS NOT NULL;
Kedua:
/* With reference to http://ejrh.wordpress.com/2011/09/27/denormalisation-aggregate-function-for-postgresql/ */ CREATE OR REPLACE FUNCTION fn_array_agg_notnull ( a anyarray , b anyelement ) RETURNS ANYARRAY AS $$ BEGIN IF b IS NOT NULL THEN a := array_append(a, b); END IF; RETURN a; END; $$ IMMUTABLE LANGUAGE 'plpgsql'; CREATE AGGREGATE array_agg_notnull(ANYELEMENT) ( SFUNC = fn_array_agg_notnull, STYPE = ANYARRAY, INITCOND = '{}' );
Memanggil yang kedua (secara alami) terlihat sedikit lebih baik daripada yang pertama:
sumber
Saya menambahkan ini meskipun utas ini cukup tua, tetapi saya mengalami trik rapi ini yang bekerja cukup baik pada array kecil. Ini berjalan di Postgres 8.4+ tanpa perpustakaan atau fungsi tambahan.
The
array_to_string()
Metode sebenarnya menghilangkan nulls.sumber
Seperti yang telah disarankan dalam komentar, Anda dapat menulis fungsi untuk menggantikan null dalam array, namun seperti yang juga ditunjukkan di utas yang ditautkan di komentar, jenis ini mengalahkan efisiensi fungsi agregat jika Anda harus membuat agregat. , pisahkan, lalu kumpulkan lagi.
Saya pikir menjaga null dalam array hanyalah fitur (mungkin tidak diinginkan) dari Array_Agg. Anda dapat menggunakan subkueri untuk menghindari ini:
SELECT COALESCE(y.ID, n.ID) ID, y.Users, n.Users FROM ( SELECT g.ID, ARRAY_AGG(g.Users) AS Users FROM Groups g WHERE g.Canonical = 'Y' GROUP BY g.ID ) y FULL JOIN ( SELECT g.ID, ARRAY_AGG(g.Users) AS Users FROM Groups g WHERE g.Canonical = 'N' GROUP BY g.ID ) n ON n.ID = y.ID
SQL FIDDLE
sumber
Ini sangat sederhana, pertama-tama buat operator - (minus) baru untuk teks [] :
CREATE OR REPLACE FUNCTION diff_elements_text ( text[], text[] ) RETURNS text[] as $$ SELECT array_agg(DISTINCT new_arr.elem) FROM unnest($1) as new_arr(elem) LEFT OUTER JOIN unnest($2) as old_arr(elem) ON new_arr.elem = old_arr.elem WHERE old_arr.elem IS NULL $$ LANGUAGE SQL IMMUTABLE; CREATE OPERATOR - ( PROCEDURE = diff_elements_text, leftarg = text[], rightarg = text[] );
Dan cukup kurangi array [null]:
select array_agg(x)-array[''] from ( select 'Y' x union all select null union all select 'N' union all select '' ) x;
Itu saja:
{Y, T}
sumber
array_agg(x) FILTER (WHERE x is not null)
tampaknya jauh lebih mudah: dbfiddle.uk/… dan Anda tidak benar-benar membutuhkan fungsi Anda sendiri, Anda cukup menggunakanarray_remove()
dbfiddle.uk/…Pertanyaan yang lebih besar adalah mengapa menarik semua kombo pengguna / grup sekaligus. Dijamin UI Anda tidak dapat menangani semua data itu. Menambahkan paging ke data yang terlalu besar juga merupakan ide yang buruk. Minta pengguna Anda untuk memfilter kumpulan sebelum mereka melihat data. Pastikan kumpulan opsi GABUNG Anda ada dalam daftar sehingga mereka dapat memfilter kinerja jika mereka mau. Terkadang 2 kueri membuat pengguna lebih bahagia jika keduanya cepat.
sumber