Şimdiye kadar cevapları bir araya getirirseniz, temizleyip geliştirirseniz, bu üstün sorguya ulaşırsınız:
UPDATE sales
SET status = 'ACTIVE'
WHERE (saleprice, saledate) IN (
SELECT saleprice, saledate
FROM sales
GROUP BY saleprice, saledate
HAVING count(*) = 1
);
Hangisi çok daha hızlı. Şu anda kabul edilen cevabın performansını 10-15 faktörü (PostgreSQL 8.4 ve 9.1'deki testlerimde) yerine getirir.
Ama bu hala optimal olmaktan uzak. KullanınNOT EXISTSDaha da iyi performans için (anti-) yarı birleştirme . EXISTSstandart SQL'dir, sonsuza kadar olmuştur (en azından PostgreSQL 7.2'den bu soru sorulmadan çok önce) ve sunulan gereksinimlere mükemmel şekilde uyar:
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 <> keman burada
Eski SQL Keman
Satırı tanımlamak için benzersiz anahtar
Tablo için birincil veya benzersiz bir anahtarınız yoksa (id örnekte), ctidbu sorgunun amacına yönelik olarak sistem sütununu kullanabilirsiniz (ancak başka bir amaçla kullanamazsınız):
AND s1.ctid <> s.ctid
Her tablonun birincil anahtarı olmalıdır. Henüz sahip değilseniz bir tane ekleyin. Bir serialveya birIDENTITYPostgres 10 + ' sütun .
İlişkili:
Bu nasıl daha hızlı?
EXISTSAnti-semi- join'deki alt sorgu ilk dupe bulunur bulunmaz değerlendirmeyi durdurabilir (daha fazla bakmanın anlamı yoktur). Birkaç kopya içeren bir temel tablo için bu sadece biraz daha verimlidir. Yinelenenler dolu bu hale yolu daha verimli.
Boş güncellemeleri hariç tut
status = 'ACTIVE'Bu güncelleştirmeyi zaten içeren satırlar için hiçbir şey değişmez, ancak yine de tam maliyetle yeni bir satır sürümü ekler (küçük istisnalar geçerlidir). Normalde bunu istemezsiniz. Başka birtane ekleWHERE kaçınmak ve daha da hızlı hale getirmek için yukarıda gösterildiği gibi koşul :
Eğer statustanımlanır NOT NULLşunları yapmanız kolaylaştırabilirsiniz:
AND status <> 'ACTIVE';
Sütunun veri türü <>operatörü desteklemelidir . Bazı türler jsonyok. Görmek:
NULL kullanımda küçük fark
Bu sorgu ( Joel tarafından şu anda kabul edilen cevabın aksine ) NULL değerlere eşit muamele etmemektedir. Aşağıdaki iki satır (saleprice, saledate)"farklı" olarak nitelendirilir (insan gözüyle aynı görünmesine rağmen):
(123, NULL)
(123, NULL)
Benzersiz bir dizinde ve hemen hemen her yerde de geçer, çünkü NULL değerleri SQL standardına göre eşit değildir. Görmek:
OTOH, GROUP BY, DISTINCTya da DISTINCT ON ()eşit olarak muamele NULL değerleri. Neyi başarmak istediğinize bağlı olarak uygun bir sorgu stili kullanın. Bu daha hızlı sorguyu kullanmak IS NOT DISTINCT FROMyerine=NULL karşılaştırmayı eşitlemek için herhangi bir veya tüm karşılaştırmalar . Daha:
Karşılaştırılan tüm sütunlar tanımlanmışsa NOT NULL, anlaşmaya yer yoktur.