Saya perlu mengambil semua baris dari tabel di mana 2 kolom digabungkan semuanya berbeda. Jadi saya ingin semua penjualan yang tidak memiliki penjualan lain yang terjadi pada hari yang sama dengan harga yang sama. Penjualan yang unik berdasarkan hari dan harga akan diperbarui ke status aktif.
Jadi saya berpikir:
UPDATE sales
SET status = 'ACTIVE'
WHERE id IN (SELECT DISTINCT (saleprice, saledate), id, count(id)
FROM sales
HAVING count = 1)
Tapi otakku sakit lebih jauh dari itu.
Jika Anda mengumpulkan jawaban sejauh ini, bersihkan dan tingkatkan, Anda akan sampai pada pertanyaan superior ini:
Yang jauh lebih cepat daripada keduanya. Nukes kinerja jawaban yang saat ini diterima oleh faktor 10 - 15 (dalam tes saya pada PostgreSQL 8.4 dan 9.1).
Namun ini masih jauh dari optimal. Gunakan
NOT EXISTS
semi-join (anti-) untuk kinerja yang lebih baik.EXISTS
adalah SQL standar, telah ada selamanya (setidaknya sejak PostgreSQL 7.2, jauh sebelum pertanyaan ini diajukan) dan sangat cocok dengan persyaratan yang disajikan:db <> biola di sini
Old SQL Fiddle
Kunci unik untuk mengidentifikasi baris
Jika Anda tidak memiliki kunci utama atau unik untuk tabel (
id
dalam contoh), Anda bisa mengganti dengan kolom sistemctid
untuk tujuan permintaan ini (tetapi tidak untuk beberapa tujuan lain):Setiap tabel harus memiliki kunci utama. Tambahkan satu jika Anda belum memilikinya. Saya menyarankan satu
serial
atau satuIDENTITY
kolom di Postgres 10+.Terkait:
Bagaimana ini lebih cepat?
Subquery di
EXISTS
anti-semi-join dapat berhenti mengevaluasi begitu dupe pertama ditemukan (tidak ada gunanya mencari lebih lanjut). Untuk tabel dasar dengan beberapa duplikat, ini hanya sedikit lebih efisien. Dengan banyak duplikat ini menjadi jauh lebih efisien.Kecualikan pembaruan kosong
Untuk baris yang sudah memiliki
status = 'ACTIVE'
pembaruan ini tidak akan mengubah apa pun, tetapi tetap memasukkan versi baris baru dengan biaya penuh (pengecualian kecil berlaku). Biasanya, Anda tidak menginginkan ini. TambahkanWHERE
kondisi lain seperti yang ditunjukkan di atas untuk menghindari ini dan membuatnya lebih cepat:Jika
status
didefinisikanNOT NULL
, Anda dapat menyederhanakan untuk:Jenis data kolom harus mendukung
<>
operator. Beberapa tipe sukajson
tidak. Lihat:Perbedaan yang halus dalam penanganan NULL
Kueri ini (tidak seperti jawaban yang saat ini diterima oleh Joel ) tidak memperlakukan nilai NULL sebagai sama. Dua baris berikut untuk
(saleprice, saledate)
dikualifikasikan sebagai "berbeda" (meskipun terlihat identik dengan mata manusia):Juga melewati dalam indeks unik dan hampir di tempat lain, karena nilai NULL tidak membandingkan sama dengan standar SQL. Lihat:
Otoh,
GROUP BY
,DISTINCT
atauDISTINCT ON ()
nilai-nilai memperlakukan NULL sebagai sama. Gunakan gaya permintaan yang sesuai tergantung pada apa yang ingin Anda capai. Anda masih dapat menggunakan kueri yang lebih cepat ini denganIS NOT DISTINCT FROM
alih - alih=
untuk setiap atau semua perbandingan untuk membuat NULL membandingkannya. Lebih:Jika semua kolom yang dibandingkan didefinisikan
NOT NULL
, tidak ada ruang untuk ketidaksepakatan.sumber
count(*)
adalah lebih efisien daripadacount(<expression>)
. Cobalah. Postgres memiliki implementasi yang lebih cepat untuk varian fungsi agregat ini. Mungkin Anda membingungkan Postgres dengan RDBMS lain?Masalah dengan kueri Anda adalah bahwa ketika menggunakan klausa GROUP BY (yang pada dasarnya Anda lakukan dengan menggunakan berbeda), Anda hanya dapat menggunakan kolom yang dikelompokkan berdasarkan atau fungsi agregat. Anda tidak dapat menggunakan id kolom karena ada nilai yang berpotensi berbeda. Dalam kasus Anda selalu ada hanya satu nilai karena klausa HAVING, tetapi sebagian besar RDBMS tidak cukup pintar untuk mengenalinya.
Namun ini harus bekerja (dan tidak perlu bergabung):
Anda juga bisa menggunakan MAX atau AVG alih-alih MIN, hanya penting untuk menggunakan fungsi yang mengembalikan nilai kolom jika hanya ada satu baris yang cocok.
sumber
Saya ingin memilih nilai yang berbeda dari satu kolom 'GrondOfLucht' tetapi mereka harus diurutkan dalam urutan seperti yang diberikan dalam kolom 'sortering'. Saya tidak bisa mendapatkan nilai yang berbeda hanya menggunakan satu kolom
Ini juga akan memberikan kolom 'sortering' dan karena 'GrondOfLucht' DAN 'sortering' tidak unik, hasilnya adalah SEMUA baris.
gunakan GROUP untuk memilih catatan 'GrondOfLucht' dalam urutan yang diberikan oleh 'sortering
sumber
Jika DBMS Anda tidak mendukung perbedaan dengan beberapa kolom seperti ini:
Multi pilih secara umum dapat dijalankan dengan aman sebagai berikut:
Karena ini dapat bekerja pada sebagian besar DBMS dan ini diharapkan lebih cepat daripada solusi kelompok karena Anda menghindari fungsi pengelompokan.
sumber