Delphi-PRAXiS
Seite 2 von 2     12   

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 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 17:06 Uhr.
Seite 2 von 2     12   

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