Hallo,
ich arbeite gerade an einem Programm in dem ich mit dem SQL Server Compact arbeite.
Und ich sitze nun schon über eine Stunde daran, eine Lösung für folgendes Problem zu finden:
In meinem Programm geht es um Koordinatenpunkte und Verbindungen zwischen ihnen.
Dass Problem ist, dass die Verbindungen in der Datenbank immer für beide Richtungen angegeben sind. Die Verbindungen sind in einer eigenen Tabelle gespeichert und haben nur die Werte FromID und ToID.
Es gibt aber eben für jede Verbindung FromID = X und ToID = Y auch die Umgekehrte Verbindung FromID = Y und ToID = X .
Wie werde ich die Doppelgänger los? Ist das Überhaupt in einer Abfrage möglich?
Die einzige Idee die ich bisher hatte, war einen Autoincrement-Wert hinzuzufügen und damit alle Verbindungen durchzugehen, die FromID und ToID auszzulesen und danach in einer Abrfrage alle einträge zu löschen, in denen die IDs anderst herum drinnestehen.
Also quasi: (Pseudocode, nur zum besseren Verständniss)
for (Var_Count = 0 to Anzahl_Verbindungen)
{
Ergebnis = Abfrage ("Select FromID, ToID FROM VerbindungsTable WHERE V_ID = Var_Count")
Abfrage(DELETE FROM Verbindungstable WHERE FromID = Ergebnis.ToID AND ToID = Ergebnis.FromID")
}
Allerdings macht dass je verbindung 2 Abfragen, und da ich mehrere tausend verbindungen habe, sehe ich dass nicht als die ideale Lösung an.
Ich hoffe hier kann mir jemand eine bessere Lösung sagen.
Danke schonmal.
Hmm, wenn ich dich richtig verstanden habe, willst du wissen, ob es Datensätze gibt, wo FromID = ToID ist und ToID = FromID, oder?
Das wäre doch nur ein
SELECT * FROM VerbindungsTable
WHERE (FromID = ToID AND ToID = FromID)
am besten sowas über eine stored procedure lösen (ich weiß nicht ob das SQL Server Compact unterstützt) und wenn das nciht geht, dann per transactionscope arbeiten, ansonsten ist noch eine möglichkeit einen trigger (ich weiß nicht ob das SQL Server Compact unterstützt) zu machen, der nach der eingabe (und das ist jetzt dirty) losrattert. oder man lädt sich die komplette tabelle (unperformant) und pickt sich die PK raus die man nciht haben möchte.
sauberster weg wäre per StoredProcedure
zweitbester weg über Transactionscopes
(meiner meinung nach ^^)
edit: ich denke zu kompliziert... machs so wie Khalid es beschrieben hat....
@Khalid: Nein, dass meine ich nicht. Sondern ich meine dass es 2 Datensätze gibt, zwischen den ToID und FromID vertauscht ist.
Also es Gibt z.B.
Eintrag1 : FromID=101 ToID=108
Eintrag5 : FromID=108 ToID=101
Das ist als würdest du eine Straße nicht als "eine Straße" beschreiben, sondern als "zwei Spuren", die eine von A nach B und die andere von B nach A.
Wenn ich aber die Straße z.B. zeichnen will, brauch ich ja nicht A nach B und B nach A, sondern nur eine davon, weil die übereinander liegen.
@Jack30lena:
Ich habe zwar wenige von deinen Worten verstanden, aber ich google mal danach und probiere etwas damit zu machen. Kannst du auf die von dir favorisierte Lösung eventuell genauer eingehen?
google nach stored procedures
man muss sich zwar reinarbeiten aber das wissen ist beim arbeiten mit danebanken ein "must have"
moin
schau dir mal den Sql Ausdruck between an.
Raik
Also between hat damit ja jetzt mal gar nichts zu tun?
Also between hat damit ja jetzt mal gar nichts zu tun?
nachdem ich nochmal richtig gelesen habe, muss ich dir zustimmen.
Raik
Hallo,
Ich würd einfach Subselects nutzen:
select * from t1 where fromid in (select distinct toid from t1) and toid in (select distinct fromid from t1)
dann bekommst alle "doppelten".
Spinnen wir das mal weiter, fals man gleich löschen will:
mit Union die Reihenfolgen ändern und zusammenwerfen:
select * from t1 union select id, toid as fromid, fromid as toid from t1
Damit hast du alle Kombinationen drin, wobei die "doppelten" jetzt noch öfter vorkommen.
dann mal grupieren und zählen:
select min(id) as firstid, count(id) as countid, fromid, toid from (
select * from t1 union select id, toid as fromid, fromid as toid from t1
) as t group by fromid, toid
Du bekommst die erte ID und siehst welche "doppelt" oder nur einfach sind
Ergebnis einschränken:
select min(id), count(id) as countid, fromid, toid as firstid from (
select * from t1 union select id, toid as fromid, fromid as toid from t1
) as t group by fromid, toid
having count(id) > 1
jetzt auf die ID's reduzieren und zum löschen benutzen:
delete from t1 where id in (
select distinct min(id) from (
select * from t1 union select id, toid as fromid, fromid as toid from t1
) as t group by fromid, toid
having count(id) > 1
)
Ole, alles überflüssige weg.
🙂
Xynratron