Autor Téma: Firedac TFDUpdateSQL + LAST_INSERT_ID  (Přečteno 222 krát)

Offline chaloup

  • Plnoletý
  • ***
  • Příspěvků: 135
  • Karma: 11
    • Verze Delphi: Delphi 12.2
Firedac TFDUpdateSQL + LAST_INSERT_ID
« kdy: 01-10-2024, 16:12:06 »
Netuší někdo jak právně napsat InsertSQL aby to načetlo AUTO_INCREMENT u MySQL? Našel jsem v příkladech, kde to používají
https://github.com/Embarcadero/RADStudio12Demos/tree/main/Object%20Pascal/Database/FireDAC/Samples/Comp%20Layer/TFDQuery/CachedUpdates/OnUpdateRecord
tam je to udělaný takto, ale to nefunguje:
Kód: [Vybrat]
INSERT INTO {id Products} (
ProductName, SupplierID, CategoryID,
QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
ReorderLevel, Discontinued)
VALUES (
:NEW_ProductName, :NEW_SupplierID,
:NEW_CategoryID, :NEW_QuantityPerUnit, :NEW_UnitPrice,
:NEW_UnitsInStock, :NEW_UnitsOnOrder, :NEW_ReorderLevel,
:NEW_Discontinued
)
{IF MySQL} select LAST_INSERT_ID() as ProductID {FI}

Offline rholecek

  • Nováček
  • *
  • Příspěvků: 7
  • Karma: 0
    • Verze Delphi: Delphi 10.1 Update 2
Re:Firedac TFDUpdateSQL + LAST_INSERT_ID
« Odpověď #1 kdy: 02-10-2024, 13:06:45 »
Přiznám se, že jsem nikdy nepoužíval komponentu TFDUpdateSQL. Vždy jsem SQL řešil jen přes TFDQuery. Předpokládám ale, že se Ti to v jedné proceduře nepodaří, protože pro update dat (vkládání, update, delete) používáš příkaz ExecSQL, který nevrací žádná data. Pro získání posledního ID potřebuješ mít klasický dotaz "SELECT LAST_INSERT_ID as product_id", který zároveň bude navázán na dataset. Uděláš aktivní dotaz, přečteš ID a dotaz ukončíš.
Já jsem měl něco takového:

function TFormHlavni.LastID : integer;
begin;
 QLastID.Active := true;
 result := DSLastID.DataSet.FieldByName('cislo').AsInteger;
 QLastID.Active := false;
end;

s tím, že na začátku aplikace jsem do QLastID (což právě byla komponenta TFDQuery) vložil QLastID.Sql.Add('SELECT LAST_INSERT_ID() as cislo'); a na QLastID mám navázanou komponentu TDataSource.
Tuto funkci jsem pak volal kdykoliv, když jsem vkládal data.

Offline chaloup

  • Plnoletý
  • ***
  • Příspěvků: 135
  • Karma: 11
    • Verze Delphi: Delphi 12.2
Re:Firedac TFDUpdateSQL + LAST_INSERT_ID
« Odpověď #2 kdy: 03-10-2024, 13:29:33 »
Není třeba používat nějaké specifické MySQL věci, Delphi mají podle dokumentace snad od XE5
funkci která provede podle nastaveného typu connection patřičná volání a vrátí poslední AutoGenValue:
Kód: [Vybrat]
function FireDAC.Comp.Client.TFDCustomConnection.GetLastAutoGenValue(const AName: String): Variant;
https://docwiki.embarcadero.com/Libraries/Athens/en/FireDAC.Comp.Client.TFDCustomConnection.GetLastAutoGenValue

Mě jde o to, jak jedním příkazem vytáhnout tohle z MySQL, v dokumentaci k TFDUpdateSQL:
https://docwiki.embarcadero.com/Libraries/Athens/en/FireDAC.Comp.Client.TFDUpdateSQL.InsertSQL
jsou příklady:
Kód: [Vybrat]
// SQL Server sample
FDUpdateSQL1.InsertSQL := 'INSERT INTO [Shippers] (COMPANYNAME, PHONE) ' +
  'VALUES (:NEW_COMPANYNAME, :NEW_PHONE); SELECT SCOPE_IDENTITY() AS SHIPPERID';

// Oracle sample
FDUpdateSQL1.InsertSQL := 'INSERT INTO ADDEMO."Shippers" (COMPANYNAME, PHONE) ' +
  'VALUES (:NEW_COMPANYNAME, :NEW_PHONE) RETURNING SHIPPERID INTO :NEW_SHIPPERID';
FDUpdateSQL1.Commands[arInsert].ParamByName('NEW_SHIPPERID').ParamType := ptOutput;
funguje mě i volání pro FirebirdSQL, ale na MySQL na to nemůžu pořád přijít...

v příkladu, který jsem uváděl je:
Kód: [Vybrat]
'INSERT INTO {id Products} (
ProductName, SupplierID, CategoryID,
QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder,
ReorderLevel, Discontinued)
VALUES (
:NEW_ProductName, :NEW_SupplierID,
:NEW_CategoryID, :NEW_QuantityPerUnit, :NEW_UnitPrice,
:NEW_UnitsInStock, :NEW_UnitsOnOrder, :NEW_ReorderLevel,
:NEW_Discontinued
)'
{IF MSSQL} select :NEW_ProductID = @@identity {FI}
{IF MSAcc} select @@identity as ProductID {FI}
{IF MySQL} select LAST_INSERT_ID() as ProductID {FI}
{IF IB} returning ProductID {into :NEW_ProductID} {FI}
{IF PG} returning ProductID {into :NEW_ProductID} {FI}
{IF SQLite}; select LAST_INSERT_ROWID() as ProductID {FI}
{IF Ora} returning ProductID into :NEW_ProductID {FI}
to bohužel nefunguje, zkoušel jsem nějaký kombinace, ale nic mě nefugovalo, hlásilo to chybu nebo to nevracelo správný data

jediný co mě napadlo a rozchodil jsem to je volat si Insert ručně v eventu UpdateRecord
a udělat po Insertu další volání výše uvedené fuknce a aktualizovat id ručně... zdá se mě to ale takový kostrbatý

Offline rholecek

  • Nováček
  • *
  • Příspěvků: 7
  • Karma: 0
    • Verze Delphi: Delphi 10.1 Update 2
Re:Firedac TFDUpdateSQL + LAST_INSERT_ID
« Odpověď #3 kdy: 03-10-2024, 14:20:25 »
Tak podle všeho Firebird umí toto:
insert into tabulka (sloupec) values(:data) returning ID;
čímž v jednom příkazu opravdu získáš last ID.

MySQL toto neumí. Takže to musíš na 2x. Jednou Insert a podruhé Select. Anebo využít tu fci GetLastAutoGenValue (neznal jsem, nemám zkušenosti).