• Hallo liebe Userinnen und User,

    nach bereits längeren Planungen und Vorbereitungen sind wir nun von vBulletin auf Xenforo umgestiegen. Die Umstellung musste leider aufgrund der Serverprobleme der letzten Tage notgedrungen vorverlegt werden. Das neue Forum ist soweit voll funktionsfähig, allerdings sind noch nicht alle der gewohnten Funktionen vorhanden. Nach Möglichkeit werden wir sie in den nächsten Wochen nachrüsten. Dafür sollte es nun einige der Probleme lösen, die wir in den letzten Tagen, Wochen und Monaten hatten. Auch der Server ist nun potenter als bei unserem alten Hoster, wodurch wir nun langfristig den Tank mit Bytes vollgetankt haben.

    Anfangs mag die neue Boardsoftware etwas ungewohnt sein, aber man findet sich recht schnell ein. Wir wissen, dass ihr alle Gewohnheitstiere seid, aber gebt dem neuen Board eine Chance.
    Sollte etwas der neuen oder auch gewohnten Funktionen unklar sein, könnt ihr den "Wo issn da der Button zu"-Thread im Feedback nutzen. Bugs meldet ihr bitte im Bugtracker, es wird sicher welche geben die uns noch nicht aufgefallen sind. Ich werde das dann versuchen, halbwegs im Startbeitrag übersichtlich zu halten, was an Arbeit noch aussteht.

    Neu ist, dass die Boardsoftware deutlich besser für Mobiltelefone und diverse Endgeräte geeignet ist und nun auch im mobilen Style alle Funktionen verfügbar sind. Am Desktop findet ihr oben rechts sowohl den Umschalter zwischen hellem und dunklem Style. Am Handy ist der Hell-/Dunkelschalter am Ende der Seite. Damit sollte zukünftig jeder sein Board so konfigurieren können, wie es ihm am liebsten ist.


    Die restlichen Funktionen sollten eigentlich soweit wie gewohnt funktionieren. Einfach mal ein wenig damit spielen oder bei Unklarheiten im Thread nachfragen. Viel Spaß im ngb 2.0.

SQL (Postgres) ID von Kategorietable einfügen

RedlightX

Bekannter NGBler

Registriert
18 Juli 2013
Beiträge
1.185
Hallo zusammen,
ich komme mir unheimlich dumm vor, aber ich stehe auf dem Schlauch.

Angenommen, ich habe 2 Tabellen.

1.) Produkte

- ID (Auto incr.)
- Name
- Kategorie_id


2.) Kategorien

- ID (Auto incr.)
- Kategoriename


Da es sich hierbei um eine größere CSV handelt, habe ich, bevor ich die eigentliche Produkttabelle inserte, andere Tabellen (hier: Kategorien) vorher gefüllt.
Alles klappt soweit. Die CSV lasse ich mitteln NodeJS in die Datenbank schreiben - es hapert jetzt nur noch an meinem Verständnis. Die gesamte CSV ist erstmal in einem Array. Soweit, so gut.

Nun möchte ich, nachdem alle "Nebenkriegsschauplätze" bereits mit Daten gefüllt sind, die fehlenden Produkt-IDs aus den anderen Tabellen, in die Haupt-Tabelle (Produkte) bekommen.
Da ich im Array bereits alle Daten habe, ist es aus dem ersten Blick etwas wie:

"Select id FROM Kategorien WHERE Kategoriename = array.kategoriename"

Ich möchte allerdings in die Datenbank Inserten.
Ein wenig herumgesucht habe ich und folgendes probiert:

INSERT INTO Produkte (Kategorie_id) SELECT id FROM Kategorien WHERE Kategoriename =array.kategoriename"

Das kann so nicht funktionieren, da er nicht weiss, welchem Produkt er genau diese ID in das Feld schreiben soll.

Ich stehe auf dem Schlauch.... habe ich etwas vergessen? Ich habe bereits bei der Tabellenerstellung Fremd/Primärschlüssel zugewiesen. Nützt natürlich erstmal nichts, wenn ich nicht weiss, wie ich diese genau hineinschreiben kann...


Ich wäre für Hilfe sehr sehr dankbar :T
 

KaPiTN

♪♪♫ wild at heart ♪♫♫♪

Registriert
14 Juli 2013
Beiträge
29.138
War denn in der csv eine Verbindung über die IDs der Kategorie? Oder eine andere Verbindung?
Aber selbst wenn, Du legst mit Auto incr. doch wohl neue IDs für die Kategorien an.

Woher soll die Information/Zuordnung kommen?
 

RedlightX

Bekannter NGBler

Registriert
18 Juli 2013
Beiträge
1.185
  • Thread Starter Thread Starter
  • #3
In der CSV war alles nur eingeklatscht und ich möchte es natürlich auf mehrere Tabellen splitten :)

Die Zuordnung muss ich beim Import mittels nodejs selbst vornehmen. Das ist ja möglich. Da muss dann Anhand eines übereinstimmenden Namens die ID ausgegeben und eingetragen werden.
Ein wenig zum Verzweifeln, dabei wollte ich alls nur sauber geordnet haben, damit die Zugriffszeiten halbwegs stimmen...
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.557
Kurze Frage, ist der Produkt Kategorie Index in Tabelle 1 lückenlos durchnummeriert? Oder gibt es Lücken in dem Zähler?

Wenn du keine Lücken hast:

Um einen Wert mit fixer Id neu anzulegen/zu ergänzen:
[src=text]INSERT INTO Kategorien(ID, KategorieName) VALUES (Kategorie_id, 'kategorieName') ON CONFLICT DO NOTHING[/src]

Das bewirkt das bei einem Konflikt, wenn schon vorhanden, nichts weiter getan wird. Alternative wäre zum Beispiel explizites überschreiben, falls schon unter der "ID" ein Eintrag vorhanden ist.

Um dann den Bezug zu "ID" und "KategorieName" zu bekommen, würdest du einmalig über alle Einträge/Produkte iterieren und die ID entsprechend für die Kategorie setzen.

Wenn du dann, sagen wir "lückenlos" 100 Kategorien eingebunden hast, kannst du den Auto Increment auch noch einmal setzen, damit alle Produkte größer als 100 eingetragen werden und nichts überschreiben:
[src=text]ALTER SEQUENCE RESTART WITH 100 OWNED BY Kategorien.ID[/src]

101 ist hier der nächste Zähler im Auto-Increment.
Siehe hier: https://www.postgresql.org/docs/10/sql-altersequence.html
 

Rakorium-M

NGBler

Registriert
14 Juli 2013
Beiträge
413
Wenn ich dich richtig verstehe suchst du nach so einem Befehl: [src=postgresql]INSERT INTO Produkte (Name, Kategorie_id) VALUES ('array.produktname', (SELECT id FROM Kategorien WHERE Kategoriename = 'array.kategoriename'));[/src]Damit fügst du ein Produkt in die Liste hinzu, wobei der Kategoriename automatisch in die ID übersetzt wird, bzw [kw]NULL[/kw] in der Spalte landet, falls die Kategorie noch nicht existiert.
 

RedlightX

Bekannter NGBler

Registriert
18 Juli 2013
Beiträge
1.185
  • Thread Starter Thread Starter
  • #6
Danke, Raktorium - da kommen wir der Sache schon sehr nahe :T
Da die Grundaten - bis auf die IDs - bereits in der Tabelle Produkte vorhanden sind, habe ich es auch mit einem Update versucht

Deshalb habe ich es im Nachhinein auch mit einem Update versucht, aber ich bekomme nur einen Fehler... "error: syntax error at or near “UPDATE products” :(
Wenn ich den Befehl manuell absetze, klappt es ohne Probleme.

"UPDATE*products SET description_id=*'57' WHERE*ean = '4030152026357";

Aber theoretisch muss ich die Funktion umschreiben, und es direkt mit mehreren Subqueries lösen (wie dein Beispiel, nur etwas umfangreicher)....


Danke für eure Hilfe :T

Edit:

Ich habe die Funktion jetzt umgeschrieben, sodass er Produkt für Produkt in die DB schreibt. Allerdings kämpfe ich noch mit den Single/Doublequotes :(

[src=javascript]
pool
.query(
"INSERT INTO products (product_name, ean,description_id)
VALUES ($1,$2,$3)",
[
itemData.product_name,
itemData.ean,
'SELECT id from product_description WHERE description = "+itemData.description"'
]
)
.then(res => console.log('ok'))
.catch(err =>console.error("Error executing query", err.stack)
);
[/src]

Folgender Fehler kommt: Error executing query error: invalid input syntax for integer: "SELECT id
Ich nutze übrigens Node-Postgres. Manuelles ausführen funktioniert bereits...
 
Zuletzt bearbeitet:

X-Coder

Aktiver NGBler

Registriert
14 Juli 2013
Beiträge
149
Bei deiner Lösung kommt durch die Escape-Funktion wahrscheinlich so etwas heraus, da der Subselect so als String durch das Escaping nochmal mit Quotes eingesetzt wird, dadurch dann die Quotes zusätzlich an der falschen Stelle bekommt und du so gleichzeitig eine Injection-Anfälligkeit eingebaut hast.
[src=mysql]INSERT INTO products (product_name, ean,description_id) VALUES ("product_name", "ean", "SELECT id from product_description WHERE description = "description"")[/src]

Dein Code sollte daher eher so aussehen:[src=javascript]
pool
.query(
"INSERT INTO products (product_name, ean,description_id)
VALUES ($1, $2, (SELECT id from product_description WHERE description = $3 LIMIT 1))",
[
itemData.product_name,
itemData.ean,
itemData.description
]
)
.then(res => console.log('ok'))
.catch(err =>console.error("Error executing query", err.stack)
);

[/src]
 
Zuletzt bearbeitet:

RedlightX

Bekannter NGBler

Registriert
18 Juli 2013
Beiträge
1.185
  • Thread Starter Thread Starter
  • #8
Danke :T

Ich bin jetzt ebenfalls in diesem Punkt, wo ich die Query und die Values umgebaut habe:

[src=javascript]
const testquery = "INSERT INTO products (product_name, ean,description_id) VALUES ($1,$2,(SELECT id from product_description WHERE description = $3))) RETURNING *;";
const values = [
itemData.product_name,
itemData.ean,
itemData.description,
...
];
pool.query(testquery, values, (err, res) => {
if (err) console.log(err);
console.log(res.rows[0]);
});
[/src]

Es werden auch statt knapp 1k Produkte immer zwischen 4 und 11 Stück korrekt importiert, allerdings hört das Script dann auf zu arbeiten, ohne einen Fehler auszugeben. Ich gehe wirklich davon aus, dass es mit dem blöden "Textvergleich" der product_description zutun hat. Ist ja auch nich sonderlich elegant :/

Gibt es eine andere Möglichkeit die description korrekt miteinander zu vergleichen, oder wenigstens eine Fehlerausgabe zu bekommen?


Danke für eure Mühe :)
 

X-Coder

Aktiver NGBler

Registriert
14 Juli 2013
Beiträge
149
Naja, wenn description nicht matched, ist ja kein Fehler, daher wird es auch kein Error-Log dazu geben, die Datensätze werden dann einfach übersprungen.

Du kannst es aber einfach debuggen indem du dir die generierten SQLs ausgeben lässt und die, welche nicht funktioniert haben, genauer anschaust.
 

Rakorium-M

NGBler

Registriert
14 Juli 2013
Beiträge
413
Wenn keine Description gefunden wird, sollte der Eintrag trotzdem eingefügt werden - mit NULL in der Spalte. Wenn die description_id natürlich auf [kw]NOT NULL[/kw] gesetzt wurde soll ein Fehler fliegen.
Hängt das Script oder stürzt es ohne Meldung ab? Und passiert das immer beim selben Produkt (lass dir das mal vor dem Query ausgeben)?

Noch einen anderen Verdacht hab ich (rein spekulativ): Du feuerst deine Querys ab, ohne auf das Ergebnis des vorherigen Befehls zu warten (die Funktion mit den logs wird ja asynchron ausgeführt). Evtl. verstopfst du damit irgendwelche Warteschlangen / blockierst Threads / läufst ins connection limit des Servers. Kannst du das so umbauen, dass jedes Query erst ausgeführt wird, wenn das vorherige abgeschlossen ist? [kw]await[/kw] dürfte das NodeJS-Schlagwort dafür sein.
 

RedlightX

Bekannter NGBler

Registriert
18 Juli 2013
Beiträge
1.185
  • Thread Starter Thread Starter
  • #11
Danke - das hilft :T
Wenn keine Description gefunden wird, kann null drin stehen. Das funktioniert auch - bzw wurden im Vorfeld Produkte ohne Description ausgeschlossen. :)

Ich habe einmal versucht, statt die description_id, die ganze description in das Feld zu schreiben, weil ich annahm, dass es da einen Fehler beim Vergleichen (Select id from produt_description WHERE description = $3). Aber daran liegt es offenbar nicht.

Der letzte Absatz macht für mich sinn! Das werde ich auf jeden Fall ausprobieren, ich muss jetzt nur sehen, wie ich es am geschicktesten einbaue.
Kleine Test-CSV mit maximal 100 Produkten funktionieren in der Regel. Also lässt das wirklich irgendwo auf die connection und Limits schließen.

Da ich immer mittels console.log() den erfolgreich eingetragenen Datensatz ausgebe, blieb es einfach still und nichts tat sich mehr. Korrekt beendet hat sich das Script nicht.


Es ist das erste Mal, dass ich etwas mit nodeJS mache und async ist komplett neu für mich. Ich hätte dafür eher PHP genommen, aber auf die Nerverei mit Timeouts etc hatte ich wenig Lust, vor allem da die CSV so groß sind...

Edit: Ja, es hört dann immer beim selben Produkt auf zu arbeiten. Aber dort ist nichts in den Datensätzen, was auf einen Fehler schliessen lässt. Wobei es durch das async ja nicht zwangsläufig Schuld genau dieser letzten Ausgabe sein muss :/
 

Rakorium-M

NGBler

Registriert
14 Juli 2013
Beiträge
413
Was passiert denn wenn du die ersten 10 Produkte überspringst? Hängt das Script beim selben Eintrag (=> Problem mit dem Eintrag) oder nach gleich vielen Einträgen (=> Limit)?

Btw: PHP kann man wie NodeJS auch als Konsolen-Script ausführen, einfach [kw]php <dateiname>[/kw] aufrufen. Dabei gibt's auch keine Timeouts. Alternativ kann man mit set_time_limit den Timeout zurücksetzen.
 

RedlightX

Bekannter NGBler

Registriert
18 Juli 2013
Beiträge
1.185
  • Thread Starter Thread Starter
  • #13
Wenn ich ab einem gewissen Zähler (i = 100) etc starten wollte, oder anderweitig begrenzen wollte, tat sich garnichts.

Ich war zwischenzeitlich so frustriert, sodass ich es in PHP gelöst habe und alles läuft einwandfrei. Merkbar langsamer, aber ich habe ja heute gelernt, dass ich das Ding einfach im Terminal laufen lassen kann :D

Danke für eure Hilfe :)
 
Oben