Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   TADOCommand mit Parametern - PK-Verletzung (https://www.delphipraxis.net/168806-tadocommand-mit-parametern-pk-verletzung.html)

hyype 12. Jun 2012 12:26

Datenbank: MSSQL2008R2 • Version: ? • Zugriff über: ADO

TADOCommand mit Parametern - PK-Verletzung
 
Hallo Community!

Ich habe ein TADOCommand und befülle CommandText mit einem sql-statement-string, der ungefähr so aussieht:

DECLARE @TRANSE CHAR(8) = 'Transe00';
BEGIN TRANSACTION @TRANSE;
IF NOT EXISTS(SELECT * FROM ST_VKL WHERE ID=:@ID)
INSERT INTO ST_VKL (ID,NAME) VALUES(:@ID,:@NAME)
ELSE
UPDATE ST_VKL SET NAME=:@NAME WHERE ID=:@ID;
IF @@ERROR = 0
COMMIT TRANSACTION @TRANSE
ELSE
ROLLBACK TRANSACTION @TRANSE;

Dabei ist schonmal zu sagen, dass mein string in diesem vereinfachten Beispiel genau _2_ Parameter enthält, @ID und @NAME.
Beim Zuweisen des commandtextes werden aber automatisch 5 erstellt, nämlich @ID, @ID, @NAME, @NAME, @ID,
was besonders sinnvoll ist, liefert doch die methode parambyname nur einen zurück...
Egal, ich habe sie allesamt mit den richtigen Werten befüllt.
Dazu ist zu sagen, dass ich sie nach der automatischen Erstellung nur noch mit Werten befülle,
also weder den Typ, noch die Größe festlege, da ich das ganz allgemein umgesetzt habe und ich im allgemeinen Fall den Datentyp nicht kenne,
dazu benutze ich den Datentyp Variant.

Nun zu meinem eigentlichen Problem:
Wie man dem statement entnehmen kann wird geguckt, ob ein Datensatz mit der ID schon da ist,
wenn nein wird ein insert gemacht, wenn ja ein update - wie kann es da sein, dass ich beim executen eine PK-Verletzung kriege?
Das ist doch eigentlich VÖLLIG UNMÖGLICH!?!

Bin mit meinem Latein am Ende, ka was delphi da macht, habe bisher immer ohne Parameter gearbeitet und den string einfach so zusammengebaut und da geht das.
Und wenn ich mein sql-statement ins ManagementStudio kopiere und statt der Parameter die Werte einfüge, funktioniert alles einwandfrei...

mkinzler 12. Jun 2012 12:32

AW: TADOCommand mit Parametern - PK-Verletzung
 
Warum verwendest du nicht das vorhandene MERGE Statement und versuchst es selber nachzubilden?

hyype 12. Jun 2012 13:04

AW: TADOCommand mit Parametern - PK-Verletzung
 
ich habe das immer so gemacht, jedoch ohne parameter
es ist ja auch absolut richtig so!
ich würde gern eine erklärung haben, wieso ein sql-statement, welches von der sache her sauber ist und niemals zu einer pk-verletzung führen kann, beim executen des tadocommands mit parametern eine pk-verletzung verursacht, weil das verstehe ich nciht und das kostet mich jetzt extrem viel zeit...

ele 12. Jun 2012 13:20

AW: TADOCommand mit Parametern - PK-Verletzung
 
Das Problem kenne ich.
Man kann einen Parameter nicht auf diese Weise wiederverwenden.

Inzwischen verwende ich SQL Variabeln um das zu Umgehen. Alternativ kannst du dafür sorgen, dass die Parameter nur jeweils einmal vorkommen (:ID1, :ID2, etc.). Dann musst du allerdings jedem Parameter den entsprechenden Wert zuweisen.

Die Lösung mit den Variabeln finde ich jedoch übersichtlicher und einfacher:

Code:
DECLARE @ID integer
DECLARE @Name varchar(20)
SET @ID = :ID
SET @Name = :Name
DECLARE @TRANSE CHAR(8) = 'Transe00';
BEGIN TRANSACTION @TRANSE;
IF NOT EXISTS(SELECT * FROM ST_VKL WHERE ID=@ID)
INSERT INTO ST_VKL (ID,NAME) VALUES(@ID,@Name)
ELSE
UPDATE ST_VKL SET NAME=@Name WHERE ID=@ID;
IF @@ERROR = 0
COMMIT TRANSACTION @TRANSE
ELSE
ROLLBACK TRANSACTION @TRANSE;
Für die Typen von ID und Name benutzt du natürlich das was du brauchst. Da du diese Information nicht geliefert hast, musste ich irgendwas erfinden...

Übrigens würde ich die Parameter nicht mit @ deklarieren. Das @ Symbol wird von SQL für Variablen verwendet, wenn du das von Delphi aus machst genügt :VariabelName.

omata 12. Jun 2012 13:24

AW: TADOCommand mit Parametern - PK-Verletzung
 
Du schreibt, dass das ein vereinfachtes Beispiel ist. Durch welches Statement wird den die PK-Verletzung durchgeführt? Ich denke es wird durch das UPDATE erzeugt, nicht durch das INSERT. Aber durch das UPDATE kann nur dann ein Fehler entstehen, wenn im SET-Teil auch die PK-Spalte(n) mit verändert werden. Es wäre also hilfreich, wenn du nicht zu viel vereinfachst, an deinem Beispiel. Dann können wir dir besser helfen.

hyype 12. Jun 2012 13:56

AW: TADOCommand mit Parametern - PK-Verletzung
 
die Verinfachung war natürlich nicht fehlerbehaftet, der PK besteht nur aus der ID
er macht tatsächlich ein Insert (habe den PK weggenommen und siehe da, ich habe 2 Datensätze)
das Problem ist, dass der Select innerhalb des exists nichts matched, obwohl der Datensatz da ist
ich habe sogar noch ein Convert um die Spalte und um den Parameter drumrumgebaut, dass da nix schief gehen kann, leider ohne Erfolg
ich glaube, er löst den Parameter an der stelle einfach nicht auf...

den Hinweis mit der unterschiedlichen Namensgebung für die Parameter kam auch von einem Kollegen, habe ich umgesetzt
(i für insert, u für update, w für where davor)

das @ kam tatsächlich dadurch rein, dass ich dachte, er würde intern eben genau das machen,
also die Variablen declaren, wodurch sie das @ bräuchten und dann mit den parameterwerten befüllen
da er es anscheinend nicht so macht, nehme ich das @ jetzt raus

ich werde den declare-Ansatz mal weiterverfolgen, vielen Dank dafür!!!

hyype 12. Jun 2012 14:30

AW: TADOCommand mit Parametern - PK-Verletzung
 
DECLARE @Transe CHAR(8) = 'Transe00';
BEGIN TRANSACTION @Transe;
DECLARE @ID INT;
SET @ID=:WID;
IF (EXISTS(SELECT * FROM ST_VKL WHERE ID=@ID))
UPDATE ST_VKL SET NAME=:UNAME
WHERE ID=@ID
ELSE
INSERT INTO ST_VKL
(ID,NAME)
VALUES(:IID,:INAME);
IF @@ERROR = 0
COMMIT TRANSACTION @Transe
ELSE
ROLLBACK TRANSACTION @Transe;

so sieht es jetzt aus.
ich habe das declare nur für die parameter gemacht, die im where verwendet werden, also zum PK gehören,
weil ich allgemein (=ohne die spezifische table zu kennen) nur für die garantieren kann, dass sie integer sind

es hat leider nicht funktioniert :/

hyype 12. Jun 2012 15:46

AW: TADOCommand mit Parametern - PK-Verletzung
 
toll, jetzt habe ich im insert auch mal @ID statt :IID verwendet und setzen tu ich wie folgt:
SET @ID = CONVERT(INT,:WID);
Der Parameter WID hat den Wert 1699, inserten tut er mir aber den Wert -1, wie geht das denn?

ele, da du das offenbar shconmal zum laufen gekriegt hast, die frage an dich: was mache ich falsch? ich hab's eigentlich genau so gemacht wie du

NormanNG 12. Jun 2012 15:59

AW: TADOCommand mit Parametern - PK-Verletzung
 
Hi,

erstelle eine StoredProc in der Datenbank, der du alle zu speichernden Werte als Parameter übergibst. In der Proc kannst du dann so ähnlich wie bisher zuerst update und ggf. insert ausführen.

In Delphi hast du dann nur einmal die Parameter - alle Logik liegt in der Datenbank.

hyype 12. Jun 2012 16:07

AW: TADOCommand mit Parametern - PK-Verletzung
 
Das Problem ist, dass ich das sehr allgemein programmiere, um es für jede Tabelle zu benutzen.
Die spezifischen Tabellen haben dann unterschiedliche Anzahl an Spalten, unterschiedliche Datentypen etc
Da ich die alle machen, kann ich nur sagen, dass die von mir als PK gekennzeichneten Spalten integer sind.
Über den Rest ist mir auf der Ebene nix bekannt, daher weise ich die Werte als Variant zu, also

var value : variant;
...
value := 1699;
...
params[i].value := value;

und:

Delphi-Quellcode:

  q := tadodataset.create(nil);
  try
    q.connectionstring := ...
    q.CommandType := cmdText;
    q.commandtext := 'DECLARE @BLUB INT; SET @BLUB = :BLUB; SELECT @BLUB AS BLUB;';
    q.Parameters.parambyname('BLUB').value := 1699;
    q.Open;
    showmessage(inttostr(q.fieldbyname('blub').asinteger));
  finally
    freeandnil(q);
  end;
das geht komischerweise, ja bin ich denn blöd?


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:55 Uhr.
Seite 1 von 2  1 2      

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