2017-10-19 2 views
0

Ich habe eine SQL Server-Abfrage, die eine Datenmenge zurückgibt, die die ID einer Person, die Entität, für die diese Person arbeitet, die zu der Entität gehörenden Standorte, den zugewiesenen Koordinator und die Status der Person.Fensterfunktion zum Entfernen bestimmter Datensätze aus dem SQL Server-Dataset

ID EntityName  LocationName  AssignedTo  StatusName 
    17  F&S   St. Lucie   A Hardon  Active 
    17  F&S   St. Lucie   A Hardon  Withdrawn 
    18  F&S   NH    A Hardon  Withdrawn 
    20  H&H   NCH    B Reedy  Active 

Ich brauche Aufzeichnungen zu beseitigen, in denen der einzige Status für die Kombination von EntityName, Location und AssignedTo Zurückgezogen wird. Also im obigen Datensatz würde ich ID = 18 mit LocationName = NH entfernen wollen.

Ich habe versucht, eine Fensterfunktion verwendet, die auf dem richtigen Weg sein können, aber ich bin nicht sicher, wie es weitergeht:

ID EntityName LocationName  AssignedTo  StatusName  RN 
    17  F&S   St. Lucie  A Hardon  Withdrawn  1 
    17  F&S   St. Lucie  A Hardon  Active   2 
    18  F&S   NH    A Hardon  Withdrawn  1 
    20  H&H   NCH    B Reedy  Active   1 
:

wie diese
Select id, entityname, locationname, assignedto, statusname 
    Into #test 
    From Table A 

    Select *, 
      row_number()over(partition by entityname, locationname, assignedto 
          order by case when statusname = 'Withdrawn' then 1 
            else 2 end) as rn 
    from #test 

Das gibt mir ein Ergebnis

Aber jetzt bin ich fest, wie ich weitermachen soll, oder wenn ich das überhaupt falsch mache.

+0

Kann 'StatusName' etwas anderes als die beiden Werte sein? –

+0

Ja, es gibt 7 Status, aber der einzige, den ich entfernen muss, ist Zurückgezogen. – jackstraw22

Antwort

2

Denken Sie darüber nach einem etwas anderen Weg. Zählen Sie die Nummer nicht zurückgezogen. Wenn dies 0 ist, werden alle zurückgezogen.

Die entsprechende Fensterfunktion ist eine bedingte Aggregation, sondern als eine Rangfunktion:

select t.* 
from (Select t.*, 
       sum(case when statusname <> 'Withdrawn' then 1 else 0 end) over 
        (partition by entityname, locationname, assignedto) as num_notwithdrawn 
     from #test t 
    ) t 
where num_notwithdrawn = 0; 
+0

Wenn ich das versuchte, löschte es fast alle Datensätze (etwa 1.000) und behielt nur 2, beide mit einem Status = 'Zurückgezogen. " – jackstraw22

+0

@ Jackstraw22. Ist' statusname' jemals 'NULL'? –

0
Select id, entityname, locationname, assignedto, statusname, 
    r row_number()over(partition by entityname, locationname, assignedto 
        order by CASE statusname WHEN 'Withdrawn' THEN 1 ELSE 2 END) as rn Into #test From Table A 
Select * from #test LEFT OUTER JOIN 
    (
     SELECT MAX(rn) MRNO,ID FROM #test GROUP BY ID 
) T ON T.ID = #TEST.ID WHERE rn = MRNO AND statusname ='Withdrawn' 

Diese Zeilen mit Status allein zurückgezogen eliinate wird für die Kombination von entityname, Musterdorf, AssignedTo

+0

Würde dies nicht beseitigen alle Status, die nicht = "zurückgezogen" sind? – jackstraw22

+0

Bearbeitete die Abfrage –

0

löschen mit einem INNEREN VERBINDEN

DELETE T 
FROM Table T 
INNER JOIN 
(
    SELECT EntityName,LocationName,AssignedTo 
    FROM Table 
    WHERE StatusName='Withdrawn' 
    GROUP BY EntityName,LocationName,AssignedTo 
    HAVING COUNT(*) = 1 
)D ON D.EntityName=T.EntityName AND D.LocationName=T.LocationName AND D.AssignedTo=T.AssignedTo 
+0

Ich versuchte den linken beitreten - es war in der Nähe, aber nicht ganz funktioniert. Es gibt einige Fälle, in denen die ID einer Person zu mehreren Entitäten mit mehreren Standorten gehören kann. Wenn eine dieser Entitäten nur einen Datensatz hat und dieser Datensatz = 'Zurückgezogen', dann wurden auch alle anderen Datensätze für diese Person eliminiert. ID = 112, Entität = F & S, Standort = NE Florida, Status = Zurückgezogen. Dieser Datensatz wird eliminiert, wie es sein sollte, aber alle anderen Datensätze für ID = 112 werden ebenfalls eliminiert – jackstraw22

+0

Ja, dann können Sie die ID nicht verwenden.Ich dachte, es wäre eine Identitätsspalte, aber es wiederholt sich. Sie müssten die MAX (ID) entfernen und dann den drei Gruppen nach Feldern in der äußeren Abfrage beitreten, um dies zu erreichen. Dies könnte jedoch Auswirkungen auf die Leistung großer Datasets haben, wenn diese drei Felder nicht indiziert werden. –

+0

Ich habe mit einem Join auf Nicht-ID-Felder aktualisiert. –

0

Versuchen Sie das bel ow ein:

WITH CTE 
AS (
Select id, entityname, locationname, assignedto, statusname, 
     row_number()over(partition by entityname, locationname, assignedto 
         order by statusname) as rn 
    From Table A) 
DELETE from CTE where rn=1 and statusname = 'Withdrawn' 
2

versuchen VORHANDEN mit

Select * 
FROM #test t1 
WHERE EXISTS (SELECT * 
       FROM #test t2 
       WHERE t1.EntityName = t2.EntityName 
         and t1.LocationName = t2.LocationName 
         and t1.AssignedTo = t2.AssignedTo 
         and t2.StatusName <> 'Withdrawn') 
+0

Ich denke, das hat es geschafft! Aber ich bin verwirrt, warum es funktionieren würde. Warum werden dadurch nicht alle Status 'Zurückgezogen' gelöscht? – jackstraw22

+0

Exists sucht, ob die Kombination von EntityName, LocationName, AssignedTo in der Tabelle mit einem anderen Status als Withdrawn vorhanden ist. Für die erste Aufzeichnung wird also F & S, St. benötigt. Lucie und A Hardon durchsucht diese Kombination nach einem anderen Status als Zurückgezogen .. Nur so findet sie den ersten Datensatz (selbst), der Aktiv ist, so dass sie es behält.Für den zweiten Datensatz findet sie auch den ersten Datensatz, da diese Felder übereinstimmen und behält auch die zweite Zeile .. Es ist wie mit einem IN() -Filter, aber Sie können nach mehreren Feldern statt nur einem suchen – JamieD77

+0

Es hat eine Weile gedauert, aber ich glaube, ich verstehe das. Es sucht nach allen Datensätzen in der ersten Tabelle die auf den 3 Feldern übereinstimmen, aber in der 2. Tabelle keinen Status = 'Zurückgezogen' haben. Das bringt alle Datensätze aus der ersten Tabelle zurück, einschließlich 'Zurückgezogen', da Sie nicht wirklich aus der ersten Tabelle filtern die einzige Aufnahme d in Tabelle 2 ist "Zurückgezogen", wird aus Tabelle 2 herausgefiltert und kann daher nicht mit Tabelle 1 verknüpft werden. – jackstraw22

0

Warum nicht potenzial Deletionen identifizieren mit einem inneren Verknüpfung und dann einen einfachen hinzufügen WHERE-Klausel ‚Zurückgezogen‘ Einträge löscht?

delete from #table a 
inner join (
      select entityname, locationname, assignedto, count(*) 
      from #table 
      group by entityname, locationname, assignedto 
      having count(*) = 1) b 
      on b.entityname = a.entityname 
      and b.locationname = a.locationname 
      and b.assignedto = a.assignedto 
where a.statusnname = 'Withdrawn' 

Die innere Verknüpfung hält ‚potenziell‘ Löschungen (beliebige Kombination von E, L und einen mit nur einem Datensatz) und die nachfolgenden WHERE-Klausel den entsprechenden Datensatz entfernt (s).

Verwandte Themen