2016-09-21 3 views
0

Ich habe dieses Stück SQL-Code, der die row_number auf einige Werte in einer Tabelle __working Basis findet, die in einer Lookup-Tabelle verbindet __Evalrow_number mit Wert Partition Ändern

;WITH r 
AS (
    select 

    w.uid, 
    t.TypeId, 
    --weight 
    ROW_NUMBER() OVER (PARTITION BY w.uid ORDER BY DIFFERENCE(t.val1, w.val1) + DIFFERENCE(t.val2, w.val2) + DIFFERENCE(t.val3, w.val3) + DIFFERENCE(t.val4, w.val4) DESC) as Score 
    ,w.account 

    from __Working w 
     join __eval t on w.val1 like t.val1 and IsNull(w.val4, '') like t.val4 and IsNull(w.val2, '') like t.val2 and IsNull(w.val3, '') like t.val3 

) 

select * from r  where r.account = 1 and score = 1 

dies liefert eine TypeId = 1

aber wenn ich es wie dies

;WITH r 
    AS (
     select 

     w.uid, 
     t.TypeId, 
     --weight 
     ROW_NUMBER() OVER (PARTITION BY w.uid ORDER BY DIFFERENCE(t.val1, w.val1) + DIFFERENCE(t.val2, w.val2) + DIFFERENCE(t.val3, w.val3) + DIFFERENCE(t.val4, w.val4) DESC) as Score 
     ,w.account 

     from __Working w 
      join __eval t on w.val1 like t.val1 and IsNull(w.val4, '') like t.val4 and IsNull(w.val2, '') like t.val2 and IsNull(w.val3, '') like t.val3 
      where r.account = 1 
    ) 

    select * from r  where r.account = 1 and score = 1 

schreiben gibt es TypeId = 2. ich würde erwarten, dass, wenn ich mehrere UIDs über verschiedene Konten in __working hatte, aber ich weiß nicht. Was fehlt mir hier?

+0

Warum Filter auf R.account im CTE und wieder int er wählen? Filterung innerhalb des CTE wird Ihre ROW_NUMBER() ändern – scsimon

+0

Gordon antwortete richtig. Das einzige, was zu beachten ist, ist, dass DIFFERENCE (t.val1, NULL) NULL wäre. Und NULL + 1 ist NULL. Wenn also nur 1 Ihrer Spalten in den DIFFERENCE-Funktionen null sein kann, wird Ihre gesamte Reihenfolge zu NULL. Ich würde vermuten, dass Sie einige NULL-Handhabung tun wollen, aber nicht sicher von Ihrem Anwendungsfall – Matt

+0

yeah, val1 ist ein nicht-Nullable-Feld, so dass die Nullprüfung nicht benötigt, aber danke – nikolifish

Antwort

2

Oh, das ist eine seltsame Art von instabilen Arten. Ihr row_number() Ausdruck ist:

ROW_NUMBER() OVER (PARTITION BY w.uid 
        ORDER BY DIFFERENCE(t.val1, w.val1) + 
           DIFFERENCE(t.val2, w.val2) + 
           DIFFERENCE(t.val3, w.val3) + 
           DIFFERENCE(t.val4, w.val4) DESC 
        ) as Score 

Das Problem besteht darin, dass mehrere Zeilen den gleichen Wert für die ORDER BY Schlüssel. Verschiedene willkürliche Aufrufe wählen aus, welche dieser mehreren Zeilen die erste, die zweite usw. ist.

Die kanonische Lösung ist eine Art von eindeutigen Schlüsseln zu schließen, so dass die Art stabil ist:

ROW_NUMBER() OVER (PARTITION BY w.uid 
        ORDER BY (DIFFERENCE(t.val1, w.val1) + 
           DIFFERENCE(t.val2, w.val2) + 
           DIFFERENCE(t.val3, w.val3) + 
           DIFFERENCE(t.val4, w.val4) 
          ) DESC, 
           ?? -- perhaps typeId 
        ) as Score 

aber ich könnte eine schwierigere Lösung vorschlagen. Akzeptieren Sie die Tatsache, dass Verknüpfungen vorhanden sein können, und verwenden Sie rank() und dense_rank(), um sie zu identifizieren. Dann, herauszufinden, explizit was zu tun, im Falle einer Krawatte - vielleicht sind alle gleich interessant für Sie oder vielleicht haben Sie eine andere Methode, Bindungen zu brechen.

+0

Oh vielen Dank. Also ist die Nachschlagetabelle so aufgebaut, dass sie keine Bindungen hat. Wenn Sie also gesagt haben, dass dies auf die Antwort hinweist. Das eigentliche Problem ist die Verwendung der Differenzfunktion, die nicht wirklich das tut, was ich dachte. Es bewertet die beiden Strings auf einer Skala von 0-4 basierend auf dem Soundex, während ich dachte, dass es mir den Unterschied in den Buchstaben geben würde. Ich werde überdenken müssen, welche Funktion ich dort verwenden soll, oder meine eigene schreiben – nikolifish