Ş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 EXISTS
Daha da iyi performans için (anti-) yarı birleştirme . EXISTS
standart 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), ctid
bu 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 serial
veya birIDENTITY
Postgres 10 + ' sütun .
İlişkili:
Bu nasıl daha hızlı?
EXISTS
Anti-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 status
tanımlanır NOT NULL
şunları yapmanız kolaylaştırabilirsiniz:
AND status <> 'ACTIVE';
Sütunun veri türü <>
operatörü desteklemelidir . Bazı türler json
yok. 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
, DISTINCT
ya 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 FROM
yerine=
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.