Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Column "xxx" specified more than once (https://www.delphipraxis.net/203695-column-xxx-specified-more-than-once.html)

Incocnito 13. Mär 2020 16:33

Datenbank: postgres • Version: 10.4 • Zugriff über: unidac

Column "xxx" specified more than once
 
Hi Zusammen,

ich führe gerade eine Append auf eine Tabelle aus und er behauptet
"Column 'xxx' specified more than once".
Das macht meiner Meinung nach bei einer einzelnen Tabelle bzw. bei einem Append keinen Sinn.

Weiß jemand zufällig wie ich mir die tatsächlich abgeschickte SQL
(ich gehe mal davon aus, dass hier eine SQL generiert wird)
ausgeben lassen kann, damit ich wenigstens sehe was passiert?

Verrückt ist auch folgendes:
In der Tabelle sind alle Felder klein geschrieben.
Alle Felder werden in der Originalschreibweise angesprochen.
Ändere ich den Befehl von
Delphi-Quellcode:
APFAMPRU_SQL['Verfalldatum'] := DateAsNull(edVerfall.Date);
auf
Delphi-Quellcode:
APFAMPRU_SQL['verfalldatum'] := DateAsNull(edVerfall.Date);
(also mit kleinem "V") dann geht es.
Die Zeile
Delphi-Quellcode:
APFAMPRU_SQL['Status'] := nStatus;
stört ihn hierbei also von der Groß-/Kleinschreibung nicht!

Wenn er bei allen Feldern meckern würde, wäre das ja klar.
Dann wäre das einfach nur ein komischer/falscher Fehlertext.
Aber diese Konstellation verwirrt mich.
PS: Ich habe gerade nochmal nachgesehen; Es gibt tatsächlich nur ein Feld mit diesem Namen! :lol:

Verwende Delphi 10.3.2 mit Devart UniDac 8.1.3.

Vielen Dank schonmal für die Zeit und Hilfe!

Liebe Grüße
Incocnito

hoika 13. Mär 2020 18:09

AW: Column "xxx" specified more than once
 
Hallo,
ich würde Dir von der Nutzung der TTable-Komponenten abraten.
Bau eine passende Query, dann siehst Du auch, was an die DB geht.

PS:
DevArt müsste auch eine TDBMonitor haben, dort kannst Du dir die geschickten Queries ansehen.

p80286 13. Mär 2020 18:51

AW: Column "xxx" specified more than once
 
Zitat:

Zitat von hoika (Beitrag 1459709)
Hallo,
ich würde Dir von der Nutzung der TTable-Komponenten abraten.
Bau eine passende Query, dann siehst Du auch, was an die DB geht.

:thumb:
Zitat:

Zitat von Incocnito (Beitrag 1459704)
ich führe gerade eine Append auf eine Tabelle aus und er behauptet
"Column 'xxx' specified more than once".

Wer bitte produziert denn diese Meldung? Meist gibt es drei Verdächtige: die DB,der Treiber,die Komponente.
Ich vermute, daß da soetwas wie
Code:
update table1 set field1=x,set field2=y,set field1=z
generiert wird.
(die genae Syntax ist natürlich von Deiner DB abhängig)

Gruß
K-H

jobo 14. Mär 2020 09:19

AW: Column "xxx" specified more than once
 
Probleme mit Großkleinschreibung rühren meist daher, dass im Table Create Script Hochkomma o.ä bei der Feldbenennung verwendet wurden.
Wo "findest Du die Felder in Kleinschrift"?
Schau Dir als erstes das Create Script an.

jobo 14. Mär 2020 10:36

AW: Column "xxx" specified more than once
 
Nachtrag:

für Windows, Postgres 12, deutsch, Standardinstallation

Konfiguration von Postgres anpassen, um bestimmte oder alle SQL Statements zu loggen:
C:\Program Files\PostgreSQL\12\data\postgresql.conf
Zeile:
Code:
..
#log_statement = 'none'         # none, ddl, mod, all
..
Kommentarzeichen entfernen und Eintrag 'none' entsprechend der Auflistung / Bedarf anpassen.
Z.B. 'mod'
(Später wieder zurückstellen, sonst kann es schnell voll werden im System!)

Code:
..
# - Where to Log -
log_destination = 'stderr'
..
stderr ist ein Defaulteintrag, der bedeutet, dass die tatsächlich verwendeten Logfiles in der folgenden Datei explizit zu finden sind (nicht nur ein Verzeichnis):
C:\Program Files\PostgreSQL\12\data\current_logfiles
Dabei wird jeweils das konkrete, aktuell verwendete Logfile mit Tagesdatum aufgeführt.
Man landet in der Regel hier:

C:\Program Files\PostgreSQL\12\data\log\
Die Logfiles enthalten im Fehlerfall sowieso bereits SQL Statement Text und der Loglevel muss nicht geändert werden.

z.B.
Code:
..
2020-03-14 08:09:59.324 CET [5416] FEHLER: Spalte »t_id« existiert nicht bei Zeichen 8
2020-03-14 08:09:59.324 CET [5416] TIPP: Vielleicht wurde beabsichtigt, auf die Spalte »test.´t_id´« zu verweisen.
2020-03-14 08:09:59.324 CET [5416] ANWEISUNG: select t_id from test
..
hier sind die Logging Infos (verwendete Version beachten!):
https://www.postgresql.org/docs/curr...g-logging.html
(btw: Postgres bietet schon seit langer Zeit diese vorbildliche, versionierte Doku)

Incocnito 16. Mär 2020 11:44

AW: Column "xxx" specified more than once
 
Danke erstmal für die ganzen Ideen/Einwürfe!

Zitat:

Zitat von hoika (Beitrag 1459709)
... ich würde Dir von der Nutzung der TTable-Komponenten abraten. ...

1) Aus was für einem Grund? Dafür ist die doch entwickelt worden!
2) Ich soll in unserem Hauptprojekt die Datenbank ersetzen,
dabei versuche ich so wenig Quelltext wie möglich zu ändern.
Und da das bisher über Tabellen-Objekte lief, baue ich das so um,
dass es ebenfalls wieder so läuft. ... Naja, das ist das Ziel!

Zitat:

Zitat von hoika (Beitrag 1459709)
...
DevArt müsste auch eine TDBMonitor haben, dort kannst Du dir die geschickten Queries ansehen.

Ja tatsächlich! Danke für den Tipp! Allerdings ignoriert er die Einstellung "BeforeEvent"
scheinbar, denn er speichert die SQL nur, wenn ich den Feldnamen kleingeschrieben habe.
Schreibe ich das Feld groß, so zeigt er mit die erzeugte SQL nicht an.

Zitat:

Zitat von jobo (Beitrag 1459723)
Probleme mit Großkleinschreibung rühren meist daher, dass im Table Create Script Hochkomma o.ä bei der Feldbenennung verwendet wurden. ...

Im PgAdmin habe ich mir einfach mal mit "Select * from" alles ausgegeben und dort sind die Felder alle kleingeschrieben. Ich kann also davon ausgehen, dass das Create-Script die Feldnamen alle wandelt oder dass der PG-Server dies nachholt.

Zitat:

Zitat von jobo (Beitrag 1459724)
...
Konfiguration von Postgres anpassen, um bestimmte oder alle SQL Statements zu loggen:
C:\Program Files\PostgreSQL\12\data\postgresql.conf
Zeile:
Code:
..
#log_statement = 'none'         # none, ddl, mod, all
..
Kommentarzeichen entfernen und Eintrag 'none' entsprechend der Auflistung / Bedarf anpassen.
Z.B. 'mod'
(Später wieder zurückstellen, sonst kann es schnell voll werden im System!)

Code:
..
# - Where to Log -
log_destination = 'stderr'
..
...
Man landet in der Regel hier:
C:\Program Files\PostgreSQL\12\data\log\
...
hier sind die Logging Infos (verwendete Version beachten!):
https://www.postgresql.org/docs/curr...g-logging.html
(btw: Postgres bietet schon seit langer Zeit diese vorbildliche, versionierte Doku)

Ich hab' mir das mit den Logs mal angesehen, aber ich bekomme das so auf die schnelle nicht zum laufen. Wie du aber schon richtig geschrieben hattest werden Fehler eh geloggt.
Ich habe das Log dann in der Windows-Ereignisanzeige gefunden:
Code:
2020-03-16 12:05:46.541 CET [6356] ERROR: column "verfalldatum" specified more than once at character 151

2020-03-16 12:05:46.541 CET [6356] STATEMENT: INSERT INTO some_sheme.some_table
     (charge, pruefungsdatum, herstellungsdatum, lfdnr, pruefer, pzn, status, verfalldatum, verfalldatum, verfalldatum, verfalldatum)
   VALUES
     ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
Ich würde sagen, dass die Komponente da Mist baut, oder?
In Zusammenhang mit dem ersten Zitat würde ich aber trotzdem schauen, dass ich das ans Laufen bekomme. Das komplette Projekt auf Querys umzubauen wäre der Horror.

Liebe Grüße an alle
Incocnito

hoika 16. Mär 2020 15:23

AW: Column "xxx" specified more than once
 
Hallo,
hast du auf dem Form da irgendwelche datensensitiven Elemente (TDBGrid),
wo Du Spalteneigenschaften angepasst hast (Displayformat oder sowas)?

Such mal in der DFM nach den doppelten Spaltennamen.

Incocnito 16. Mär 2020 15:36

AW: Column "xxx" specified more than once
 
Die Komponente wird zur Laufzeit erstellt ohne Parent.
Diese wird dann auf dem Formular an mehreren Stellen benutzt.
Erzeuge ich eine neue Komponente und arbeite darauf, dann geht's.

Fehlersuche geht weiter ...

jobo 16. Mär 2020 16:54

AW: Column "xxx" specified more than once
 
Das klingt ganz leicht nach timing / initialisierungsfehler.

Aber ohne originalen Code ist es Raterei.

Bbommel 16. Mär 2020 17:14

AW: Column "xxx" specified more than once
 
Falls du nicht doch selber bei dir einen Fehler findest und ihr einen laufenden Vertrag bei DevArt habt, kann es sich lohnen, dort mal beim Support anzufragen. Ich hatte in den letzten Wochen zwei Probleme (eins lag letztlich an mir, eins war tatsächlich ein Bug in UniDac) und in beiden Fällen innerhalb weniger Stunden eine hilfreiche Antwort bekommen.

Incocnito 17. Apr 2020 15:20

AW: Column "xxx" specified more than once
 
Ich habe da mal was gebaut, mit dem das jeder nachvollziehen könnte.
Man muss natürliche eine PostgreSQL-Datenbank haben und eine neue Datenbank samt Benutzer anlegen.

Delphi-Quellcode:
unit TemporaererTestGF;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  Vcl.ExtCtrls, Vcl.StdCtrls, Uni;

{
-- Table: test_sh.fam_pruefung

-- DROP TABLE test_sh.fam_pruefung

CREATE TABLE test_sh.fam_pruefung
(
    bemerkung text COLLATE pg_catalog."default",
    charge character varying(20) COLLATE pg_catalog."default",
    data text COLLATE pg_catalog."default",
    pruefungsdatum date,
    herstellungsdatum date,
    lfdnr integer,
    massnahme text COLLATE pg_catalog."default",
    pruefer character varying(5) COLLATE pg_catalog."default",
    pzn integer,
    status integer,
    verfalldatum date
)
WITH (
    OIDS = FALSE
)
TABLESPACE pg_default;

ALTER TABLE test_sh.fam_pruefung
    OWNER to testuser;

GRANT ALL ON TABLE test_sh.fam_pruefung TO testuser;
GRANT ALL ON TABLE test_sh.fam_pruefung TO postgres;
}

type
  TfrmTemporaererTestGF = class(TForm)
    btnRun: TButton;
    pnlButtons: TPanel;
    btnClose: TButton;
    procedure btnCloseClick(Sender: TObject);
    procedure btnRunClick(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  frmTemporaererTestGF: TfrmTemporaererTestGF;

implementation

uses
  DB;

{$R *.dfm}

procedure TfrmTemporaererTestGF.btnCloseClick(Sender: TObject);
begin
  Close();
end;

procedure TfrmTemporaererTestGF.btnRunClick(Sender: TObject);
var
  xnPZN       : Integer;
  nLfdNr      : Integer;
  APFAMPRU_SQL : TUniTable;
  DBCon       : TUniConnection;
begin
  DBCon                      := TUniConnection.Create(nil);
  DBCon.ProviderName         := 'PostgreSQL';
  DBCon.Options.LocalFailover := True;
  DBCon.SpecificOptions.Add('ApplicationName=TestGF');

  DBCon.Database             := 'test_db';//DBGloApo.FDConnection.Database;
  DBCon.Username             := 'testuser';//DBGloApo.FDConnection.Username;
  DBCon.Password             := 'test_12345';//DBGloApo.FDConnection.Password;

  DBCon.Server               := 'localhost';//DBGloApo.FDConnection.Server;
  DBCon.Port                 := 9999;//DBGloApo.FDConnection.Port;
  DBCon.Connected            := True;

  APFAMPRU_SQL := TUniTable.Create(Application.MainForm);
  APFAMPRU_SQL.Connection := DBCon;

  APFAMPRU_SQL.TableName := 'test_sh.fam_pruefung';//TPostgres.SchemaNameAposoft + '.' + 'fam_pruefung';

  APFAMPRU_SQL.OrderFields := 'PZN, Pruefungsdatum';
  APFAMPRU_SQL.Open();

  try
    APFAMPRU_SQL.OrderFields := 'LfdNr';
    APFAMPRU_SQL.Last();
    nLfdNr := APFAMPRU_SQL.FieldByName('LfdNr').AsInteger + 1;
    APFAMPRU_SQL.OrderFields := 'PZN, Pruefungsdatum';

    // ----

    xnPZN := 9206022;

    if (APFAMPRU_SQL.Locate('PZN', VarArrayOf([xnPZN]), [])) then
    begin
      APFAMPRU_SQL.Filter  := 'PZN = ' + xnPZN.ToString;
      APFAMPRU_SQL.Filtered := True; // <- Diese Zeile ist das Problem!?
      APFAMPRU_SQL.Execute(); // Mit Execute geht alles!
      APFAMPRU_SQL.Filtered := False;
      APFAMPRU_SQL.Execute(); // Mit Execute geht alles!
    end;

    APFAMPRU_SQL.Append();
    APFAMPRU_SQL['PZN']              := xnPZN;
    APFAMPRU_SQL['Pruefungsdatum']   := EncodeDate(2020, 4, 3);
    APFAMPRU_SQL['Charge']           := '111';
    APFAMPRU_SQL['Herstellungsdatum'] := EncodeDate(2020, 1, 1);
    APFAMPRU_SQL['Verfalldatum']     := EncodeDate(2020, 12, 31);
    APFAMPRU_SQL['Status']           := 1;
    APFAMPRU_SQL['Pruefer']          := 'gfr';
    APFAMPRU_SQL['LfdNr']            := nLfdNr;
    APFAMPRU_SQL.Post();
  finally
    try APFAMPRU_SQL.Free(); except end;
    try DBCon.Free(); except end;
  end;
end;

end.
Hatte ich mein Tabellen-Objekt also beim Filtern um das Execute erweitert,
lief alles problemlos. Ein wenig seltsam finde ich das aber schon.
Vor allem, dass es so ein bisschen geht.
1) Wenn "Verfalldatum" klein geschrieben ist (nur das Rest ist egal)
2) Nach Filtern mit "Execute"

PS: Nicht wie ich darauf reinfallsen: Beim ersten Mal läuft es ja, weil er das Filtern nicht ausführt!
PS2: Den Port und evtl. den Server müsst ihr natürlich auch für euch anpassen!

PS3: Leider habe ich keine Zeit dem weiter nachzugehen.
Falls mal jemand etwas ähnliches hat, hilft dieser Trick aber ja.

LG Incocnito

himitsu 17. Apr 2020 15:53

AW: Column "xxx" specified more than once
 
Zitat:

Wenn "Verfalldatum" klein geschrieben ist
Normal ist in Postgre die Groß-/Kleinschreibung egal, so lange ein Name nicht in " angegeben wurde.

Es wird automatisch ein Lowercase über alles gelegt, außer bei 'Strings' und "Namen" mit " .

Zitat:

Das macht meiner Meinung nach bei einer einzelnen Tabelle bzw. bei einem Append keinen Sinn.
Ja, es gibt einmal den Fall, dass die Spalte bei einem JOIN in mehreren Tabellen/Quellen vorhanden ist und man hier den Namespace (Tabellenname) mit angeben muß, damit die DB weiß was du eigentlich willst.

Und dann gibt es den Fall, dass eine Spalte mehrfach im Select vorkommt, z.B. nochmal mit AS umbenannt.

Delphi-Quellcode:
SELECT aaa, aaa AS bbb
oder bei
Delphi-Quellcode:
SELECT aaa, *
bzw,
Delphi-Quellcode:
SELECT aaa AS bbb, *
.

Hier gibt es erstmal kein Problem, aber wenn das Feld geändert wurde und man das POSTen will, dann weiß die DBKompoente nicht welchen Wert die nun speichern soll.
Den Wert von aaa oder den von bbb, welcher ja auch in aaa gespeichert würde.

Lösung:
  • Entweder die Extended-Infos der DB-Komponente deaktivieren, also damit PgDAC/UniDAC/... nicht weiß dass bbb eigentlich aaa ist
  • oder auf Seiten der DB bereits diese Verbindung auftrennen, indem man das Feld durch eine Funktion jagt
    Delphi-Quellcode:
    SELECT aaa, Trim(aaa) AS bbb, Coalsece(aaa, NULL) AS ccc, EineEigeneDetachFunctionDamitManAmNamenErkenntWarumDasHierSteht(aaa) AS ddd
    .
  • oder manuell ein Insert- und Update-Statement in der DB-Komponente hinterlegen, damit nicht versucht wird automatisch Eines zu generieren



Wie UniDAC hier nun clientseitig arbeitet .... wer weiß, aber vermutlich auch so wie PgDAC, welches die Vegleiche der Namen case-insensitiv durchführt,
womit clientseitig das eigentlich auch egal wäre.


Hast du mal nachgesehn, wie es in der Datnbank aussieht?
Wurden die Felder Verfalldatum oder Status dort eventuell wirklich explizit mit Großschreibung erstellt?



PS: Bei nur einem Feld, wäre beim Locate der Weg über das Variant-Array nicht nötig.
Delphi-Quellcode:
APFAMPRU_SQL.Locate('PZN', VarArrayOf([xnPZN]), ...) = APFAMPRU_SQL.Locate('PZN', xnPZN, ...)


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:51 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