# Keine doppelten Datensätze einfügen



## mysql@java (27. Aug 2009)

Hallo,

ich möchte bestimmte Datensätze aus einer Tabelle(artikel) in eine andere Tabelle(translation), die später für die Volltextsuche dienen soll, einfügen. Dabei soll aber geprüft werden, ob der Datensatz schon vorhanden ist. Zusätzlich ist noch zu sagen, die neue Tabelle wird immer wieder aktualierst werden und die alte beinhaltet ein paar Hunderttausend/Millionen Datensätze (so genau kann ich das net sagen), deshalb sind Lösungsvorschläge wie "nachdem Einfügen doppelte löschen oder von der einen Tabelle in wieder eine neue Tabelle verschieben und doppelte filtern" für mich schwachsinnig und können weggelassen werden.

Ich hatte ma was von UNIQUE gelesen, aber auch nur in Verbindung mit Integer. Nur die Spalte, die nicht doppelt sein darf, ist ein Text (bestehend aus mehreren Wörtern).
REPLACE und INSERT IGNORE hatte ich mal versucht, aber das haute dann auch net wirklich hin... oder ich weiß einfach net, wie man es anwendet..



Ein kleiner Auszug aus dem Programm



```
rs = st.executeQuery("Select a.ArtikelNr, a.Kurztext, b.Kurztext from artikel a, artikelfremdsprachen " + 
              "b where a.ArtikelID=b.ArtikelID and b.SprachenID=2"); 
     
    Statement st1 = con.createStatement();  
    while(rs.next()){ 
        st1.executeUpdate("insert into translation  (Deutsch, Quelle, QuelleNummer, Englisch) " + 
                "values ('"+rs.getString("a.Kurztext")+"', '1', '"+rs.getString("a.ArtikelNr")+"'," + 
                   " '"+rs.getString("b.Kurztext")+"') "); 
    }
```


Also beim ersten Durchlauf des Programms sind die Daten in der Tabelle ja korrekt, nur wenn ich dann weitere mache, fügt es ja immer die selben wieder ein.

Hoffe, jemand kann mir helfen <.<


Ähm ja.. vllt noch erwähnenswert, ich arbeite mit MySQL 5.0


EDIT: Mir is noch was eingefallen, nur weiß ich nicht wirklich, wie ich es realisieren soll:

```
select ID from translation where Deutsch = rs.getString("a.Kurztext")
            	  if ID > 0 dann vorhanden, d.h. nicht mehr in translation einfügen
```
Die Spalte ID is der Index von der Tabelle translation.


----------



## Michael... (27. Aug 2009)

Du könntest vor dem Einfügen per Select count... prüfen, ob der Eintrag schon vorhanden ist.
Oder Du könntest die entscheidenden Spalten als Primärschlüssel definieren, allerdings würde dann beim Einfügeversuch eine Exception geworfen werden.
Oder Du könntest zuerst den Eintrag - egal ob vorhanden oder nicht - löschen, und anschliessend neu einfügen.


----------



## velaluka (27. Aug 2009)

Hi Michael,
wie siehts den hiermit aus. Lass doch die DB tun was sie am Besten kann..
Z. B. so:
MySQL Ref 5.0
Hoffe es hilft 
Ciao velaluka


----------



## Landei (27. Aug 2009)

Schon beim Lesen mit DISTINCT Eindeutigkeit fordern.

```
rs = st.executeQuery(
          "Select DISTINCT a.ArtikelNr, a.Kurztext, b.Kurztext from artikel a, artikelfremdsprachen " + 
          "b where a.ArtikelID=b.ArtikelID and b.SprachenID=2");
```

<Philosophiemodus>Generell nicht versuchen, Probleme auf Krampf da zu lösen, wo sie stören, sondern da, wo sie verursacht werden.</Philosophiemodus>


----------



## Michael... (27. Aug 2009)

velaluka hat gesagt.:


> Hi Michael,
> wie siehts den hiermit aus. Lass doch die DB tun was sie am Besten kann..
> Z. B. so:
> MySQL Ref 5.0
> ...


Aber dazu müssen die Primärschluessel definiert sein, oder?? (Habe mich bisher mit mySQL nur rudimentär beschäftigt)


----------



## mysql@java (27. Aug 2009)

Das mit select count muss ich mir mal angucken, wie das geht. Hab keine Ahnung von SQL ^^

Die Daten jedesmal löschen und neu einfügen... naja..   Die werden schließlich immer mehr und bleiben nicht gleich, deshalb soll die Tabelle mit dem Programm immer wieder mal aktualisiert werden und nicht immer ganz neu geschrieben. 

Und nur eine Spalte ist entscheidend -> Spalte Deutsch
und Primärschlüssel is auf translation.ID


@Landei: das versteh ich nicht ganz... die Abfrage für die Daten die rein sollen, stimmt schon, nur will ich beim Einfügen keine doppelten rein. Ich hab es mal mit DISTINCT getestet und keine Auswirkung (hätte mich auch ein wenig gewundert)


----------



## Michael... (27. Aug 2009)

Eine Möglichkeit wäre folgendes:

```
rs = st.executeQuery("Select a.ArtikelNr, a.Kurztext, b.Kurztext from artikel a, artikelfremdsprachen "
	 + "b where a.ArtikelID=b.ArtikelID and b.SprachenID=2");
Statement st1 = con.createStatement();
Statement st2 = con.createStatement();
while(rs.next(){
	if (st2.executeQuery("Select * From translation Where Deutsch ='" + rs.getString(2) + "'")).next()) {
		st1.executeUpdate("insert into translation (Deutsch, Quelle, QuelleNummer, Englisch) "
			 + "values ('"+rs.getString(2)+"', '1', '"	+ rs.getString(1)+"'," + " '"+rs.getString(3)+"') ");
	}
}
```
Ist nur so hingeschmiert und lässt sich sicherlich noch optimieren.


----------



## velaluka (27. Aug 2009)

Hallo mysql@java,
schonmal in meinen Link gesehen? Wie wäre es mit 
	
	
	
	





```
INSERT into translation (Deutsch, Quelle, QuelleNummer, Englisch) 
     Select a.ArtikelNr, ..... from.....
    ON DUPLICATE KEY UPDATE deutsch="Aktuellen Text..oder so" ]
```
Dann lässt du die DB den ganzen Mist erledigen
Ansonsten würde ich dir noch empfehlen Prepared Statements zu verwenden...
Ciao velaluka


----------



## mysql@java (27. Aug 2009)

@Michael: es sah zwar gut aus, hat aber leider nichts gebracht >.<

@velaluka: ja, hatte mal reingeguckt und so hatte ich mit dem Programm auch angefangen, nur es net hinbekommen.. 
Ich versuch es mal damit nochmal.

zwischendrinn schonma danke für die ganze mühe


----------



## mysql@java (27. Aug 2009)

```
st1.executeUpdate("INSERT INTO bb_translation (csDeutsch, usQuelle, csQuelleNummer, csEnglisch) "+ 
            		" SELECT a.csArtnr, a.csKurztext, b.csKurztext from bb_artikel a, bb_artfsptxt " +
              		"b where a.ulArtikelID=b.ulArtikelID and b.ulSprachenID=2 ON DUPLICATE KEY UPDATE " +
              		"csDeutsch='"+rs.getString("a.csKurztext")+"' ");
```


```
java.sql.SQLException: Column count doesn't match value count at row 1
```

Naja.. ist eh klar. Aber anders fehlen mir wieder die ganzen Bedingungen und Bezüge. Ich krieg das mit einem Statement einfach nicht hin. Jetzt wurde mir wieder klar, warum ich zwei draus gemacht hab xD


----------



## velaluka (27. Aug 2009)

Hallo,
du willst einen Insert auf 4 Feldern machen, selektierst aber nur 3 in der Select Anweisung:noe:
Irgendwas möchte die DB da schon haben, ansonsten kannst du auch gleich die Spalte weglassen, ansonsten sieht das Statement doch gut aus. 


> Aber anders fehlen mir wieder die ganzen Bedingungen und Bezüge.


Wieso du kannst doch die where Bedienung genauso an dein Select hängen wie vorher auch???:L Oder andersherum: Innerhalb des Insert Statement kannst du ein Select mit all seinen Möglichkeiten absetzen um die Menge für den Insert einzugrenzen....
Ciao velaluka


----------



## mysql@java (27. Aug 2009)

Das größte Problem ist halt, dass ich keine Ahnung von SQL hab.
Und das die Select-Anweisung falsch is, weiß ich auch xD
Nur, ich hab keeiiiineeee Ahnung wie es machen soll >.<

Oki, mir is was eingefallen - nur, wie mach ich das mit "Quelle", die leg ich doch selbst fest, die is ja immer "1", dazu gibts keine Spalte sonst wo.


```
st1.executeUpdate("INSERT INTO bb_translation (csDeutsch, usQuelle, csQuelleNummer, csEnglisch) "+ 
            			" SELECT a.csKurztext, '1', a.csArtnr, b.csKurztext from bb_artikel a, bb_artfsptxt " +
              		"b where a.ulArtikelID=b.ulArtikelID and b.ulSprachenID=2 ON DUPLICATE KEY UPDATE " +
              		"csDeutsch='"+rs.getString("a.csKurztext")+"' ");
```

Die Version funktioniert auch net, jetzt sind sogar noch mehr Daten drinne.

Was macht dieses ON DUPLICATE KEY UPDATE eigentlich genau? Mir scheint, als würde es die bereits eingefügen Datensätze verdoppeln und diese dann wieder verdoppeln xD


----------



## Landei (27. Aug 2009)

mysql@java hat gesagt.:


> @Landei: das versteh ich nicht ganz... die Abfrage für die Daten die rein sollen, stimmt schon, nur will ich beim Einfügen keine doppelten rein. Ich hab es mal mit DISTINCT getestet und keine Auswirkung (hätte mich auch ein wenig gewundert)



Einen hab' ich noch, einen hab' ich noch!1!!

Probiere mal:

```
rs = st.executeQuery("Select a.ArtikelNr, a.Kurztext, b.Kurztext from artikel a, artikelfremdsprachen "
     + "b where a.ArtikelID=b.ArtikelID and b.SprachenID=2 Group By a.ArtikelNr, a.Kurztext, b.Kurztext");
```


----------



## Michael... (27. Aug 2009)

mysql@java hat gesagt.:


> Was macht dieses ON DUPLICATE KEY UPDATE eigentlich genau? Mir scheint, als würde es die bereits eingefügen Datensätze verdoppeln und diese dann wieder verdoppeln xD


Wenn ich es richtig verstehe, kann für den Fall, dass ein Datensatz mit demselben Schlüssel eingefügt werden soll, hier definiert werden welche Spalte mit welchem Wert aktualisiert werden soll.
Da Du aber als Schlüssel scheinbar eine ID per autoincrement verwendest, wird Dir das so nicht weiterhelfen.  - Bitte um Korrektur, falls ich da was falsch verstanden habe


----------



## mysql@java (27. Aug 2009)

@Landei: Es fügt mir beim ersten ersten Durchlauf des Programms zwar keine doppelten Datensätze ein, aber bei den nächsten Durchläufen fügt es die selben nochmal ein ohne zu prüfen, ob dieser schon vorhanden ist und da bringt mir DISTINCT oder GROUP BY nicht viel <.<


----------



## mysql@java (27. Aug 2009)

Michael... hat gesagt.:


> Wenn ich es richtig verstehe, kann für den Fall, dass ein Datensatz mit demselben Schlüssel eingefügt werden soll, hier definiert werden welche Spalte mit welchem Wert aktualisiert werden soll.
> Da Du aber als Schlüssel scheinbar eine ID per autoincrement verwendest, wird Dir das so nicht weiterhelfen.  - Bitte um Korrektur, falls ich da was falsch verstanden habe



Ja, das stimmt.


----------



## mysql@java (27. Aug 2009)

```
DROP TABLE IF EXISTS TRANSLATION; 
    create table TRANSLATION 
    ( 
       ID INT UNSIGNED NOT NULL AUTO_INCREMENT,      
       Quelle    SMALLINT UNSIGNED DEFAULT 0 COMMENT '1=Artikel,2=Beleg', 
       QuelleNummer CHAR(25)  DEFAULT '' COMMENT 'wenn Quelle=1 steht hier Artikelnr, wenn 2 dann die  Belegnr'  , 
       Deutsch text, 
       Englisch text, 
    PRIMARY KEY (ID) 
    ) 
    TYPE = MYISAM 
    ;
```

Könnte jemand die Spalte Deutsch auf UNIQUE setzen?


----------



## Michael... (27. Aug 2009)

mysql@java hat gesagt.:


> Könnte jemand die Spalte Deutsch auf UNIQUE setzen?




```
create table TRANSLATION ( 
       ID INT UNSIGNED NOT NULL AUTO_INCREMENT,      
       Quelle    SMALLINT UNSIGNED DEFAULT 0 COMMENT '1=Artikel,2=Beleg', 
       QuelleNummer CHAR(25)  DEFAULT '' COMMENT 'wenn Quelle=1 steht hier Artikelnr, wenn 2 dann die  Belegnr'  , 
       Deutsch text, 
       Englisch text, 
       PRIMARY KEY (ID),
       UNIQUE(Deutsch)
)
```
Kann es denn wirklich nicht vorkommen, dass bei unterschiedlichen Artikel der gleiche deutsche Text vorkommt??


----------



## maki (27. Aug 2009)

> TYPE = MYISAM


Davon kann man nur abraten, der "bessere" Typ wäre INNODB.


----------



## mysql@java (27. Aug 2009)

Die Tabelle translation hat 5 Spalten: ID, Quelle(=SprachenID), Quellennummer(=Artikelnummer), Deutsch(=Kurztext von Artikel), Englisch(=Kurztext Fremsprachen).
Grundsätzlich dient die Tabelle translation nur für die Volltextsuche(muss noch im TabellenQuellcode eingebaut werden später). Z.B. Suche ich alle Artikel, die das Wort "Fangrahmen" in der Beschreibung drinne haben. Dazu muss ich aber doch nicht die ganze Datenbank durchsuchen. Es reicht, wenn jede Artikelbeschreibung nur EINMAL in der Tabelle vorhanden ist, denn mit der Quellennummer kann man dann auf die einzelnen Artikel zurückgreifen. Das erspart Zeit und die Performance wird nicht so runtergezogen, als wenn es ein paar Millionen Datensätze pro Tabelle einzeln durchsuchen muss.

Achja: So einfach geht das mit UNIQUE nicht, hatte ich selbst schon so versucht.

```
1170 - BLOB/TEXT column 'Deutsch' used in key specification without a key length
```

Das heißt dann wohl, ich könnte kein TEXT Format nehmen, nur was bleibt? VARCHAR? Wie viel geht da maximal? 255? Mhm.. das dürfte nun wirklich nicht reichen.. -_-


----------



## mysql@java (27. Aug 2009)

maki hat gesagt.:


> Davon kann man nur abraten, der "bessere" Typ wäre INNODB.



Nein, das geht leider nicht, brauche MYISAM für die Volltextsuche.


----------



## mysql@java (28. Aug 2009)

Es scheint, als wäre die Lösung gefunden. Bin mir zwar noch net 100%-ig sicher, ob sie auch genau das macht, was ich will, aber werde wohl noch ein paar Tests machen, um mir vollkommen sicher zu sein.


```
rs = st.executeQuery("Select a.csArtnr, a.csKurztext,b.csKurztext from artikel a, artfsptxt " +
           		"b where a.ulArtikelID=b.ulArtikelID and b.ulSprachenID=2");
             
           	Statement st1 = con.createStatement(); 
                         
           // Kurztext von Artikel nach translation übertragen
            while(rs.next()){ 
        		// prüfen, ob schon vorhanden
            	rs2 = st1.executeQuery("select ulID from translation where csDeutsch = '"+rs.getString("a.csKurztext")+"' ");
            	boolean ok = rs2.next();
            	if (ok && rs2.getInt(1) > 0)continue;
            		
            	// falls noch nicht vorhanden 

            		st1.executeUpdate("insert into translation  (csDeutsch, usQuelle, csQuelleNummer, csEnglisch) " +
            				"values ('"+rs.getString("a.csKurztext")+"', '1', '"+rs.getString("a.csArtnr")+"'," +
            				" '"+rs.getString("b.csKurztext")+"') ");
            	
            }
```


----------



## Landei (28. Aug 2009)

Sollte funktionieren, nur die Performance wird nicht so doll sein. Vielleicht kann man eine Stored Procedure schreiben, die diesen Check selbst macht und dann einfügt oder halt nicht.


----------



## mysql@java (28. Aug 2009)

Da die Tabelle translation eh noch Volltextindex bekommt, muss nur noch die Syntax angepasst werden und dann dürfte das auch weiter kein Problem sein.


----------



## mysql@java (28. Aug 2009)

Naja, für mich hat sich das hier erstmal erledigt, werde keine weiteren Arbeiten an diesem Programm/Datenbank machen. War ja auch nicht für mich.

Trotzdem danke für die Hilfe.

Jemand anders wird meine Arbeit wohl zu ende bringen


----------

