Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi SQL Semicolon im String -> Fehler bei Insert (https://www.delphipraxis.net/215200-sql-semicolon-im-string-fehler-bei-insert.html)

DaCoda 26. Mai 2024 16:44

Datenbank: SqLite • Version: 3.42.0 • Zugriff über: FireDAC

SQL Semicolon im String -> Fehler bei Insert
 
Einfügen von Strings (Singlequoted) mit Semicolon im String.
Code:
      tblData.First;
      WriteLn(SqlFile, 'INSERT INTO Mediathek (' + QuotedStr('ID') + ',' + QuotedStr('Interpret') + ',' + QuotedStr('Album') + ',' + QuotedStr('Titel') + ',' + QuotedStr('FileName') + ') VALUES');

      Caption := tblData.RecordCount.ToString;
      for Loop := 0 to tblData.RecordCount - 2 do begin
        WriteLn(SqlFile, '(' + tblDataID.AsString + ',' + QuotedStr(tblDataInterpret.AsWideString) + ',' + QuotedStr(tblDataAlbum.AsWideString) + ',' + QuotedStr(tblDataTitel.AsWideString) + ',' + QuotedStr(tblDataFileName.AsWideString) + '),');
        tblData.Next;
        Application.ProcessMessages;
      end;
      tblData.Last;
      WriteLn(SqlFile, '(' + tblDataID.AsString + ',' + QuotedStr(tblDataInterpret.AsWideString) + ',' + QuotedStr(tblDataAlbum.AsWideString) + ',' + QuotedStr(tblDataTitel.AsWideString) + ',' + QuotedStr(tblDataFileName.AsWideString) + ');');
Dabei gibt es das Problem das wegen dem Semicolon ein Fehler auftritt. (Vermutlich auch bei '). ALso der Fehler entsteht beim einlesen der SQL-Datei, zB. mit HeidiSQL.
Beispiel einer Zeile:
INSERT INTO Mediathek ('ID','Interpret','Album','Titel','FileName') VALUES
(9,'Jethro Tull','Benefit','Sossity; You''re a Woman','M:\Musik\Jethro Tull\Benefit\10 Sossity; You''re a Woman.mp3');
...

Ich finde die Lösung einfach nicht.

haentschman 26. Mai 2024 16:52

AW: SQL Semicolon im String -> Fehler bei Insert
 
Hallöle...8-)
Zitat:

Ich finde die Lösung einfach nicht.
Delphi-Quellcode:
+ QuotedStr(tblDataFileName.AsWideString) + '),');
..
+ QuotedStr(tblDataFileName.AsWideString) + ');'); // hier Semikolon richtig?
PS: Diese QuotedStr Orgien machen mir immer Gänsehaut...:?

...mit Parametern wäre das nicht passiert. Zeige mal den Teil wo du das 'INSERT' SQL der Query zuweist...
Parameter:
https://docwiki.embarcadero.com/RADS...ngen_(FireDAC)
Delphi-Quellcode:
FDQuery1.SQL.Text := 'select * from tab where code = :Code';
FDQuery1.ParamByName('code').AsString := '123';
FDQuery1.Open;

himitsu 26. Mai 2024 17:00

AW: SQL Semicolon im String -> Fehler bei Insert
 
Parameter, Parameter, Parameter, Parameter, ..........


ODER, man sollte gefällgist einige "richtige" Funktion für das Escaping verwenden:!:
QuoteStr ist und war noch niemals für SQLs, denn es kennt ausschließlich die Syntax von PascalStrings, aber kein nicht die Syntax vom SQL, wie z.B. \

DaCoda 26. Mai 2024 17:10

AW: SQL Semicolon im String -> Fehler bei Insert
 
Die Routine sieht so aus:

Code:
function TfrmBackupRestore.GetSqlVersion: string;
begin
  Result := 'Unbekannt';
  try
    with qryData.SQL do begin
      Clear;
      Add('SELECT sqlite_version()')
    end;
    qryData.Open;
    Result := qryData.FieldByName('sqlite_version()').AsString;
    qryData.CLose;
  finally

  end;
end;

procedure TfrmBackupRestore.DoBackup;
var
  SqlFile: TextFile;
  Loop: Integer;
begin
  AssignFile(SqlFile, SqlBackupFileName);
  Rewrite(SqlFile);
  if IOResult = 0 then begin
    tblData.Active := True;
    tblData.Open;
    try
      WriteLn(SqlFile, '-- --------------------------------------------------------');
      WriteLn(SqlFile, '-- Host: ' + DbName + SqLiteSqlExt);
      WriteLn(SqlFile, '-- Server-Version: ' + dmMain.SqlConnection.Drivername + ' Version : ' + GetSqlVersion);
      WriteLn(SqlFile, '-- Server - Betriebssystem: ' + TOSVersion.Name);
      WriteLn(SqlFile, '-- Generator: ' + FileVersion.strProductName + Space + strVersion + FileVersion.strFileVersion);
      WriteLn(SqlFile, '-- --------------------------------------------------------');
      WriteLn(SqlFile);

      WriteLn(SqlFile, '-- Exportiere Datenbank - Struktur für Mediathek');
      WriteLn(SqlFile, '/*!40000 CREATE DATABASE if not EXISTS Mediathek */;');
      WriteLn(SqlFile);

      WriteLn(SqlFile, '-- Exportiere Struktur von Tabelle Mediathek.Mediathek');
      WriteLn(SqlFile, 'CREATE TABLE if not EXISTS Mediathek(ID INTEGER PRIMARY KEY AUTOINCREMENT, Interpret VARCHAR not NULL, Album VARCHAR not NULL, Titel VARCHAR not NULL, FileName VARCHAR not NULL UNIQUE);');
      WriteLn(SqlFile);

      WriteLn(SqlFile, '-- Exportiere Daten aus Tabelle Mediathek.Mediathek');
      WriteLn(SqlFile, 'DELETE FROM Mediathek;');
      WriteLn(SqlFile, '/*!40000 ALTER TABLE "Mediathek" DISABLE KEYS */;');

      tblData.First;
      WriteLn(SqlFile, 'INSERT INTO Mediathek (' + QuotedStr('ID') + ',' + QuotedStr('Interpret') + ',' + QuotedStr('Album') + ',' + QuotedStr('Titel') + ',' + QuotedStr('FileName') + ') VALUES');

      Caption := tblData.RecordCount.ToString;
      for Loop := 0 to tblData.RecordCount - 2 do begin
        WriteLn(SqlFile, '(' + tblDataID.AsString + ',' + QuotedStr(tblDataInterpret.AsWideString) + ',' + QuotedStr(tblDataAlbum.AsWideString) + ',' + QuotedStr(tblDataTitel.AsWideString) + ',' + QuotedStr(tblDataFileName.AsWideString) + '),');
        tblData.Next;
        Application.ProcessMessages;
      end;
      tblData.Last;
      WriteLn(SqlFile, '(' + tblDataID.AsString + ',' + QuotedStr(tblDataInterpret.AsWideString) + ',' + QuotedStr(tblDataAlbum.AsWideString) + ',' + QuotedStr(tblDataTitel.AsWideString) + ',' + QuotedStr(tblDataFileName.AsWideString) + ');');

      WriteLn(SqlFile, '/*!40000 ALTER TABLE "Mediathek" ENABLE KEYS */;');
      WriteLn(SqlFile);

      WriteLn(SqlFile, '-- Exportiere Struktur von Tabelle Mediathek.TempData');
      WriteLn(SqlFile, 'CREATE TABLE IF NOT EXISTS TempData (ID INTEGER PRIMARY KEY AUTOINCREMENT, OrgId INT NOT NULL UNIQUE, FileName VARCHAR NOT NULL UNIQUE);');
      WriteLn(SqlFile);

      WriteLn(SqlFile, '-- Exportiere Daten aus Tabelle Mediathek.TempData');
      WriteLn(SqlFile, 'DELETE FROM TempData;');
      WriteLn(SqlFile, '/*!40000 ALTER TABLE "TempData" DISABLE KEYS */;');
      WriteLn(SqlFile, '/*!40000 ALTER TABLE "TempData" ENABLE KEYS */;');
    finally
      CloseFile(SqlFile);
    end;
    tblData.Close;
    tblData.Active := False;
  end else begin
    ErrorDialog('Die Sicherungsdatei: ' + SqlBackupFileName + CRLF + 'konnte nicht angelegt werden !');
  end;
end;

Uwe Raabe 26. Mai 2024 17:31

AW: SQL Semicolon im String -> Fehler bei Insert
 
Zitat:

Zitat von haentschman (Beitrag 1537148)
...mit Parametern wäre das nicht passiert. Zeige mal den Teil wo du das 'INSERT' SQL der Query zuweist...

Ich vermute, das ist hier gar nicht gegeben:
Zitat:

Zitat von DaCoda (Beitrag 1537147)
ALso der Fehler entsteht beim einlesen der SQL-Datei, zB. mit HeidiSQL.


DaCoda 26. Mai 2024 18:16

AW: SQL Semicolon im String -> Fehler bei Insert
 
Das Problem ist ja, das diese Semikolons oder auch manchmal ' da sind und auch müssen...

Wenn ich aber die endgültige Backup.sql zB. mit Heidi-SQL oder SqLite-Expert ausführe, dann führt das zu Fehlern.
Und das möchte ich irgendwie hinbekommen, OHNE diese Zeichen zu entfernen.

himitsu 26. Mai 2024 19:49

AW: SQL Semicolon im String -> Fehler bei Insert
 
Bei vielen DBMS/Tools kann man auch Zeichen umdefinieren und z.B. ein anderes Zeichen/Zeichengruppe für die Trennung der einzelnen SQL-Statements verwenden.

Gibt es im MySQL auch sowas wie \u12AF ?

Sinspin 27. Mai 2024 13:33

AW: SQL Semicolon im String -> Fehler bei Insert
 
Dann trag doch einfach mal einen Record von Hand in die DB ein, der solche Zeichen enthält. Und mach dann einen Export mit den Tools die Du auch für den Import verwenden willst.
In dem Export sollten die Zeichen ja so kodiert sein dass es passt.

DaCoda 27. Mai 2024 17:31

AW: SQL Semicolon im String -> Fehler bei Insert
 
Hallo Sinspin,
das war mal eine Top-Idee. Hab ich auch gleich mal gemacht.
Das Ergebnis ist ernüchternd. Das SQL-Backup wurde anstandslos erzeugt, aber bein einlesen gibt es dann wieder das Problem...
Also liegt es gar nicht mal unbedingt an meiner Backupfunktion.
Da ich aber sowieso im Moment SqLite nehme brauche ich auch gar nicht so eine Funktion, weil ich die gesamte Datei ja kopieren kann.

Mein Plan war natürlich größer und wollte eine allgemeine Unit machen, um Datenbanken zu sichern und zurück zu lesen. Weil sowas ja bei FireDAC immer noch fehlt.
UniDAC ist da schon immer etwas weiter und hat diese Funktionalität, ich möchte aber nicht noch eine "Fremdsoftware" dazu kaufen, da ich nur für mich (Hobby) programmiere...

himitsu 27. Mai 2024 17:40

AW: SQL Semicolon im String -> Fehler bei Insert
 
Zitat:

Zitat von DaCoda (Beitrag 1537209)
UniDAC ist da schon immer etwas weiter und hat diese Funktionalität,

Hmmmmm, ob das inzwischen auf im PgDAC drin ist?

Nja, wir rufen da einfach die psql.exe mehrfach auf und lassen sie den Export je einer Tabelle in eine SQL-Datei machen, inzwischen mit einer Pipe durch die 7z.exe, um es nochmal als ZIP zu verpacken.

Sinspin 27. Mai 2024 18:31

AW: SQL Semicolon im String -> Fehler bei Insert
 
Zitat:

Dann trag doch einfach mal einen Record von Hand in die DB ein, der solche Zeichen enthält. Und mach dann einen Export mit den Tools die Du auch für den Import verwenden willst.
In dem Export sollten die Zeichen ja so kodiert sein dass es passt.
Zitat:

Zitat von DaCoda (Beitrag 1537209)
Hab ich auch gleich mal gemacht.
Das Ergebnis ist ernüchternd. Das SQL-Backup wurde anstandslos erzeugt, aber bein einlesen gibt es dann wieder das Problem.

Ist doch immer schön zu sehen wenn das, worauf man sich verlassen können sollte nicht funktioniert.
Es ist zwar nicht optimal, aber Du könntest das Backup und Restore auch komplett selber machen. Und einfach die Daten in eine CSV Datei schreiben.
Beim einlesen erzeugst Du SQL Scripte denen Du die Feldinhalte mit Parametern übergeben kannst. Das sollten das String Problem umgehen.

DaCoda 28. Mai 2024 00:59

AW: SQL Semicolon im String -> Fehler bei Insert
 
Manchmal sitzt der Fehler aber auch einfach vor dem Bildschirm, das berühmte "40cm Problem" :-)

Ich habe das Backup/Restore Backup/Restore mal anders gelöst, wegen UTF8-Codierung und es geht so auch schneller:

Code:
const
  EmptyStr = '';

function TfrmBackupRestore.GetSqlVersion: string;
begin
  Result := 'Unbekannt';
  try
    with qryData.SQL do begin
      Clear;
      Add('SELECT sqlite_version()')
    end;
    qryData.Open;
    Result := qryData.FieldByName('sqlite_version()').AsString;
    qryData.CLose;
  finally
    // 
  end;
end;

procedure TfrmBackupRestore.DoBackup;
var
  SL: TStringList;

begin
  SL := TstringList.Create;
  try
    tblData.Active := True;
    tblData.Open;

    if tblData.RecordCount > 0 then begin

      SL.Add('-- --------------------------------------------------------');
      SL.Add('-- Host: ' + DbName + SqLiteSqlExt);
      SL.Add('-- Server-Version: ' + dmMain.SqlConnection.Drivername + ' Version : ' + GetSqlVersion);
      SL.Add('-- Server - Betriebssystem: ' + TOSVersion.Name);
      SL.Add('-- Generator: ' + FileVersion.strProductName + Space + strVersion + FileVersion.strFileVersion);
      SL.Add('-- --------------------------------------------------------');

      SL.Add(EmptyStr);

      SL.Add('-- Exportiere Datenbank - Struktur für Mediathek');
      SL.Add('/*!40000 CREATE DATABASE if not EXISTS Mediathek */;');

      SL.Add(EmptyStr);

      SL.Add('-- Exportiere Struktur von Tabelle Mediathek.Mediathek');
      SL.Add('CREATE TABLE if not EXISTS Mediathek(ID INTEGER PRIMARY KEY AUTOINCREMENT, Interpret VARCHAR not NULL, Album VARCHAR not NULL, Titel VARCHAR not NULL, FileName VARCHAR not NULL UNIQUE);');

      SL.Add(EmptyStr);

      SL.Add('-- Exportiere Daten aus Tabelle Mediathek.Mediathek');
      SL.Add('DELETE FROM Mediathek;');
      SL.Add('/*!40000 ALTER TABLE Mediathek DISABLE KEYS */;');

      SL.Add(EmptyStr);

      pbProgress.Style := pbstMarquee;
      tblData.First;
      while not (tblData.Eof or boAborted) do begin
        SL.Add('INSERT INTO Mediathek VALUES (' + QuotedStr(tblDataID.AsString) + ',' + QuotedStr(tblDataInterpret.AsWideString) + ',' + QuotedStr(tblDataAlbum.AsWideString) + ',' + QuotedStr(tblDataTitel.AsWideString) + ',' + QuotedStr(tblDataFileName.AsWideString) + ');');
        tblData.Next;
        Application.ProcessMessages;
      end;
      pbProgress.Style := pbstNormal;

      SL.Add('/*!40000 ALTER TABLE Mediathek ENABLE KEYS */;');

      SL.Add(EmptyStr);

      SL.Add('-- Exportiere Struktur von Tabelle Mediathek.TempData');
      SL.Add('CREATE TABLE IF NOT EXISTS TempData (ID INTEGER PRIMARY KEY AUTOINCREMENT, OrgId INT NOT NULL UNIQUE, FileName VARCHAR NOT NULL UNIQUE);');

      SL.Add(EmptyStr);

      SL.Add('-- Exportiere Daten aus Tabelle Mediathek.TempData');
      SL.Add('DELETE FROM TempData;');
      SL.Add('/*!40000 ALTER TABLE TempData DISABLE KEYS */;');
      SL.Add('/*!40000 ALTER TABLE TempData ENABLE KEYS */;');
      SL.SaveToFile(SqlBackupFileName, TEncoding.UTF8);
    end;

    tblData.Close;
    tblData.Active := False;
  finally
    FreeANdNil(SL);
  end;
end;

procedure TfrmBackupRestore.DoRestore;
var
  SL: TStringList;
  Loop: Integer;

begin
  SL := TStringList.Create;
  try
    SL.LoadFromFile(SqlBackupFileName, TEncoding.UTF8);
    if SL.Count > 0 then begin
      for Loop := 0 to SL.Count - 1 do begin
        if SL[Loop] <> EmptyStr then begin
          try
            qryData.SQL.Text := SL[Loop];
            qryData.ExecSQL;
            Application.ProcessMessages;
          except
            // TODO
          end;
        end;
      end;
    end;
  finally
    FreeAndNil(SL);
  end;
end;
Allerdings haben meine DBMS-Tools an dieser Stelle offensichtlich auch einen Fehler.
Meine SQL-Sicherung wird nun anstandslos von den Tools verarbeitet.
Ich habe aber auch eine Restore-Procedure mit gepostet...

Also Danke Euch für Eure Hilfe und Tipps :-)

Sinspin 28. Mai 2024 08:38

AW: SQL Semicolon im String -> Fehler bei Insert
 
Sorry, Ich muss leider nochmal nachtreten.
Wofür machst du :
Delphi-Quellcode:
Application.ProcessMessages;
.

Das reduziert die Ausführgeschwindigkeit massiv.

Wenn es unbedingt sein muss, dann alle 100 oder 200 Datensätze.
Oder eventuell 50 mal auf 100% aller Datensätze.
Allerdings sehe ich in deiner Routine nichts was wie eine Fortschrittsanzeige aussieht. Also raus damit.

DaCoda 28. Mai 2024 08:50

AW: SQL Semicolon im String -> Fehler bei Insert
 
Hallo Sinspin,

Zitat:

Zitat von Sinspin (Beitrag 1537234)
Sorry, Ich muss leider nochmal nachtreten.
Wofür machst du :
Delphi-Quellcode:
Application.ProcessMessages;
.

Das reduziert die Ausführgeschwindigkeit massiv.

Wenn es unbedingt sein muss, dann alle 100 oder 200 Datensätze.
Oder eventuell 50 mal auf 100% aller Datensätze.
Allerdings sehe ich in deiner Routine nichts was wie eine Fortschrittsanzeige aussieht. Also raus damit.

Das Processmessages und die Progressbar waren zum testen und sind halt noch beim posten drinne gewesen :-)


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:52 Uhr.

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