Saya perlu untuk mengambil semua baris dari tabel yang mana 2 kolom gabungan semua berbeda. Jadi saya ingin semua penjualan yang tidak memiliki penjualan yang terjadi pada hari yang sama untuk harga yang sama. Penjualan yang unik berdasarkan hari dan harga yang akan mendapatkan update ke status aktif.
Jadi saya'm berpikir:
UPDATE sales
SET status = 'ACTIVE'
WHERE id IN (SELECT DISTINCT (saleprice, saledate), id, count(id)
FROM sales
HAVING count = 1)
Tapi otak saya sakit akan lebih jauh dari itu.
SELECT DISTINCT a,b,c FROM t
adalah roughly setara dengan:
SELECT a,b,c FROM t GROUP BY a,b,c
It's merupakan ide yang baik untuk mendapatkan digunakan untuk KELOMPOK DENGAN sintaks, seperti's lebih kuat.
Untuk pertanyaan anda, saya'd lakukan seperti ini:
UPDATE sales
SET status='ACTIVE'
WHERE id IN
(
SELECT id
FROM sales S
INNER JOIN
(
SELECT saleprice, saledate
FROM sales
GROUP BY saleprice, saledate
HAVING COUNT(*) = 1
) T
ON S.saleprice=T.saleprice AND s.saledate=T.saledate
)
Jika anda menempatkan bersama-sama jawaban sejauh ini, membersihkan dan memperbaiki, anda akan tiba di segala query:
UPDATE sales
SET status = 'ACTIVE'
WHERE (saleprice, saledate) IN (
SELECT saleprice, saledate
FROM sales
GROUP BY saleprice, saledate
HAVING count(*) = 1
);
Yang banyak lebih cepat daripada salah satu dari mereka. Nuklir kinerja saat ini jawaban yang diterima oleh faktor 10 - 15 (dalam tes saya pada PostgreSQL 8.4 dan 9.1).
Tapi ini masih jauh dari optimal. Gunakan TIDAK ADA
(anti-)semi-bergabung untuk kinerja yang lebih baik. ADA
adalah standar SQL, telah sekitar selamanya (setidaknya sejak PostgreSQL 7.2, jauh sebelum pertanyaan ini diminta) dan cocok disajikan persyaratan sempurna:
UPDATE sales s
SET status = 'ACTIVE'
WHERE NOT EXISTS (
SELECT FROM sales s1 -- SELECT list can be empty for EXISTS
WHERE s.saleprice = s1.saleprice
AND s.saledate = s1.saledate
AND s.id <> s1.id -- except for row itself
)
AND s.status IS DISTINCT FROM 'ACTIVE'; -- avoid empty updates. see below
db<>biola di sini Old SQL Biola
Jika anda don't memiliki primary atau unique key untuk tabel (id
dalam contoh), anda dapat mengganti dengan sistem kolom ctid
untuk tujuan ini query (tetapi tidak untuk beberapa tujuan lain):
AND s1.ctid <> s.ctid
Setiap tabel harus memiliki primary key. Tambahkan satu jika anda tidak't memiliki satu, belum. Saya sarankan serial
atau IDENTITAS
kolom di Postgres 10+.
Terkait:
Subquery dalam ADA
anti-semi-bergabung dapat berhenti mengevaluasi sesegera pertama dupe ditemukan (tidak ada gunanya melihat lebih jauh). Untuk sebuah meja dengan beberapa duplikat ini hanya sedikit lebih efisien. Dengan banyak duplikat ini menjadi cara lebih efisien.
Untuk baris yang sudah memiliki status = 'AKTIF'
update ini tidak akan mengubah apa pun, tapi masih menyisipkan baris baru versi penuh biaya (minor pengecualian berlaku). Biasanya, anda tidak ingin ini. Tambahkan lagi di MANA
kondisi seperti yang ditunjukkan di atas untuk menghindari hal ini dan membuatnya bahkan lebih cepat:
Jika status
didefinisikan NOT NULL
, anda dapat menyederhanakan untuk:
AND status <> 'ACTIVE';
Query ini (tidak seperti saat ini jawaban yang diterima oleh Joel) tidak memperlakukan nilai-nilai NULL sama. Dua baris berikut untuk (saleprice, saledate)
akan memenuhi syarat sebagai "yang berbeda" (meskipun tampak identik dengan mata manusia):
(123, NULL)
(123, NULL)
Juga lewat di indeks unik dan hampir di mana pun, karena nilai-nilai NULL tidak membandingkan sama sesuai dengan standar SQL. Lihat:
OTOH, GROUP BY
, BERBEDA
atau BERBEDA PADA ()
mengobati NULL nilai-nilai yang sama. Menggunakan query yang sesuai gaya tergantung pada apa yang ingin anda capai. Anda masih dapat menggunakan ini lebih cepat query dengan INI TIDAK BERBEDA DARI
bukan =
untuk setiap atau semua perbandingan untuk membuat NULL membandingkan sama. Lebih lanjut:
Jika semua kolom yang dibandingkan didefinisikan NOT NULL
, tidak ada ruang untuk perbedaan pendapat.
Masalah dengan query anda adalah bahwa ketika menggunakan GROUP BY clause (yang pada dasarnya dilakukan dengan menggunakan distinct) anda hanya dapat menggunakan kolom yang anda grup atau fungsi agregat. Anda tidak dapat menggunakan kolom id karena ada potensi nilai-nilai yang berbeda. Dalam kasus anda hanya selalu ada satu nilai karena MEMILIKI klausa, tetapi sebagian besar RDBMS tidak cukup pintar untuk menyadari bahwa.
Ini harus bekerja namun (dan doesn't perlu bergabung):
UPDATE sales
SET status='ACTIVE'
WHERE id IN (
SELECT MIN(id) FROM sales
GROUP BY saleprice, saledate
HAVING COUNT(id) = 1
)
Anda juga bisa menggunakan MAX atau AVG bukan MIN, itu hanya penting untuk menggunakan sebuah fungsi yang mengembalikan nilai dari kolom jika hanya ada satu baris pencocokan.
Saya ingin memilih nilai-nilai yang berbeda dari satu kolom 'GrondOfLucht' tapi mereka harus diurutkan dalam urutan seperti yang diberikan dalam kolom 'sortering'. Saya tidak bisa mendapatkan nilai yang berbeda hanya menggunakan satu kolom
Select distinct GrondOfLucht,sortering
from CorWijzeVanAanleg
order by sortering
Hal ini juga akan memberikan kolom 'sortering' dan karena 'GrondOfLucht' DAN 'sortering' adalah tidak unik, hasilnya akan SEMUA baris.
gunakan GRUP untuk memilih catatan 'GrondOfLucht' dalam urutan yang diberikan oleh 'sortering
SELECT GrondOfLucht
FROM dbo.CorWijzeVanAanleg
GROUP BY GrondOfLucht, sortering
ORDER BY MIN(sortering)
Jika anda DBMS doesn't dukungan berbeda dengan beberapa kolom seperti ini:
select distinct(col1, col2) from table
Multi-pilih secara umum dapat dilaksanakan dengan aman sebagai berikut:
select distinct * from (select col1, col2 from table ) as x
Karena hal ini dapat bekerja pada sebagian besar DBMS dan ini diharapkan akan lebih cepat daripada kelompok dengan solusi seperti yang anda menghindari pengelompokan fungsi.