Laden...

Die Spalte 'xy' hat die Einschränkung, dass sie eindeutig sein muss.

Erstellt von Tweaky vor 10 Jahren Letzter Beitrag vor 10 Jahren 6.209 Views
T
Tweaky Themenstarter:in
24 Beiträge seit 2010
vor 10 Jahren
Die Spalte 'xy' hat die Einschränkung, dass sie eindeutig sein muss.

Hi,

ich habe ein Query, das zwei Tabellen per INNER JOIN abfragt.
In etwa so:
SELECT * FROM Archive AS a INNER JOIN Meta AS m ON a.meta_id = m.meta_id
(SQLite 3.5.1)

Daraufhin fliegt folgende Exception, wenn ich versuche die DataTable zu laden:
Die Spalte 'meta_id1' hat die Einschränkung, dass sie eindeutig sein muss. Der Wert '161' ist bereits vorhanden.

Ich kann aktuell nicht nachvollziehen, warum bei 161 angeblich das Problem sein soll.
Die id ist nur einmal vorhanden.
Weshalb fliegt diese Exception? (Hoffe alle wichtigen Angaben gegeben zu haben)

Generell möchte ich im Anschluss zwei Objekte (Trennung wie Tabellen) daraus bauen.
Kann ich den Spaltennamen einer Tabelle einen prefix wie "a." mitgeben, um die zugehörigen Felder einfacher zuordnen zu können?
Denn leider sind einige spalten namentlich identisch.

F
10.010 Beiträge seit 2004
vor 10 Jahren

Natürlich kannst/solltest du statt "SELECT * ..." eine Vollqualifizierung machen.

R
212 Beiträge seit 2012
vor 10 Jahren

Ist der wert 161 denn 2mal vorhanden in der tabelle vorhanden?

C
2.121 Beiträge seit 2010
vor 10 Jahren

ON a.meta_id = m.meta_id
meta_id ist in zwei Spalten mit dem selben Namen im Ergebnis. Wahrscheinlich liegts daran. Daher der Tip von FZelle.
Wobei die Fehlermeldung schon recht irreführend ist.

R
212 Beiträge seit 2012
vor 10 Jahren

Daran sollte es nicht liegen die fehlermeldung geht außerdem zu der spalte meta_id1.
(foreign key´s und Primary key´s heißen be imir unter jeden datenbanksystem gleich und Joins waren da nochnie ein problem)

Welches datenbanksystem verwendest du eig Tweaky?

T
Tweaky Themenstarter:in
24 Beiträge seit 2010
vor 10 Jahren

Danke für die Tipps!

ich muss allerdings noch mal nachhaken.

Natürlich kannst/solltest du statt "SELECT * ..." eine Vollqualifizierung machen.

Ist mit "Vollqualifizierung" die manuelle Angabe der Spaltennamen gemeint?
Also SELECT a.meta_id , m.meta_id, ...

Ich wollte das bisher nicht, da ich so darauf achten muss, das eine Erweiterung Datenbankstruktur auch in allen Queries aufgenommen werden muss.

Cool wäre so was:
SELECT a.* , m.* FROM ...
Sodass die Spaltennamen um einen Prefix ergänzt würden, aber das geht leider nicht. Jedenfalls nicht so.

T
Tweaky Themenstarter:in
24 Beiträge seit 2010
vor 10 Jahren

@Robin0:
ich verwende SQLite 3.5.1 und lese über einen SQLiteDataReader die Daten in eine DataTable (unter .Net 3.5).
Btw. ich habe die Spalte nicht meta_id1 genannt... ist es denn nach deine Meinung normal, das die 1 ergänzt wird?

R
212 Beiträge seit 2012
vor 10 Jahren

was bekommst du denn raus wenn dus nicht in ein datatable schreibst sondern irgentwoandershin, hast du dann die überschrift "meta_id" doppelt(was ich nicht denke)

Oder versucht dein DataTable eine neue tabelle zu generieren mit Primary Key einschränkungen, und die zahl 161 in "meta_id1"(in diesem fall die PK Spalte) ist 2x vorhanden (eher warscheinlich).

F
10.010 Beiträge seit 2004
vor 10 Jahren

Ganz abgesehen das man die DataTable nicht über einen DataReader befüllt ( auch wenn man es kann ) sondern einen DataAdapter benutzt, ist es natürlich normal das die Namen bei Kollisionen angepasst werden.

T
Tweaky Themenstarter:in
24 Beiträge seit 2010
vor 10 Jahren

Was meinst du mit "nicht in die DataTable" schreiben?
Viel mehr ist da ja nicht....
Ich habe nur ein SQLiteCommand Objekt, dem ich das Query verpasse und dann wird "SQLiteDataReader reader = command.ExecuteReader();" ausgeführt.
Danach kommt schon die DataTable ins Spiel: "dt.Load(reader);".

--

Habe mal zum Test folgendes Query verwendet:
SELECT m.meta_id, a.meta_id ....

im reader hab ich dann beides mal nur "meta_id"
reader.GetName(0)
"meta_id"
reader.GetName(1)
"meta_id"

R
212 Beiträge seit 2012
vor 10 Jahren

Nehmen wir an du bekommst das raus warum auch immer das rauskommst...

meta_id1 | meta_id |meta_id
-----------| ----------- |---------
10-----------10-----------10
11-----------11-----------11
12-----------12-----------12
13-----------13-----------13
14-----------14-----------14
. .
. .


161----------161 ---------161|
161----------254 ---------254|
_______________________|

Wenn meta_id1 nun in deinem DataTable eine Primary Key einschränkung hat, kommt es zu einem fehler weil 161 x2 da ist.

T
Tweaky Themenstarter:in
24 Beiträge seit 2010
vor 10 Jahren

Ok, konnte das nun prüfen. Und ja, du hast natürlich recht... in der Verbindung, ist meta 161 zwei mal geladen, da zwei Archiveinträge darauf verweisen.

Nur wie lade ich sowas dann?

Zum background:
Ich hatte zuvor ein Query das mir die ids geholt hat und dann habe ich mir in ner Schleife zu den IDs die eigentlichen Daten nachgeladen, somit gab es das Problem bisher nicht. Allerdings ist das bei größeren Datenmengen ne ziemliche Krücke.
Daher dachte ich, gut lad ich gleich alles auf einmal und baue meine Objekte aus den gesamten Daten einer Row zusammen ...

T
Tweaky Themenstarter:in
24 Beiträge seit 2010
vor 10 Jahren

Aktuell sehe ich nur die Möglichkeit diese Spalte nicht auszulesen.
Das ist von den Werten her eh nur doppelt, da es ja die Verbindung zum Archiv ist und somit dort bereits enthalten ist.

Was ich nun aber nicht gut finde, ist wie oben genannte die Tatsache, das dieses Query angepasst werden muss, wenn ich die Tabellen erweitere.
Bisher habe ich nur DB und Objekt erweitern müssen.
Jetzt muss ich dann alle Queries dieser Art ebenfalls anpassen.

Ist eines davon übersehen worden, wird mein Objekt nicht vollständig geladen und würde beim Speichern einen Datenverlust bedeuten...

Kann ich ein SELECT *, BUT_NOT(m.meta) ... oder so was schreiben!?

Oder gibt es vielleicht eine "dumme" DataTable, der die Beschränkungen egal ist?
Diese macht hier im verbundenen zustand ohnehin keinen Sinn...

F
10.010 Beiträge seit 2004
vor 10 Jahren
  1. Eine Connection anlegen, dann ein Command erzeugen, dann den Reader Holen um dann die dataTable zu Befüllen ist viel zu viel Code. Das macht ein DataAdapter einfacher. Ausserdem verhindert es eine Connection durchgängig zu benutzen.

  2. Ich bin mir sicher das du schon lange mit einem Qualifizierten Sql fertig wärst, statt den letzt Beitrag zu formulieren.

  3. Faulheit ist nie ein richtiger Grund vernünftige Programmierung zu vernachlässigen.

C
2.121 Beiträge seit 2010
vor 10 Jahren

vor allem 2. ist natürlich gut 😃

Trotzdem noch eine Ergänzung, wenns tatsächlich mit * gehen muss, warum auch immer.
Dann lade die zwei Tabelleninhalte in getrennte DataTables.
Den JOIN kannst du ja drin lassen, lädst aber nur a.* und dann separat b.*. Dann kannst du die zwei Inhalte getrennt verarbeiten.

R
212 Beiträge seit 2012
vor 10 Jahren

Wenn die datensätze wirklich doppelt sind versuchst mit distinct.
http://www.w3schools.com/sql/sql_distinct.asp

oder änder den datensatz mit der 161 einfach um.

Zudem solltest du die Spalte der Tabelle in deiner Datenbank wo der datensatz doppelt vorkommt mit UNIQUE Einschränken.

T
67 Beiträge seit 2010
vor 10 Jahren

Um solche Probleme von vornherein zu vermeiden verwende ich bei meinen Tabellen für Schlüsselfelder immer die Kürzel PK (primary key) bzw. FK (foreign key). In deinem Fall hätte ich also die Schlüsselspalten PK_meta_id & FK_meta_id genannt. So hast Du anschließend auch kein Problem wenn Du mal schnell einen SQL mit SELECT * los lässt.

Allerdings muss ich FZelle zustimmen, dass man qualifizierte SQL Syntax verwenden sollte. SELECT * ist quick and dirty und nur zu gebrauchen wenn man kurz etwas testen will.

T
Tweaky Themenstarter:in
24 Beiträge seit 2010
vor 10 Jahren

@ Robin0:
Die Datenbank sollte sauber sein. Vielleicht hab ich mich da nicht sauber ausgedrückt.
Die Archiv Tabelle hat einen Verweis auf die Meta Tabelle (meta_id). Die Meta Tabelle hat diese meta_id als PK mit auto inc.
Da ist nichts doppelt. Es ist jedoch gestattet einen Meta Eintrag mehrfach in Archiv zu verwenden. Archiv wiederum hat nen eigenen PK der ebenfalls auto inc ist. Sollte hier passen.

@Talon, chilic, FZelle:
Ich Teile eure Meinung nur bedingt. Ich bin mir bewusst, das man lediglich das Abfragen sollte, was man auch braucht. In diesem Fall möchte ich jedoch die gesamten Daten in ein selbst gebasteltes DBO stecken, das weitere Features mitbringt. Dieses muss komplett sein. In sofern stellt * im Query sicher, das nicht irgendwo vergessen wurde ein Query zu ergänzen, nur weil ein Feld in der DB und dem Objekt selbst ergänzt wurde.

Mit anderen Worten nur Queries mit * sollten das DBO füllen um ein Datenleck zu vermeiden. Wenn ein DBO in einem selteneren Fall von einem Vollqualifiziertem Query, das nicht nachgezogen wurde, gebaut wird, fehlen Daten im DBO, die dann durch das Speichern selbigem verloren gehen.

... wo ich das grade schreibe fällt mir auf, dass das nicht passieren würde, da ich ja ein Feld im DBO erwarte, das im Query nicht mitkommt. Somit sollte es hier schon knallen.
Was man in seltenen Szenarien jedoch vielleicht erst nicht selbst mitbekommt.

Ich danke euch für die Ratschläge. Das ganze mal Diskutiert zu haben hat mir ein paar neue Erkenntnisse gebracht. 👍
Jetzt muss ich mir nur noch einig werden was ich will. 😉

F
10.010 Beiträge seit 2004
vor 10 Jahren

DBO?
Und warum dann DataTable?

Ich glaube du solltest mal erzählen was Du da wirklich machen willst, es hört sich für mich langsam so an, als wenn du dir das Leben unnötig schwer machst.

T
Tweaky Themenstarter:in
24 Beiträge seit 2010
vor 10 Jahren

Mag sein, das wäre nicht das erste mal 😃
Gibts da schon was von Haus aus? Hast du mal nen Link für mich?

Meine Dbos sind im Grunde ein Abbild eines Tabelleneintrags.
Es hat also für jede Tabellenspalte eine Klassenvariable.
Geladen wird es durch Übergabe der id (PK aus Tabelle).
So kann ich intern mit den Objekten arbeiten und kann wenn sich was ändert die Save Methode des Objektes verwenden um es wieder in die DB zu schreiben.

Manche haben noch weitere Methoden...

4.931 Beiträge seit 2008
vor 10 Jahren

Hallo,

warum verwendest du denn dann keinen Objektrelationalen Mapper (ORM)?

F
10.010 Beiträge seit 2004
vor 10 Jahren

Wie Th69 sagte, das nennt sich ORM und da gibt es zig verschiedene von, neben dem von MS ( Entity Framework ) auch z.b. NHibernate, OpenAccess und viele MicroORM wie Dapper, Massiv oder Simple.Data.

Die langweilige Arbeit die Klassen zu generieren kann dir dabei entweder eine Zugehörige UI ( OpenAccess ) oder T4 abnehmen, wenn es DB first ist.

Wenn du dann noch Migrations anschaust ist das schon mal ein einfaches Paket.

Ich brauche z.b. nur einen Connectionstring um fast den gesamten DAL incl. Migrations usw von einem Script generieren zu lassen.