Birden fazla sütun üzerinde DISTINCT'i nasıl SELECT edebilirim (veya edebilir miyim)?
Birleştirilmiş 2 sütunun hepsinin farklı olduğu bir tablodan tüm satırları almam gerekiyor. Yani aynı gün aynı fiyata gerçekleşen başka bir satış olmayan tüm satışları istiyorum. Gün ve fiyat bazında benzersiz olan satışlar aktif duruma güncellenecek.
Düşünüyorum da:
UPDATE sales
SET status = 'ACTIVE'
WHERE id IN (SELECT DISTINCT (saleprice, saledate), id, count(id)
FROM sales
HAVING count = 1)
Ama bundan daha ileri gitmek beynimi acıtıyor.
382
3
ile eşdeğerdir:
Daha güçlü olduğu için GROUP BY sözdizimine alışmak iyi bir fikirdir.
Sorgunuz için ben olsam şöyle yapardım:
Şimdiye kadarki cevapları bir araya getirir, temizler ve geliştirirseniz, bu üstün sorguya ulaşırsınız:
Bu da ikisinden de çok daha hızlı. Şu anda kabul edilen cevabın performansını 10 - 15 kat artırıyor (PostgreSQL 8.4 ve 9.1 üzerinde yaptığım testlerde).
Ancak bu hala optimal olmaktan uzaktır. Daha iyi performans için bir
NOT EXISTS
(anti-)semi-join kullanın. EXISTS` standart SQL'dir, uzun zamandır kullanılmaktadır (en azından PostgreSQL 7.2'den beri, bu soru sorulmadan çok önce) ve sunulan gereksinimlere mükemmel şekilde uymaktadır:dbfiddle here Old SQL Fiddle
Satırı tanımlamak için benzersiz anahtar
Tablo için birincil veya benzersiz bir anahtarınız yoksa (örnekte
id
), bu sorgunun amacı içinctid
sistem sütunu ile değiştirebilirsiniz (ancak başka amaçlar için değil):Her tablonun bir birincil anahtarı olmalıdır. Eğer henüz yoksa bir tane ekleyin. Postgres 10+'da bir
serial
veyaIDENTITY
sütunu öneririm.İlgili:
Bu nasıl daha hızlı?
EXISTS` anti-semi-join'deki alt sorgu, ilk dupe bulunur bulunmaz değerlendirmeyi durdurabilir (daha fazla aramanın bir anlamı yoktur). Az sayıda kopyası olan bir temel tablo için bu yalnızca biraz daha verimlidir. Çok sayıda kopya ile bu çok daha verimli hale gelir.
Boş güncellemeleri hariç tut
Halihazırda
status = 'ACTIVE'
olan satırlar için bu güncelleme hiçbir şeyi değiştirmez, ancak yine de tam maliyetle yeni bir satır sürümü ekler (küçük istisnalar geçerlidir). Normalde bunu istemezsiniz. Bunu önlemek ve daha da hızlı hale getirmek için yukarıda gösterildiği gibi başka birWHERE
koşulu ekleyin:Eğer
status
NOT NULL
olarak tanımlanmışsa, şu şekilde basitleştirebilirsiniz:NULL işlemede ince fark
Bu sorgu (Joel tarafından şu anda kabul edilen yanıtın aksine) NULL değerleri eşit olarak değerlendirmez. (saleprice, saledate)` için aşağıdaki iki satır "distinct" olarak nitelendirilebilir (insan gözüne aynı görünmesine rağmen):
Ayrıca, SQL standardına göre NULL değerler eşit olarak karşılaştırılmadığından, benzersiz bir dizinde ve hemen hemen her yerde geçer. Bkz:
Buna karşın,
GROUP BY
,DISTINCT
veyaDISTINCT ON ()
NULL değerleri eşit olarak ele alır. Ne elde etmek istediğinize bağlı olarak uygun bir sorgu stili kullanın. NULL karşılaştırmasını eşit yapmak için herhangi bir veya tüm karşılaştırmalar için=
yerineIS NOT DISTINCT FROM
ile bu daha hızlı sorguyu kullanmaya devam edebilirsiniz. Daha fazlası:Karşılaştırılan tüm sütunlar
NOT NULL
olarak tanımlanmışsa, anlaşmazlığa yer yoktur.Sorgunuzla ilgili sorun, bir GROUP BY cümlesi kullanırken (aslında distinct kullanarak yapıyorsunuz) yalnızca grupladığınız sütunları veya toplama işlevlerini kullanabilmenizdir. İd sütununu kullanamazsınız çünkü potansiyel olarak farklı değerler vardır. Sizin durumunuzda HAVING cümlesi nedeniyle her zaman yalnızca bir değer vardır, ancak çoğu RDBMS bunu fark edecek kadar akıllı değildir.
Ancak bu işe yaramalıdır (ve birleştirme gerektirmez):
MIN yerine MAX veya AVG de kullanabilirsiniz, sadece tek bir eşleşen satır varsa sütunun değerini döndüren bir fonksiyon kullanmak önemlidir.