sqlite row unique moeglich?

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
pyront
User
Beiträge: 22
Registriert: Donnerstag 28. Juni 2018, 16:04

Hi

ich wuerde gerne in sqlite die komplette row als unique setzten ist das irgentwie moeglich?

das problem ist, dass die daten in den columns alle mehrfach vorkommen koennen ...
aber ich dennoch gerne die db updaten wuerde...

meine loesung waere "einen" hash ueber alle(ausser der hash column) columns der row zu erstellen und diesen in einer neuen column einzutragen und diese dann als unique setzten,
was aber, so glaube ich, sehr resourcen intensiv sein wuerde ....

gefunden hab ich nur verschiedene schreibweisen fuer ein single/mehrfach column unique, was aber wegen dem "mehrfachvorkommen" nicht funktionierte.

mfg py
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@pyront: warum glaubst Du dass ein UNIQUE über mehrere Spalten nicht funktioniert? Was hast Du ausprobiert?
pyront
User
Beiträge: 22
Registriert: Donnerstag 28. Juni 2018, 16:04

hi sirirus

genau das will ich ja "ein" unique ueber mehrer spalten(bzw alle)......

am besten sah das aus

Code: Alles auswählen


def erstelle_table_ks_tab(tname):
    with con:
        cur = con.cursor()
        cur.execute("CREATE TABLE IF NOT EXISTS {} ( \
            milch varchar[200], \
            butter varchar[200], \
            anzahl_genommen real, \
            anzahl_hinzugefuegt real, \
            obst_sorte varchar[200], \
            obst_anzahl real, \
            date_stamp text, \
            name varchar[200] , UNIQUE(date, name, obst_sorte) ON CONFLICT ABORT))" .format(tname))
erstelle_table_ks_tab(tname)
aber so wie es aussgesehen hat wurde dadurch nur die 3 einzeln als unique gesetzt . also 3 x unique und nicht 1 unique aus 3

Code: Alles auswählen

 UNIQUE(date, name, obst_sorte) ON CONFLICT ABORT))"
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Wie hast Du denn das getestet?

`con` kommt bei »erstelle_table_ks_tab« aus dem nichts. Das sollte ein Argument sein. Was heißt denn die Abkürzung ks_tab? `tname` ist auch eine schlechte Abkürzung. Tabellennamen sollten sowieso nicht variabel sein. Benutze """-Strings, um mehrzeilige Strings zu machen. \ hat immer die Gefahr, dass ein verstecktes Leerzeichen danach kommt, und damit ein schwer zu findender SyntaxError.
pyront
User
Beiträge: 22
Registriert: Donnerstag 28. Juni 2018, 16:04

hi

ich bin noch anfaenger sollte ich auch immer dazu sagen xD

ja con wird normalerweise mit

Code: Alles auswählen

con = sqlite3.connect('ks03.db3')
allgemein uebergeben... ich glaube das ist ein argument?

ks_tab hab ich mir ausgedacht und stand fuer kuehlschrank table

der table name ist doch garnicht variable? ich will nur nicht 10 mal die funktion schreiben um 10 verschiedene tables zu erstellen

Code: Alles auswählen

"""-Strings 
noch nie gesehen werd ich mal nachschauen.. nano zeigt die leerzeichen mit an vieleicht hatte ichdeshalb noch keine probleme damit

edit achja ich hatte das und wie auch alles andere auch getestet ... also die

Code: Alles auswählen

, UNIQUE(date, name, obst_sorte) ON CONFLICT ABORT) 
zeile. heb halt nur manchmal die code fetzen auf und rest delete...
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Dann hast Du nicht richtig getestet, z.b. das »IF NOT EXISTS« wird Dir zum Verhängnis, weshalb man dieses Konstrukt nicht verwenden sollte, sondern nur Tabellen dann erzeugen, wenn sie auch wirklich neu sind. »allgemein übergeben« gibt es nicht, alles was eine Funktion braucht, sollte auch in ihren Parametern auftauchen. »kuehlschrank« ist deutlich lesbarer als »ks«. Und tab ist doppelt gemoppelt, bei erstelle_table. Sprachen zu mischen, ist auch nicht so gut, am besten benutzt Du nur englisch.

Wenn 10 verschiedene Tabellen exakt die gleiche Struktur haben, dann hast Du einen Designfehler, wahrscheinlich weil Du Informationen in den Tabellennamen kodierst. Statt dessen solltest Du aber eine weitere Spalte mit dieser Information füllen und nur eine Tabelle haben.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@pyront: Die Typen sind bei der Tabelle sind auch etwas komisch. Anzahlen sind normalerweise ganzzahlig (INTEGER) und ein ”Datumstempel” hat den Typ DATE und nicht TEXT. SQLite ist da etwas entspannter was die Datentypen angeht, aber Bibliotheken/Programme die diese Tabellen dann verwenden, schauen sich oft den deklarierten Typ an und verhalten sich dann entsprechend anders. SQLAlchemy liefert Daten aus DATE-Spalten beispielsweise als `datetime.date`-Objekte. Und das will man eigentlich haben, statt einer Zeichenkette bei TEXT.

Insgesamt ist mir auch nicht so ganz klar was diese Tabelle(n) wie speichern sollen. Da erscheint mir einiges durcheinandergeworfen zu sein.

Das ``ON CONFLICT ABORT`` würde ich weglassen. Das ist die Voreinstellung wenn man kein ``ON CONFLICT`` angibt und ``ON CONFLICT`` ist kein Standard-SQL. Es wird also unnötigerweise unportabel dadurch.

Irgendwie fehlt mir auch eine künstliche ID als Primärschlüssel. Es ist nach meiner Erfahrung sehr selten das man keine solche ID in einer Tabelle hat. Eigentlich fast nur in Verbindungstabellen bei N:M-Beziehungen. Natürliche IDs sind eher selten, also Werte die sich gut als Index eignen und sich nie ändern werden, wie Postleitzahlen — ach nee, das war ein Beispiel von vor der Wiedervereinigung. :-)
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
pyront
User
Beiträge: 22
Registriert: Donnerstag 28. Juni 2018, 16:04

ja es funktoniert tatsaechlich so wie es soll. am bsp 1 unique aus 3 spalten
leider ist meine freude darueber gering.

ich dachte auch dieses mal es geht nicht, aber das problem ist/heisst duplikat.
hatte ich nicht fuer moeglich gehalten...
plan b faellt damit auch ins wasser (hash)

plan c
ich muss beim eintragen und updaten, eintragen, dass es x duplicate der zeilen gibt.
oder ohne unique und per last date_stamp vor dem eintragen abgleichen/sortieren

um dir mal einen blick in die anfaenger welt zu geben
ich habe min 6 tables(mit unique ohne mit if ...) erstellt
erst auf groesse dann auf duplikate verglichen
ich kam nur zu spaltenduplikatsvergleichen...daher
die 2 tables unique und nichtu in > datei geprinted
mit $ uniq -d datei die zeilen duplikate erhalten

falls ich mal auf deinem lvl bin werde ich das failen nicht mehr mit einprogrammieren
und die namensgebung beachten. ich glaube, ich hatte den funktionskopf kopiert
und nur das letzte wort geloescht und ks_tab eingefuegt...wahrscheinlich daher die dopplung


Anzahlen sind normalerweise ganzzahlig (INTEGER)
hier leider nicht hans kann auch 1.101 aepfel nehmen

”Datumstempel” hat den Typ DATE und nicht TEXT.
bekomm den date_stamp als string und benoetige beide versionen string/date

Das mit `ON CONFLICT ABORT`
hatte ich mir gestern noch durchgelesen und lass es jetzt weg, aber im code fetzen bleibt es damit ich weiss wohin es sollte

irgendwie fehlt mir auch eine künstliche ID als Primärschlüssel.
keine ahnung noch nie gehoert vieleicht loest das ja mein problem
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@pyront: Aus Deiner Beschreibung wird weder klar was Du willst, was Du gemacht hast, noch was eigentlich das Problem ist. Was bedeutet „das problem ist/heisst duplikat“? Du hast Duplikate? Du willst Duplikate und es geht nicht? Duplikate von *was*? Von ganzen Zeilen ja nicht wenn es ein UNIQUE-Constraint gibt.

Ein Datum gehört als DATE in die Datenbank, auch wenn man das als Zeichenkette bekommt und später vielleicht auch mal eine Zeichenkettendarstellung benötigt. Daten sollte möglichst als die Datentypen verarbeitet werden, die am meisten Sinn machen. Umwandlungen an den ”Grenzen” eines Programms möglichst früh wenn die Daten rein kommen und möglichst spät wenn sie das Programm verlassen. Das ist zum einen Dokumentation um was für einen Wertebereich es sich handelt, und zum anderen bestimmt es bei den Datentypen ja auch was für Operationen möglich sind.

``NOT NULL`` fehlt wahrscheinlich auch bei einigen, wenn nicht sogar allen Spalten.

Da ich nicht weiss welches Problem da überhaupt gelöst werden soll, kann man natürlich auch nicht sagen ob ein künstlicher Primärschlüssel das Problem löst, aber der Datenbankentwurf sieht sehr komisch aus. Eventuell eine 1:1 Übernahme wie man die Informationen auf einem Blatt Papier in einer Tabelle notieren würde, aber nicht nach einem relationalen Modell. Was ist denn der Primärschlüssel von so einem Datensatz in der Tabelle?
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
pyront
User
Beiträge: 22
Registriert: Donnerstag 28. Juni 2018, 16:04

wow du bist schnell ...
leider fehlt es mir an wissen, den letzten abstatz versteh ich garnicht.

Was bedeutet „das problem ist/heisst duplikat“
das es gewollte duplikate in dem table giibt. das heisst alle spalten der zeile stimmen mit einer anderen zeile ueberein.
als ich alle spalten zu einer unique formierte fehlten am ende daten... deswegen dachte ich ja, dass es(1unique x spalten) nicht geht...

ich hab ca 6 funktionen die das date als sting benoetigen und nur eine die es als date braucht und die wird auch nur in unter 0.1% der faelle angewendet, von daher macht es fuer mich immo mehr sinn es als string drin zu lassen.

``NOT NULL`` fehlt wahrscheinlich auch bei einigen, wenn nicht sogar allen Spalten.
liegst du wahrscheinlich richtig... ich uebergeb den werten vor dem eintragen einen 0 wert als zahl oder string damit es nicht null is und der rest der werte sicher genullt werden.

ich denke ich werde eine weietere spalte einfuegen die beim eintragen von dopplungen hochzaehlt, dann wieder auf 0 geht und diese spalte mit als unique reinehmen....
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Statt einen solchen komischen hack mit einer laufenden Nummer fueg einfach eine auto-id Spalte hinzu, die eine eindeutige Nummer fuer jede eingetragene Zeile automatisch erzeugt. Und das ist dann deine eindeutige ID, auf die du dich von woanders aus beziehen kannst. ZB so:

Code: Alles auswählen

CREATE TABLE countries (
 country_id INTEGER PRIMARY KEY,
 name text NOT NULL
);
country_id ist dadurch automatisch eine aufsteigende Nummer, die vergeben wird. Mit

Code: Alles auswählen

cursor.execute('INSERT INTO countries (name) VALUES (?)',
               ('TakaTukaLand',))
print(cursor.lastrowid)
bekommst du nach dem einfuegen diese ID, und kannst mit ihr weiter arbeiten, also sie zB in anderen Tabellen als Bezug verwenden.

Und deine Intuition bezueglich 5 zu 1 string vs date ist falsch. So arbeitet man nicht. Wenn du ein Datum *hast*, dann behaelst du das bis zu dem Zeitpunkt, wo du es zB zur Darstellung in einer Datei in ein spezifisches Format konvertierst. Das macht dir das Leben einfacher. Vertrau uns da.
pyront
User
Beiträge: 22
Registriert: Donnerstag 28. Juni 2018, 16:04

ich versteh nich wie mir der primary key weiterhelfen soll...
nach deinem beispiel bekomme ich eine spalte mehr mit +=1 pro eintrag ..
wenn ich das mit als unique reinehme, gehen bei der erstbespielung die doubletten zwar mit rein,
aber beim update wird das unique doch sinnlos, weil country_id immer unique ist und so der komplette datensatz hinzuaddiert wuerde, anstatt ihn upzudaten.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Der primary key kommt in kein uinque. Das unique faellt in dem Moment weg, es ist ja eh einen Luege. Deine Daten sind nicht unique. Dein Ansatz ist zu sagen, dass es statt Takatukaland jetzt halt (Takatukaland, 1) und (Takatukaland, 2) gibt. Nur das du komplizierte Logik brauchst, um 1 und 2 zu erzeugen. Mein Ansatz sagt "spar dir die Logik, es gibt (Takatukaland, 123422342) und (Takatukaland, 324032300)", weil die Zahl eh irrelevant ist - sie dient dazu, die Dubletten eindeutig identifizierbar zu machen.

Fuer beide Ansaetz gilt, dass ein update ein Problem hat, denn welchen Datensatz von den diversen Takatukalendern das nun betrifft, kann halt keiner sagen. Sind halt doofe Daten. Ausser es gibt ein implizites weiteres Kriterium wie zB die Reihenfolge in der CSV-Datei. Wenn nicht, dann bist du halt samt Kind im Brunnen.
pyront
User
Beiträge: 22
Registriert: Donnerstag 28. Juni 2018, 16:04

dank euch fuer den beistand und die vielen tips drum herum

also ich verstehe zwar was du schreibst, aber mir faellt kein loesungsweg mit dem primary key ohne uniques ein..

ich hab das jetzt mit multi column uniques gemacht inkl. der zusatzspalte duplicate

Code: Alles auswählen

duplikat_gewollt_counter = 0
i = 0
while i < 15:
    milch='0'
    butter='0'
    anzahl_genommen=i
    anzahl_hinzugefuegt=i
    obst_sorte='0'
    obst_anzahl=i
    date_stamp='0'
    name='0'
    #duplikat_gewollt_counter = 0

    if i == 12:
        anzahl_genommen = i - 1
        anzahl_hinzugefuegt = i - 1
        obst_anzahl = i - 1

    if  i == 13:
        anzahl_genommen = i - 2
        anzahl_hinzugefuegt = i - 2
        obst_anzahl = i - 2

    if i > 0 and bamilch==milch and babutter==butter and baanzahl_genommen==anzahl_genommen and baanzahl_hinzugefuegt==anzahl_hinzugefuegt  and baobst_sorte==obst_sorte and baobst_anzahl==  ==obst_anzahl and badate_stamp==date_stamp and baname==name:
        duplikat_gewollt_counter +=1
        print('doublette found',duplikat_gewollt_counter)

    fill_ks_tab(milch, butter, anzahl_genommen, anzahl_hinzugefuegt, obst_sorte, obst_anzahl, date_stamp, name, duplikat_gewollt_counter)

    bamilch=milch
    babutter=butter
    baanzahl_genommen=anzahl_genommen
    baanzahl_hinzugefuegt=anzahl_hinzugefuegt
    baobst_sorte=obst_sorte
    baobst_anzahl=obst_anzahl
    badate_stamp=date_stamp
    baname=name

    #duplikat_gewollt_counter = 0
    i += 1

ergibt dann sowas

Code: Alles auswählen

('doublette found', 1)
('doublette found', 2)
(1, u'0', u'0', 0.0, 0.0, u'0', 0.0, u'0', u'0', 0)
(2, u'0', u'0', 1.0, 1.0, u'0', 1.0, u'0', u'0', 0)
(3, u'0', u'0', 2.0, 2.0, u'0', 2.0, u'0', u'0', 0)
(4, u'0', u'0', 3.0, 3.0, u'0', 3.0, u'0', u'0', 0)
(5, u'0', u'0', 4.0, 4.0, u'0', 4.0, u'0', u'0', 0)
(6, u'0', u'0', 5.0, 5.0, u'0', 5.0, u'0', u'0', 0)
(7, u'0', u'0', 6.0, 6.0, u'0', 6.0, u'0', u'0', 0)
(8, u'0', u'0', 7.0, 7.0, u'0', 7.0, u'0', u'0', 0)
(9, u'0', u'0', 8.0, 8.0, u'0', 8.0, u'0', u'0', 0)
(10, u'0', u'0', 9.0, 9.0, u'0', 9.0, u'0', u'0', 0)
(11, u'0', u'0', 10.0, 10.0, u'0', 10.0, u'0', u'0', 0)
(12, u'0', u'0', 11.0, 11.0, u'0', 11.0, u'0', u'0', 0)
(13, u'0', u'0', 11.0, 11.0, u'0', 11.0, u'0', u'0', 1)
(14, u'0', u'0', 11.0, 11.0, u'0', 11.0, u'0', u'0', 2)
(15, u'0', u'0', 14.0, 14.0, u'0', 14.0, u'0', u'0', 2)
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@pyront: um ehrlich zu sein, ich verstehe nicht, was Du erreichen willst.

Beschreibe doch mal, was sind Deine Ausgangsdaten, und was willst Du damit machen.
pyront
User
Beiträge: 22
Registriert: Donnerstag 28. Juni 2018, 16:04

hi Sirius
die ausgabe meines letzten postings wollte ich erreichen xD also geschaft hurra :) ich bin sogar etwas am feiern xD

ich wollte das table updaten ....um beim update nicht den alten und neuen bestand in einem zu haben, brauchte ich uniques... aber ueberaschung es gab gewollte duplikate ...
mit dem posting oben werden nun auch die duplikate mit eingetragen und alles ist updatefaehig. perfekt.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@pyront: Irgendwie ist das hier als Leser etwas frustrierend. Ich habe nicht verstanden was Du machen willst, Sirius3 auch nicht, und ich denke auch sonst niemand. Ich habe aber das Gefühl das es falsch gelöst ist, denn das sieht nach keinem gesunden Datenbankentwurf aus. Du hast das Problem was niemand hier kennt, immer nur in Form einer vermeintlichen Lösung beschrieben, die keiner hier versteht.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
pyront
User
Beiträge: 22
Registriert: Donnerstag 28. Juni 2018, 16:04

oje das wollt ich nicht...
ich glaub das ziel war zu simple, sodass ihr es garnicht anerkennt :(

ein table updaten das duplikate enthaellt und erhaelt updaten.... mehr nicht
ich glaub __deets__ hat es verstanden
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Nein, verstanden habe ich das auch nicht.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@pyront: das was Du da gezeigt hast, hat nichts mit einer Datenbank zu tun, weil Du nur eine Handvoll Tuple erzeugst, wo die eine Hälfte der Elemente konstant ist, und die andere hochgezählt wird. Es ist schwer zu glauben, dass das die Lösung ist.

Um eine Datenbanktabelle zu aktualisieren, braucht man etwas, das einen Eintrag eindeutig identifiziert und einen Wert, der ersetzt werden soll. Laut erstem Beitrag sind das Datum, Name und Obstsorte. Aktualisiert werden könnte Obstanzahl. Die Spalten anzahl_genommen und anzahl_hinzugefügt lassen aber vermuten, dass die Tabelle gar keinen Zustand beschreiben soll, sondern Transaktionen. Butter und Milch sind zwei Felder, die gar nicht zum Rest passen
Antworten