Laden...

Schwierige SQL Abfrage

9 Antworten
2,357 Aufrufe
Letzter Beitrag: vor 17 Jahren
Schwierige SQL Abfrage

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)

"Jedes Ding hat drei Seiten, eine positive, eine negative und eine komische." (Karl Valentin)

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

Herr, schmeiss Hirn vom Himmel - Autsch!

Die Erfahrung zeigt immer wieder, dass viele Probleme sich in Luft auslösen, wenn man sich den nötigen Abstand bzw. Schlaf gönnt.