Önemli: Lütfen MySQL 8+ sürümüne geçmeyi düşünün ve tanımlı ve belgelenmiş ROW_NUMBER () işlevini kullanın ve MySQL'in özelliklerle sınırlı eski bir sürümüne bağlı eski korsanlardan kurtulun
Şimdi bu hacklerden biri:
Burada çoğunlukla sorgu içi değişkenleri kullanan cevaplar / hepsi belgelerin söylediği gerçeğini göz ardı ediyor gibi görünüyor (açıklama):
Yukarıdan aşağıya doğru sırayla değerlendirilmekte olan SELECT listesindeki öğelere güvenmeyin. Bir SELECT öğesinde değişken atama ve bunları başka bir SELECT öğesinde kullanma
Bu nedenle, yanlış cevabı atma riski vardır, çünkü genellikle
select
(row number variable that uses partition variable),
(assign partition variable)
Bunlar aşağıdan yukarıya değerlendirilirse, satır numarası çalışmayı durduracaktır (bölüm yok)
Bu nedenle, garantili bir yürütme sırasına sahip bir şey kullanmamız gerekiyor. NE ZAMAN DURUMDA GİRİN:
SELECT
t.*,
@r := CASE
WHEN col = @prevcol THEN @r + 1
WHEN (@prevcol := col) = null THEN null
ELSE 1 END AS rn
FROM
t,
(SELECT @r := 0, @prevcol := null) x
ORDER BY col
Anahat ld olarak, prevcol atama sırası önemlidir - biz geçerli satırdan bir değer atamadan önce prevcol geçerli satırın değeri ile karşılaştırılmalıdır (aksi takdirde önceki satırın col değeri değil, geçerli satırların col değeri olurdu) .
Bunun nasıl birbirine uyduğu aşağıda açıklanmıştır:
İlk NE ZAMAN değerlendirilir. Bu satırın sütunu önceki satırın sütunu ile aynıysa, @r artırılır ve CASE'den döndürülür. Bu dönüş led değerleri @r. MySQL'in bir özelliği, atamanın @r'ye atanan şeyin yeni değerini sonuç satırlarına döndürmesidir.
Sonuç kümesindeki ilk satır için @prevcol null (alt sorguda null olarak başlatılır), bu nedenle bu yüklem yanlıştır. Bu ilk yüklem ayrıca col her değiştiğinde false değerini döndürür (geçerli satır önceki satırdan farklıdır). Bu, ikinci NE ZAMAN değerlendirilmesine neden olur.
İkinci WHEN yüklemi her zaman yanlıştır ve yalnızca @prevcol'e yeni bir değer atamak için var olur. Bu satırın col değeri önceki satırın col'sinden farklı olduğu için (bunu biliyoruz çünkü aynı olsaydı, ilk NE ZAMAN kullanılırsa), bir dahaki sefere test için yeni değeri atamamız gerekir. Ödev yapıldığından ve ödevin sonucu null ile karşılaştırıldığından ve null ile eşitlenmiş herhangi bir şey yanlış olduğundan, bu yüklem her zaman yanlıştır. Ancak en azından değerlendirmek, col değerini bu satırdan tutma görevini yaptı, böylece bir sonraki satırın col değerine göre değerlendirilebilir
İkinci NE ZAMAN yanlış olduğu için, (col) ile bölümlediğimiz sütunun değiştiği durumlarda, numarayı 1'den yeniden başlatarak @r için yeni bir değer veren ELSE'dir.
Bu durumun şu olduğu bir duruma geliyoruz:
SELECT
t.*,
ROW_NUMBER() OVER(PARTITION BY pcol1, pcol2, ... pcolX ORDER BY ocol1, ocol2, ... ocolX) rn
FROM
t
Genel forma sahiptir:
SELECT
t.*,
@r := CASE
WHEN col1 = @pcol1 AND col2 = @pcol2 AND ... AND colX = @pcolX THEN @r + 1
WHEN (@pcol1 := pcol1) = null OR (@pcol2 := col2) = null OR ... OR (@pcolX := colX) = null THEN null
ELSE 1
END AS rn
FROM
t,
(SELECT @r := 0, @pcol1 := null, @pcol2 := null, ..., @pcolX := null) x
ORDER BY pcol1, pcol2, ..., pcolX, ocol1, ocol2, ..., ocolX
Dipnotlar:
Pcol içindeki p "bölüm" anlamına gelir, ocol içindeki o "düzen" anlamına gelir - genel formda görsel karmaşayı azaltmak için değişken adından "prev" i düşürdüm
Çevresindeki parantezler (@pcolX := colX) = null
önemlidir. Onlar olmadan @pcolX'e null atayacaksınız ve işler artık çalışmıyor
Önceki sütun karşılaştırmasının çalışması için sonuç kümesinin bölüm sütunları tarafından da sıralanması gerektiği bir uzlaşmadır. Böylece rownumber'ınızı bir sütuna göre sıralayamazsınız, ancak sonuç kümeniz diğerine sıralanabilir. Bunu alt sorgular ile çözebilirsiniz, ancak belgelerin LIMIT kullanılmadığı sürece alt sorgu sırasının göz ardı edilebileceğini ve bu etkinin verim
Yöntemin işe yaradığını test etmenin ötesine geçmedim, ancak ikinci NE ZAMAN'daki tahminlerin ortadan kaldırılacağı riski varsa (null ile karşılaştırılan herhangi bir şey null / false, öyleyse neden ödevi çalıştırmıyorsunuz) ve yürütülmedi , durur. Bu benim tecrübelerime göre görünmüyor, ancak yorumları memnuniyetle kabul edip makul bir şekilde ortaya çıkabilirse çözüm önereceğim
@PcolX oluşturan null'ları, @pcolX değişkenlerini oluşturan alt sorguda, sütunlarınızın gerçek türlerine dönüştürmek akıllıca olabilir: select @pcol1 := CAST(null as INT), @pcol2 := CAST(null as DATE)
greatest-n-per-group
Sizi benzer sorulara yönlendirmek için etiketlendi .