Seite 1 von 2

SQLite 3 Wert eines Tables auf anderen Table verweisen

Verfasst: Donnerstag 31. Mai 2012, 12:05
von FrostByteGER
Moin,

noch immer plage ich mich mit meiner Datenbank und der Bankklasse rum.

Meine Idee ist es, dass ein Kunde eine Kundennummer hat, welche sozusagen die Konten dem Kunden zuordnet. Also ein Kunde hat eine einzigartige Nummer, welche mehrere Konten haben kann.

Also: Kunde mit Kundennummer -> Mehrere Konten.

Nur bisher habe ich ehrlich gesagt keine wirkliche Idee wie genau ich das verwirklichen kann. Ich habe jetzt 2 Tables, einmal Customer und Accounts. Dort werden dann logischweise alle Konten und Kunden mitsamt der Infos(Kontostatus, Alter usw...)
gespeichert.

Der letzte Wert des Kundentables pro Kunde ist die Kundennummer, welche ja auf die Konten verweisen soll.

Habt ihr Ideen, Anregungen oder sonstiges, weil ich bin momentan ziemlich ratlos und Google eher sporadisch...

Mein bisheriger Code ist hier zu finden, falls es hilft: http://pastebin.com/uFqNt72e

Re: SQLite 3 Wert eines Tables auf anderen Table verweisen

Verfasst: Donnerstag 31. Mai 2012, 12:12
von Hyperion
Das ist ja per se erst einmal kein Python-Problem, sondern ein fehlendes / lückenhaftes Verständnis für relationales DB-Design.

Schau Dir doch mal diese Übung an: Link

Da wird der Entwurf vom ERD bis hin zu Datenbank erklärt. Vieles ist dabei bewusst simpel gehalten, da die Zielgruppe ziemlich gemischte Bachelor-Studis sind. Zumindest die Unterscheidung der drei verschiedenen Relationen hinsichtlich ihrer Multiplizitäten (1:1, 1:n, n:m) werden erklärt.

Heute würde ich da einiges anders machen, aber ich bin ja nur der "Hiwi" gewesen :-D

Re: SQLite 3 Wert eines Tables auf anderen Table verweisen

Verfasst: Donnerstag 31. Mai 2012, 12:55
von FrostByteGER
Ahh Danke, genau sowas brauchte ich. Da ich momentan noch in der Schule sitze, konnte ich gerade nur die Folien begutachten, aber es hat mir schon etwas geholfen. Im Prinzip ähnelt das Schema einer Datenbank einem UML Klassendiagramm. Leider haben wir in der Schule noch keine Datenbanken, daher hab ich das SQLite Tutorial von Galileo Computing genommen. Da wurde dieses Wissen hier aus der Präsentation nicht vermittelt^^ Ich hab sowas zwar schon im techn. Englisch Unterricht(Durch Zufall angeschnitten) gesehen, aber halt nicht richtig.

Auch wenn es mir bewusst ist, dass da nochmehr zugehört, ist der Kernpunkt für mein Problem doch eigentlich nur, dass ich den Primärschlüssel & fremdschlüssel nicht gesetzt habe.

Damit verweist die Kundennummer(Primärkey) auf die Kontonummer(fremdkey) und ich hab die Relation zwischen den beiden Tables hergestellt. Ein Primärschlüssel kann doch auch mehrere Relationen haben, oder nicht?

Ansonsten werde ich heute Abend mal mir die Präsentation angucken.

Gruß FrostByteGER

edit: Sry, foreign Key falsch übersetzt :oops:

Re: SQLite 3 Wert eines Tables auf anderen Table verweisen

Verfasst: Donnerstag 31. Mai 2012, 13:11
von Hyperion
FrostByteGER hat geschrieben: Auch wenn es mir bewusst ist, dass da noch mehr zugehört, ist der Kernpunkt für mein Problem doch eigentlich nur, dass ich den Primärschlüssel & fremdschlüssel nicht gesetzt habe.
Naja, diese Schlüssel musst Du vor allem für Dich definieren; ein RDBMS kann mit diesen Infos natürlich auch Dinge "anstellen", z.B. zur automatischen Integritätserhaltung bei Löschoperationen (`on delete cascade`) uvm. Du kannst auch ohne Datenbank seitige Definition, Fremdschlüsselbeziehungen bei Abfragen nutzen ;-)

Natürlich sollte man dieses explizit bei der DB-Erstellung angeben, so die DB so etwas unterstützt. SQLite bspw. hatte solch eine Funktionalität lange Zeit nicht.

Re: SQLite 3 Wert eines Tables auf anderen Table verweisen

Verfasst: Donnerstag 31. Mai 2012, 13:24
von FrostByteGER
Okay, wie sieht denn die Syntax beim erstellen eines Tables dazu aus, wenn ich nen Primärschlüssel setze?

Bisher habe ich nur sowas gefunden: http://www.devdaily.com/android/sqlite- ... ys-example

Kann ich den primärschlüssel direkt beim jeweiligen Wert schon setzen? Also z.b. Customernumber TEXT PRIMARY KEY,....
und bei dem Kontotable FOREIGN KEY(Accountnumber) REFERENCES Customers(Customernumber),...

Oder erst dahinter, so wie aktuell bei mir:

Customertable:

Code: Alles auswählen

Name TEXT, Surname TEXT, Age TEXT, Customernumber TEXT, PRIMARY KEY(Customernumber)
Beim Kontotable:

Code: Alles auswählen

Accountnumber TEXT, PIN INTEGER, Value INTEGER, Currency TEXT,FOREIGN KEY(Accountnumber) REFERENCES Customers(Customernumber)

Re: SQLite 3 Wert eines Tables auf anderen Table verweisen

Verfasst: Donnerstag 31. Mai 2012, 13:30
von Hyperion
FrostByteGER hat geschrieben: Kann ich den primärschlüssel direkt beim jeweiligen Wert schon setzen? Also z.b. Customernumber TEXT PRIMARY KEY,....
Probiere es doch aus ;-) Das geht sicherlich schneller, als hier nachzufragen. Zudem steht auf der von Dir verlinkten Seite doch diese Option!

Ich persönlich bevorzuge es, die "Funktion" am Schluss einer Tabellendefinition aufzurufen; bei zusammen gesetzten PKs geht das iirc auch nicht mehr per Attributannotation.

Dein FK ist semantisch falsch definiert - dazu musst Du Dir aber erst mal das Verständnis holen, was ein FK bewirken soll und wie zwei Tabellen zusammenhängen. Kleiner Tipp: Deine Accountnummer hat *nichts* mit der Kundennummer zu tun! Weiterer Tipp: Ein FK ist selten PK in der selben Tabelle... ;-)

Re: SQLite 3 Wert eines Tables auf anderen Table verweisen

Verfasst: Donnerstag 31. Mai 2012, 13:55
von FrostByteGER
Ja hast recht, habs probiert und klappt soweit.

Allerdings warum hängen Accountnumber und Kundennummer nicht zusammen? Durch die Kundennummer finden wir ja raus, welches Konto/Konten der Kunde hat! Schliesslich muss der FK ja auf den Primärkey verweisen, sonst macht das ganze ja keinen Sinn...

Der Foreign Key verweist ja auch den Primärkey. Soweit konnte ich es Wikipedia und SQLite.org rauslesen.
Letzteren Tipp hab ich auch nicht ganz verstanden, sry^^

Laut meinem Verständis sieht das ganze so aus: http://s14.directupload.net/file/d/2907 ... s7_png.htm

Re: SQLite 3 Wert eines Tables auf anderen Table verweisen

Verfasst: Donnerstag 31. Mai 2012, 14:31
von Hyperion
Die Accountnummer identifiziert exakt ein Konto. Die Kundennummer identifiziert genau einen Kunden. Beide sind vollkommen *unabhängig*! Aber: die Kundennummer spielt die *entscheidende* Rolle bei der Definition des Zusammenhangs zweier solcher Tupel.

Tipp: Dazu muss sie in der Tabelle "Account" irgend wie als *Attribut* vorkommen!

Das wird auch alles in der Übung erklärt btw ;-)

Ich kann Dein Bild nicht öffnen; bette es doch besser mal anders hier ein.

Re: SQLite 3 Wert eines Tables auf anderen Table verweisen

Verfasst: Donnerstag 31. Mai 2012, 14:40
von FrostByteGER
Ah jetzt verstehe ich was du meinst. Ich werds dann erstmal pausieren und heute Abend weiterführen.

Außerdem scheint es wohl Probleme mit DirectUpload zu geben, merkwürdig. http://www.imagebanana.com/view/dbhq4o4g/Unbenannt.png

Nur mal so ne externe Frage: Öfters finde ich, dass diese Foreign Keys bei SQLite ausgeschaltet sind, stimmt das?

Re: SQLite 3 Wert eines Tables auf anderen Table verweisen

Verfasst: Freitag 8. Juni 2012, 17:49
von FrostByteGER
Phew hatte in den letzten Tage viel zutun. Jetzt aber konnte ich mir das ganze endlich mal fertig angucken!

Ein Kunde kann ja mehrere Konten haben. Customernumber ist unser PK. Im Accounttable haben wir unsere Accountnumber, welche unser FK ist. Die sind damit untrennbar verbunden.
Allerdings hab ich es so verstanden, dass der PK den Wert des FK haben muss. Ansonsten funktioniert das ganze nicht, oder?

Alternativ könnte ich auch eine neue Spalte mit namen AccoundID erzeugen, die dieselben werte hat wie die Customernumber. Somit müsste ich nicht die Accountnumbers "opfern".

Damit das ganze auch bei mehreren Konten funktioniert, muss die Accountnumber der Customernumber des Kunden entsprechen. Also wir haben dann 4 Spalten mit DE001 als Accountnumber, welche auf die Customernumber DE001 verweisen.

Okay soweit alles verstanden. Oh man, so ein Praktikum hätte ich jetzt gerne übers Wochenende :D

Ist es auch möglich, dass ein FK != eines PK sein kann, aber dennoch darauf verweist? Oder ist das unmöglich?

Re: SQLite 3 Wert eines Tables auf anderen Table verweisen

Verfasst: Freitag 8. Juni 2012, 18:02
von EyDu
Hyperion hat dir die Lösung doch eigentlich schon verraten: Du brauchst eine Tabelle für den Kunden, welche Namen, Anschrift und die Kundennummer enthält. Letztere ist der PK für die Kundentabelle. Als weitere Tabelle benötigst du die Konten. Diese enthält den Kontostand, die Kontonummer und die Kundennummer. Bei der Kontotabelle ist die Kontonummer der PK und vollkommen unabhängig von der Kundennummer. die Kundenummer in der Kontentabelle ist ein FK und enthält nur Nummern, welche in der Kundentabelle als Kundennummer vorkommen.

Kunden: Name, Kundennummer (PK)
Konten: Stand, Kontonummer (PK), Kundennummer (FK)


Wenn ein Konto auch mehrere Besitzer haben darf, dann brauchst du drei Tabellen:
Kunden: Name, Kundennummer (PK)
Konten: Stand, Kontonummer (PK)
Zuordnung: Kundennummer (FK), Kontonummer (FK)

Re: SQLite 3 Wert eines Tables auf anderen Table verweisen

Verfasst: Mittwoch 13. Juni 2012, 17:56
von FrostByteGER
Soweit so gut.

Allerdings spuckt er mir beim Versuch, dass wenn Accounts.Customernumber und Customers.Customernumber übereinstimmen, nichts aus.
Eigentlich sollte er dann 9 Listenelemente zurückgeben, aber er gibt nur eine Leere Liste aus und führt nichteinmal die for-Schleife aus!

Mein Code:

Code: Alles auswählen

    def createCustTable(self):
    
        self.cur.execute("""CREATE TABLE Customers (
         Customernumber TEXT, Name TEXT, Surname TEXT, Age TEXT, PRIMARY KEY(Customernumber))""")
        
        self.connection.commit()
                                              
    def createAccTable(self):

        self.cur.execute("""CREATE TABLE Accounts (
        Accountnumber TEXT, PIN INTEGER, Value INTEGER, Currency TEXT, Customernumber TEXT, 
        PRIMARY KEY(Accountnumber), FOREIGN KEY(Customernumber) REFERENCES Customers(Customernumber))""")
                                              
        self.connection.commit()            
 
    def loadTable(self,searchedcustid):
        self.connection.text_factory = str
        searchedcustid = searchedcustid,
        self.cur.execute("SELECT Customers.*,Accounts.* FROM Customers,Accounts WHERE Customers.Customernumber AND Accounts.Customernumber = (?)",searchedcustid)
        custinformations = [] 

        for a in self.cur.fetchall():
            for element in a:
                custinformations.append(element)

        return custinformations
Also die Nummern in beiden Tables sind gleich!. Hab ich nen Fehler irgendwo? Die searchedcustid ist exakt die gleiche, wie die in den Tables!
Ich hab überprüft, ob der das execute Statement überhaupt ausführt und ja, er führt es aus.
Einer ne Idee?

Mache ich das bei jedem Table einzeln, funktioniert es und er gibt mir alle Elemente in der gesuchten Zeile zurück bzw. aus!

Re: SQLite 3 Wert eines Tables auf anderen Table verweisen

Verfasst: Mittwoch 13. Juni 2012, 18:09
von /me
FrostByteGER hat geschrieben:Ich hab überprüft, ob der das execute Statement überhaupt ausführt und ja, er führt es aus.
Das Statement wird tatsächlich ausgeführt? Ich hätte die Bedingung im WHERE für ungültiges SQL gehalten.

Ich habe das Statement mal umformuliert (und umformatiert).

Code: Alles auswählen

SELECT 
    customers.*, accounts.* 
  FROM customers
  JOIN accounts ON 
    accounts.customernumber = customers.customernumber
  WHERE 
    customers.customernumber = (?)
Läuft das jetzt?

Re: SQLite 3 Wert eines Tables auf anderen Table verweisen

Verfasst: Donnerstag 14. Juni 2012, 07:41
von sparrow
/me hat geschrieben:Das Statement wird tatsächlich ausgeführt? Ich hätte die Bedingung im WHERE für ungültiges SQL gehalten.
Das geht schon, nur scheint als Bedingung ein Feld ohne Operator immer "Falsch" zu sein:

Code: Alles auswählen

>>> import sqlite3
>>> con = sqlite3.connect(":memory:")
>>> con.execute("CREATE TABLE test (id INTEGER PRIMARY KEY, name VARCHAR)")
<sqlite3.Cursor object at 0x02AA92E0>
>>> con.execute("INSERT INTO test (id, name) VALUES (1, 'sparrow')")
<sqlite3.Cursor object at 0x02AA9420>
>>> con.execute("SELECT id, name FROM test WHERE test.name").fetchall()
[]
>>> con.execute("SELECT id, name FROM test WHERE NOT test.name").fetchall()
[(1, u'sparrow')]

Re: SQLite 3 Wert eines Tables auf anderen Table verweisen

Verfasst: Donnerstag 14. Juni 2012, 15:29
von FrostByteGER
Yo funzt! Danke /me. Auch mit mehreren Konten funktioniert es einwandfrei :D

Woran lag mein Fehler denn genau?

Re: SQLite 3 Wert eines Tables auf anderen Table verweisen

Verfasst: Donnerstag 14. Juni 2012, 15:41
von /me
FrostByteGER hat geschrieben:Woran lag mein Fehler denn genau?
Daran:

Code: Alles auswählen

WHERE Customers.Customernumber AND Accounts.Customernumber = (?)
Das hättewie folgt aussehen müssen:

Code: Alles auswählen

WHERE Customers.Customernumber =(?) AND Accounts.Customernumber = (?)
Oder auch so:

Code: Alles auswählen

WHERE Customers.Customernumber Accounts.Customernumber AND Accounts.Customernumber = (?)
Persönlich finde ich diese Art des SQL-Statements allerdings mittelprächtig scheußlich und bevorzuge die von mir bereits gepostete aussagekräftigere Variante mit JOIN.

Re: SQLite 3 Wert eines Tables auf anderen Table verweisen

Verfasst: Donnerstag 14. Juni 2012, 20:15
von BlackJack
@FrostByteGER: Analog dazu verhält sich übrigens Python bei ``a and b == c``. Du kannst nicht einfach einen umgangssprachlichen Satz zu einem logischen Ausdruck machen. Der muss sich schon an die Auswertungsregeln der Programmiersprache halten.

Re: SQLite 3 Wert eines Tables auf anderen Table verweisen

Verfasst: Donnerstag 14. Juni 2012, 21:13
von FrostByteGER
Yo verstanden.

Letzte Frage dazu:

Wenn ich jetzt ne Zeile löschen will, also von Customers, dann soll er die dazugehörige(n) Zeilen bei Accounts auch löschen. Ich hab mir das ON DELETE CASCADE Statement schon angeguckt, aber das dürfte doch nur funktionieren, wenn ich etwas von Accounts lösche. Dadurch löscht er ja dann die dazugehörige Customers Zeile.

Gibts dazu ne möglichkeit, oder muss ich das Delete-Statement zweimal , also je Einmal bei Accounts und Customers, anwenden?

Re: SQLite 3 Wert eines Tables auf anderen Table verweisen

Verfasst: Freitag 15. Juni 2012, 08:47
von sparrow
Stichwort "Fremdschlüssel" und "Kaskadierung":

http://www.sqlite.org/foreignkeys.html

Re: SQLite 3 Wert eines Tables auf anderen Table verweisen

Verfasst: Freitag 15. Juni 2012, 12:34
von sparrow
Das sieht dann in etwa so aus:

Code: Alles auswählen

import sqlite3

names = (("sparrow",), ("frosty",), ("hanniball",), ("gangster",))
trans = ((500, 1), (200, 1), (50, 2),  (100, 3), (200, 3), (400, 3),
         (50, 4), (-20, 4), (10, 4))

con = sqlite3.connect(":memory:")
con.execute("PRAGMA foreign_keys = ON") # Activate for everey connection!
con.execute("CREATE TABLE costumers (id INTEGER PRIMARY KEY, name TEXT)")
con.execute(("CREATE TABLE accounts (id INTEGER PRIMARY KEY, "
             "value INTEGER, "
             "costumer REFERENCES costumers(id) ON DELETE CASCADE)"))
con.executemany("INSERT INTO costumers (name) VALUES (?)", names)
con.executemany("INSERT INTO accounts (value, costumer) VALUES (?, ?)", trans)
print "Vor DELETE:", con.execute("SELECT * FROM accounts").fetchall()
con.execute("DELETE FROM costumers WHERE name = ?", ("hanniball",))
print "Nach DELETE:", con.execute("SELECT * FROM accounts").fetchall()