- Als neu kennzeichnen
- Lesezeichen
- Abonnieren
- Stummschalten
- RSS-Feed abonnieren
- Kennzeichnen
- Anstößigen Inhalt melden
Hallo zusammen,
ich habe einen Datensatz vorliegen, der vereinfacht folgendermaßen aufgebaut ist:
Identnummer Umsatz
1 2
2 5
3 1
3 3
4 7
Nun möchte ich die doppelten Datensätze (gleiche Identnummer) löschen, und zwar soll immer der Datensatz mit dem größeren Umsatz vorhanden bleiben.
Das Ergebnis sollte also folgendermaßen aussehen:
Identnummer Umsatz
1 2
2 5
3 3
4 7
Vorab schon vielen Dank für Eure Mühen und eure Hilfe.
Viele Grüße
Katrin
- Als neu kennzeichnen
- Lesezeichen
- Abonnieren
- Stummschalten
- RSS-Feed abonnieren
- Kennzeichnen
- Anstößigen Inhalt melden
Simple SQL:
data have;
input id umsatz;
datalines;
1 2
2 5
3 1
3 3
4 7
;
proc sql;
create table want as
select id, max(umsatz) as umsatz
from have
group by id;
quit;
Wenn es noch mehr Spalten gibt (ist wohl anzunehmen), macht man das mit "having":
data have;
input id umsatz sonst $;
datalines;
1 2 a
2 5 b
3 1 c
3 3 d
4 7 e
;
proc sql;
create table want as
select *
from have
group by id
having umsatz = max(umsatz);
quit;
- Als neu kennzeichnen
- Lesezeichen
- Abonnieren
- Stummschalten
- RSS-Feed abonnieren
- Kennzeichnen
- Anstößigen Inhalt melden
Hallo @Katrin11 ,
hier bietet sich das Sortieren und ein anschließender Data-Step mit BY-Variable an:
/* Testdaten */
data DATEN;
input Identnummer Umsatz;
cards;
1 2
2 5
3 1
3 3
4 7
;
run;
/* Sortieren */
proc sort data=DATEN;
by Identnummer descending Umsatz;
run;
/* Filtern */
data DATEN;
set DATEN;
by Identnummer;
if first.Identnummer;
run;
Der Trick ist, nach Identnummer und Umsatz absteigend zu sortieren und dann den ersten Datensatz (also den mit höchstem Umsatz) zu behalten.
Viel Erfolg
Christian
- Als neu kennzeichnen
- Lesezeichen
- Abonnieren
- Stummschalten
- RSS-Feed abonnieren
- Kennzeichnen
- Anstößigen Inhalt melden
Und auch noch mit Data-Step Mitteln:
proc sort data=have;
by id umsatz;
run;
data want;
set have;
by id;
if last.id;
run;
- Als neu kennzeichnen
- Lesezeichen
- Abonnieren
- Stummschalten
- RSS-Feed abonnieren
- Kennzeichnen
- Anstößigen Inhalt melden
data have;
input Identnummer Umsatz;
datalines;
1 2
2 5
3 1
3 3
4 7
;
data want;
do until(last.Identnummer);
set have;
by Identnummer;
if Umsatz gt _iorc_ then _iorc_=Umsatz;
end;
Umsatz=_iorc_;
_iorc_=.;
run;
- Als neu kennzeichnen
- Lesezeichen
- Abonnieren
- Stummschalten
- RSS-Feed abonnieren
- Kennzeichnen
- Anstößigen Inhalt melden
Interessante Lösung!
Aber auch dafür muss das Dataset nach Identnummer und absteigend nach Umsatz sortiert sein.
Spannend, wie immer mehrere Wege zum Ziel führen!
- Als neu kennzeichnen
- Lesezeichen
- Abonnieren
- Stummschalten
- RSS-Feed abonnieren
- Kennzeichnen
- Anstößigen Inhalt melden
@CKothenschulte schrieb:
Interessante Lösung!
Aber auch dafür muss das Dataset nach Identnummer und absteigend nach Umsatz sortiert sein.
Spannend, wie immer mehrere Wege zum Ziel führen!
Stimmt nicht wirklich. Denn der Umsatz muss hier gar nicht sortiert sein (Max ist Max, egal in welcher Reihenfolge).
Man kann diese Methode (DOW loop) sogar auf Bestände mit mehreren Variablen anwenden, indem man in jeder Iteration des Data Step ein Hash-Objekt füllt, und nach dem Abarbeiten einer Gruppe jenen Eintrag mit dem Maximum sucht und für die Ausgabe verwendet. Danach leert man das Objekt, so dass in der nächsten Iteration (= nächste Gruppe) wieder mit 0 begonnen wird. Ist das Dataset handlich genug, kann man sogar alles in ein Hash einlesen und daraus die Auswertung fahren.
- Als neu kennzeichnen
- Lesezeichen
- Abonnieren
- Stummschalten
- RSS-Feed abonnieren
- Kennzeichnen
- Anstößigen Inhalt melden
Okay!
In der Version zum Zeitpunkt meines Beitrages (siehe unten, hatte ich noch im EG) kam ein falsches Ergebnis heraus, wenn ich in den Testdaten die Datensätze:
3 1
33
vertauscht habe:
3 3
3 1
data have;
input Identnummer Umsatz;
datalines;
1 2
2 5
3 3
3 1
4 7
;
data want;
do until(last.Identnummer);
set have;
by Identnummer;
if Identnummer gt _iorc_ then _iorc_=Identnummer;
end;
_iorc_=.;
run;
Mittlerweile sieht der Code ja anders aus. Das funktioniert dann unabhängig von der Reihenfolge in den Eingabedaten.
- Als neu kennzeichnen
- Lesezeichen
- Abonnieren
- Stummschalten
- RSS-Feed abonnieren
- Kennzeichnen
- Anstößigen Inhalt melden
Yes, I corrected the code since there was an obvious error. Sorry, I am doing this in English. I understand German, though not fluently speaking 🙂
- Als neu kennzeichnen
- Lesezeichen
- Abonnieren
- Stummschalten
- RSS-Feed abonnieren
- Kennzeichnen
- Anstößigen Inhalt melden
Die Sortierung ist trotzdem notwendig (nicht nach Umsatz, aber immer noch nach Identnummer).
Wenn ein BY-Statement mit "Identnummer" vorkommt, braucht es eine entsprechende Sortierung (im Beispiel ist das zufälligerweise gegeben. Allgemein gültig ist der code so nicht).
Beispiel:
data have;
input Identnummer Umsatz;
datalines;
1 2
3 3
2 5
3 1
4 7
;
run;
- Als neu kennzeichnen
- Lesezeichen
- Abonnieren
- Stummschalten
- RSS-Feed abonnieren
- Kennzeichnen
- Anstößigen Inhalt melden
Hier Beispielcode für die Verwendung des Hash:
data have;
input id umsatz sonst $;
datalines;
1 2 a
2 5 b
3 3 c
3 1 d
4 7 e
;
data want;
if _n_ = 0 then set have;
if _n_ = 1
then do;
declare hash h (dataset:"have (obs=0)"); /* nur die Struktur anlegen */
h.definedata("sonst");
h.definekey("umsatz");
h.definedone();
end;
do until (last.id);
set have;
by id;
ums = max(ums,umsatz);
rc = h.add();
end;
/* 2 Statements zur Kontrolle */
rc = h.num_items;
put rc=; /* Groesse des Hash */
umsatz = ums; /* Maximalwert setzen */
rc = h.find(); /* dazu passendes Item extrahieren */
rc = h.clear();
drop ums rc;
/* automatische Ausgabe des Maximum-Objekts per Gruppe */
run;
Wenn zB der Eingangsbestand nach ID und Datum sortiert ist, und man nicht umsortieren will. Da immer nur eine Gruppe im Memory gehalten wird, ist es äusserst unwahrscheinlich, dass einem der Speicher ausgeht.
- Als neu kennzeichnen
- Lesezeichen
- Abonnieren
- Stummschalten
- RSS-Feed abonnieren
- Kennzeichnen
- Anstößigen Inhalt melden
Und hier jetzt mit komplett unsortierter Quelle, da muss dann allerdings der ganze Datenbestand ins Memory passen:
data have;
input id umsatz sonst $;
datalines;
3 3 c
2 5 b
3 5 x
4 7 e
3 1 d
1 2 a
;
data want (
keep=_id _umsatz _sonst
rename=(_id=id _umsatz=umsatz _sonst=sonst)
);
if _n_ = 0 then set have;
length
_id 8
_umsatz 8
_sonst $8
;
retain _id;
if _n_ = 1
then do;
declare hash h(dataset:'have',ordered:'a',multidata:'Y');
h.definekey('id','umsatz');
h.definedata('id','umsatz','sonst');
h.definedone();
declare hiter hi('h');
rc = hi.first();
_id = id;
end;
rc = 0;
do until (rc);
do until(_id ne id or rc);
_umsatz = umsatz;
_sonst = sonst;
rc = hi.next();
end;
output;
_id = id;
end;
stop;
run;
proc print data=want noobs;
run;
Ergebnis:
id umsatz sons 1 2 a 2 5 b 3 5 x 4 7 e