Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi variabler Tabellenname in SQL-Abfrage (https://www.delphipraxis.net/194026-variabler-tabellenname-sql-abfrage.html)

Luca Haas 9. Okt 2017 10:05

variabler Tabellenname in SQL-Abfrage
 
Hi Leute,
ich entwickle derzeit eine Suchfunktion, mit der ich eine Datenbank durchsuchen kann.
Dafür habe ich erst zwei Edits genommen, denen eine feste Spalte in der Tabelle zugewiesen (dass diese nur die eine Spalte durchsucht, was auch problemlos funktioniert
Delphi-Quellcode:
SQLBefehl := 'SELECT * FROM KST_Lagerbewertung';
if (Edit1.Text <> '') then
  SQLBefehl := SQLBefehl + (' WHERE Artikelbezeichnung LIKE ''' + StringReplace(Edit1.Text, '*', '%', [rfReplaceAll]) + '%''');
Jetzt versuche ich allerdings eine dritte Suchfunktion hinzuzufügen, wo der Spaltenname nicht vorgegeben ist, sondern durch eine ComboBox ausgewählt werden kann. Ich versuche den Spaltennamen über eine Variable (CB1Spalte) in die SQL-Abfrage einzugeben, allerdings weiß ich nicht wie ich der Abfrage klarmache, dass ich aktuell eine Variable benutze und diese nicht der Spaltenname ist
Delphi-Quellcode:
  if (Edit3.Text <> '') then
  begin
    CB1Spalte := ComboBox1.Text;
    SQLBefehl := SQLBefehl + (' WHERE ''CB1Spalte'' LIKE ''' + StringReplace(Edit3.Text, '+', '%', [rfReplaceAll]) + '%''');
  end;
Jetzt meine Frage, wie genau kann ich Delphi, bzw der SQL-Abfrage, klarmachen, dass CB1Soalte nur eine Variable ist und ich deren Wert benötige ?

jobo 9. Okt 2017 10:11

AW: variabler Tabellenname in SQL-Abfrage
 
Du kannst es der Abfrage nicht "klarmachen"
Der Spaltenname muss aus Deiner Komobox entnommen werden und im Klartext in die Abfrage eingebaut werden.

p.s.: dabei keine Hochkommata verwenden, sonst wird es für eine Textkonstante gehalten.

Luca Haas 9. Okt 2017 10:23

AW: variabler Tabellenname in SQL-Abfrage
 
Wie entnehme ich den Spaltennamen den aus der Combobox, etwa mit Combobox1.Text ?

jobo 9. Okt 2017 11:21

AW: variabler Tabellenname in SQL-Abfrage
 
Ja, machst Du doch schon. Du musst die Variable halt auch so mit + (Textkokatenierung) einbinden, wie Deinen Suchwert (Den man im Übrigen besser als Parameter einbinden würde.
Aber alles der Reihe nach.

Luca Haas 9. Okt 2017 11:31

AW: variabler Tabellenname in SQL-Abfrage
 
Es tut mir leid, aber so genau verstehe ich nicht wie du das mit dem + meinst. Ich programmiere noch nicht so lange und kenne das leider noch nicht
Delphi-Quellcode:
  begin
    CB1Spalte := ComboBox1.Text;
    SQLBefehl := SQLBefehl + (' WHERE +CB1Spalte+ LIKE ''%' + StringReplace(Edit3.Text, '*', '%', [rfReplaceAll]) + '%''');
  end;
Es sieht jetzt so aus, allerdings erhalte ich noch eine Fehlermeldung, wegen falscher Syntax in der Nähe von LIKE

Jumpy 9. Okt 2017 11:35

AW: variabler Tabellenname in SQL-Abfrage
 
Zitat:

Zitat von Luca Haas (Beitrag 1382888)
Es tut mir leid, aber so genau verstehe ich nicht wie du das mit dem + meinst. Ich programmiere noch nicht so lange und kenne das leider noch nicht
Delphi-Quellcode:
  begin
    CB1Spalte := ComboBox1.Text;
    SQLBefehl := SQLBefehl + (' WHERE +CB1Spalte+ LIKE ''%' + StringReplace(Edit3.Text, '*', '%', [rfReplaceAll]) + '%''');
  end;
Es sieht jetzt so aus, allerdings erhalte ich noch eine Fehlermeldung, wegen falscher Syntax in der Nähe von LIKE

Delphi-Quellcode:
  begin
    CB1Spalte := ComboBox1.Text;
    SQLBefehl := SQLBefehl + (' WHERE '+CB1Spalte+' LIKE ''%' + StringReplace(Edit3.Text, '*', '%', [rfReplaceAll]) + '%''');
  end;

Luca Haas 9. Okt 2017 11:37

AW: variabler Tabellenname in SQL-Abfrage
 
So klappt es, danke schön :thumb:

nahpets 9. Okt 2017 11:46

AW: variabler Tabellenname in SQL-Abfrage
 
Suchst Du sowas in der Art? (Auch wenn's schon zu spät ist ;-))
Delphi-Quellcode:
function CreateSQL(ATabellen : String; ASpalten : String; ASuchbegriff : String) : String;
var
  SQLSuchbegriff : String;
begin
  Result := Format('select * from %s',[ATabelle]);
  if (ASpalten <> '')
  and (ASuchbegriff <> '') then begin
    SQLSuchbegriff := Trim(ASuchbegriff);
    SQLSuchbegriff := StringReplace(SQLSuchbegriff, '*', '%', [rfReplaceAll]);
    SQLSuchbegriff := StringReplace(SQLSuchbegriff, '?', '_', [rfReplaceAll])
    SQLSuchbegriff := QuotedStr(SQLSuchbegriff + '%');
    Result := Format('%s where %s like %s',[Result,ASpalte,SQLSuchbegriff]);
  end;
end;

// Aufruf
SQLBefehl := CreateSQL(ComboBoxTabellennamen.Text, ComboBoxSpaltennamen.Text, EditSuchbegriff.Text);

himitsu 9. Okt 2017 19:42

AW: variabler Tabellenname in SQL-Abfrage
 
Keine Hochkomma stimmt nicht.
Es kommt aber auf die Syntax des jeweiligen DBMS drauf an.

Denn es gibt verschiedene "Hochkomma" ... " ' ´ ` usw.
und die werden unterschiedlich verwendet, also entweder für "Strings" oder eben auch für "Namen".


Derartige zusammengebaute SQLs verleiten doch nahezu zu SQL-Injections? :stupid:
Es gibt garantiert irgendwo in den verwendeten Zugriffskomponenten entsprechende Funktionen zum "Quoten und Escapen" von Werten/String und von Bezeichnern, welche man bei sowas besser auch verwenden sollte.

Und wenn auch ständig immerwieder welche Delphi-Referenz durchsuchenQuotedStr verwenden, so ist das doch eigentlich falsch, denn das ist für "Pascal-Strings" und nicht für "SQL-Bezeichner", welche nahezu immer einer komplett anderen Syntax unterliegen.

nahpets 9. Okt 2017 22:21

AW: variabler Tabellenname in SQL-Abfrage
 
Dann muss man mit Parametern arbeiten (wobei man Tabellenanem nicht über Parameter in eine Abfrage bekommt), ohne zu wissen, was für Komponenten genutzt werden, ist da ein Beispiel schwierig.

Da ist dann QuotedStr ungefähr genausogut wie eine Reihe von ', wie im ersten Post bei

Delphi-Quellcode:
SQLBefehl := SQLBefehl + (' WHERE Artikelbezeichnung LIKE ''' + StringReplace(Edit1.Text, '*', '%', [rfReplaceAll]) + '%''');


Frei nach dem Motto, passt meistens aber nicht immer und ja, beides ist bekanntermaßen nicht perfekt.

jobo 9. Okt 2017 22:48

AW: variabler Tabellenname in SQL-Abfrage
 
Also ich bezeichne es wie folgt:
Hochkomma = '
Anführungszeichen = "
Tick = ´
Backtick = `

Der entscheidende Punkt für den Anfang ist doch erstmal:
Tabellen und Feldnamen gehen idealerweise im SQL "Fließtext" einfach so ohne weiteres ein, keine Hochkomma oder wie auch immer.
Es gibt in mysql (besonders) oder auch woanders (Access dann noch mit eckigen Klammern) dieses Theater, damit man auch Leerzeichen und Chinesisch usw. in die Feldbezeichner bringen kann.
Ich hab es lieber clean, ASCII ANSI Bezeichner auf Englisch und fertig.

Das ganze Problem hat erstmal nichts damit zu tun, wie ich mein SQL dann zusammensetze mit variablen Spalten.
Einfache String Konkatenierung. Dabei muss dann im Quelltext ggF. escaped werden.

Das nächste Problem ist dann die Nutzung von Parametern für die Werteangaben. Das sollte man natürlich machen, wegen kann man überall nachlesen.

Dieses Verfahren mit den Parametern funktioniert nach meiner Kenntnis aber nicht mit Feldnamen.

Im Ergebnis habe ich also Parameter eingesetzt und bin u.U. trotzdem noch nicht gegen Injection gefeit.
Das kann man aber doch wohl verhindern, indem man die Feldnamen nicht beliebig macht, sondern Wertelisten vorgibt, oder?
Also mit einer Combobox ohne Editmöglichkeit.

blawen 9. Okt 2017 22:52

AW: variabler Tabellenname in SQL-Abfrage
 
Zitat:

Zitat von Luca Haas (Beitrag 1382888)
Es tut mir leid, aber so genau verstehe ich nicht wie du das mit dem + meinst. Ich programmiere noch nicht so lange und kenne das leider noch nicht
Delphi-Quellcode:
  begin
    CB1Spalte := ComboBox1.Text;
    SQLBefehl := SQLBefehl + (' WHERE +CB1Spalte+ LIKE ''%' + StringReplace(Edit3.Text, '*', '%', [rfReplaceAll]) + '%''');
  end;
Es sieht jetzt so aus, allerdings erhalte ich noch eine Fehlermeldung, wegen falscher Syntax in der Nähe von LIKE

Wieso so "kompliziert"?
Ich würde es Sinngemäss so lösen
Delphi-Quellcode:
Query.SQL.Text := 'SELECT * FROM ' + ComboBox1.Text + ' WHERE...

p80286 10. Okt 2017 08:56

AW: variabler Tabellenname in SQL-Abfrage
 
Zitat:

Zitat von jobo (Beitrag 1382967)
Dieses Verfahren mit den Parametern funktioniert nach meiner Kenntnis aber nicht mit Feldnamen.

Du könntest Dir hier mit einem "Wörterbuch" der vorhandenen Tabellen und Felder weiterhelfen. Damit ist dann auch die Gefahr der Injection gemindert.

Gruß
K-H

HolgerX 10. Okt 2017 09:50

AW: variabler Tabellenname in SQL-Abfrage
 
Hmm..

Zitat:

Zitat von p80286 (Beitrag 1382987)
Du könntest Dir hier mit einem "Wörterbuch" der vorhandenen Tabellen und Felder weiterhelfen. Damit ist dann auch die Gefahr der Injection gemindert.

Je nach Verbindung zur Datenbank kannst Du von der Datenbank auch die vorhandenen Tabellen und Felder auslesen und somit dein 'Wörterbuch' dynamisch erstellen. ;)

nahpets 10. Okt 2017 11:27

AW: variabler Tabellenname in SQL-Abfrage
 
Die TAdoConnction hat 'ne Methode zum Holen der Tabellennamen. Das Ergebnis wird in eine Stringliste geliefert. Dafür kann man ComboBox.Items nehmen.

Ebenfalls gibt es eine Methode zum Holen der Spaltennamen einer Tabelle, auch hier ist das Ergebnis eine Stringliste, kann also Items einer weiteren ComboBox sein.

Wenn sich der ItemIndex der Combobox für die Tabellennamen ändert, befüllt man dann die ComboBox für die Spaltennamen entsprechen (geht einfach über die Ereignisroutinen).

Beim Zusammenbauen des SQLs nimmt man dann nicht mehr ComboBox.Text sondern ComboBox.Items[ComboBox.ItemIndex] und schon hat man eine sichere Auswahl von Tabellen und Spaltennamen.

Wenn der ItemIndex der ComboBoxen kleiner 0 ist, gibt man dem Anwender ggfls. eins auf die Finger, weil er was ungültiges in ComboBox.Text eingegeben hat oder bei ItemIndex = -1 macht man einfach nichts. (Button zum Schließen der Suchmaske disablen, keine Zuweisung des SQLs an die Query ...)

Damit der Anwender über die Eingabe des Suchbegriffes keinen "Mist" mehr machen kann, fügt man, statt der Eingabe, in das SQL einen Parameter ein und befüllt diesen dann mit der Eingabe. Dadurch spart man sich dann auch direkt das Rummhampeln mit ' und '' und ''' und QuotedStr.

p80286 10. Okt 2017 12:23

AW: variabler Tabellenname in SQL-Abfrage
 
Zitat:

Zitat von nahpets (Beitrag 1383018)
Die TAdoConnction hat 'ne Methode zum Holen der Tabellennamen. Das Ergebnis wird in eine Stringliste geliefert. Dafür kann man ComboBox.Items nehmen.

Die Funktion ist mit Vorsicht zu genießen, da nicht alle Views/Tabellen zurück geliefert werden (ist je nach DB unterschiedlich) darum lieber die DB direkt fragen.

Gruß
K-H

nahpets 10. Okt 2017 12:31

AW: variabler Tabellenname in SQL-Abfrage
 
Ja, stimmt schon, aber dann verabschieden wir uns sehr schnell von der Datenbankunabhägigkeit.

Und für 'nen Programmiereinsteiger, der gerade seine erste Datenbankapplikation schreibt, dürften die hier von uns vorgeschlagenen Sachen weit über das hinausgehen, was man zum ersten Lernen so benötigt.

HolgerX 10. Okt 2017 12:38

AW: variabler Tabellenname in SQL-Abfrage
 
Zitat:

Zitat von p80286 (Beitrag 1383021)
Zitat:

Zitat von nahpets (Beitrag 1383018)
Die TAdoConnction hat 'ne Methode zum Holen der Tabellennamen. Das Ergebnis wird in eine Stringliste geliefert. Dafür kann man ComboBox.Items nehmen.

Die Funktion ist mit Vorsicht zu genießen, da nicht alle Views/Tabellen zurück geliefert werden (ist je nach DB unterschiedlich) darum lieber die DB direkt fragen.

.. und es funktioniert wahrscheinlich nur mit ADO so ;)

Hingegen ein SQL-Query wie

Code:
Select TABLE_NAME, COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS
order by TABLE_NAME
functioniert meines wissen auf MariaDB, MySQL, PostgreSQL ,SQL-Server.... mit diversern Query Komponenten und liefert dir direkt den Tabellennamen mit den Columnenamen ;)

nahpets 10. Okt 2017 12:54

AW: variabler Tabellenname in SQL-Abfrage
 
Entsprechende Routinen gibt es auch in anderen Komponentensammlungen für Datenbankzugriffe.

Sie kapseln (mal mehr, mal weniger gut), den SQL-Standard, aus dem sich ergibt, wo im INFORMATION_SCHEMA was zu suchen ist.

Wenn man die Routinen der Komponenten nutzt, muss man halt nicht alles selber machen.

Letztlich müssen es alle Komponentensammlungen auf den gemeinsamen Nenner des SQL-Standards runterbrechen, um gegen beliebige Datenbanken laufen zu können.

Und wenn man Glück hat, haben die Bauer der Komponentensammlungen dann auch die Besonderheiten von X Datenbanken (mehr oder weniger gut) berücksichtigt.

Und ja, man kann es immer und überall auch selber machen. Aber für jemanden, der das Programmieren mit Delphi lernt und die ersten Schritte in Richtung Datenbank macht, ist das händische Ermitteln der Datenbankinformationen zur weiteren Verarbeitung, doch etwas übertrieben.

Jedenfalls nutze ich zuerst die Methoden, die Delphi mit seinen Komponenten liefert. Und erst dann, wenn es da Probleme gibt, fange ich an, eigene Lösungen zu entwickeln.
Das soll in der Art auch der Sinn von RAD sein, wofür Delphi ja seit seinen Anfangstagen durchaus bekannt ist.

p80286 10. Okt 2017 13:06

AW: variabler Tabellenname in SQL-Abfrage
 
Zitat:

Zitat von nahpets (Beitrag 1383025)
Letztlich müssen es alle Komponentensammlungen auf den gemeinsamen Nenner des SQL-Standards runterbrechen, um gegen beliebige Datenbanken laufen zu können.

Und wenn man Glück hat, haben die Bauer der Komponentensammlungen dann auch die Besonderheiten von X Datenbanken (mehr oder weniger gut) berücksichtigt.

OK die Hardcore Fraktion sieht das wohl etwas enger, aber darüber können wir uns irgendwann anders streiten!
Solange man weiß, daß es ein Kompromiss ist...

Gruß
K-H


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:34 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz