AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Datenbanken Manipulation eines Records in einer FDQuery
Thema durchsuchen
Ansicht
Themen-Optionen

Manipulation eines Records in einer FDQuery

Ein Thema von Ykcim · begonnen am 15. Jun 2023 · letzter Beitrag vom 19. Jun 2023
Antwort Antwort
Seite 1 von 2  1 2      
Ykcim

Registriert seit: 29. Dez 2006
Ort: NRW
824 Beiträge
 
Delphi 10.4 Sydney
 
#1

Manipulation eines Records in einer FDQuery

  Alt 15. Jun 2023, 09:24
Datenbank: MsSQL • Version: 14 • Zugriff über: FireDac
Guten Morgen Zusammen,

seit einigen Tagen verzweifle ich an dem Versuch, einen Wert in einem Feld in einer FDQuery zu ändern. Der Hintergrund besteht darin, dass ich die Information von einem anderen Datenbank-Server abrufen muss und deshalb nicht alles in der gleichen Query durch führen kann...

Delphi-Quellcode:
MsQuery.SQL.Add('SELECT TOP 1 '+
                                'CASE WHEN ( '+
                                  'concat(rj.JOB_ID, ' + QuotedStr(' ') + ', JOB_NAME) is NULL) then '+
                                  'LAG(Concat(rj.JOB_ID, ' + QuotedStr(' ') + ', rj.JOB_NAME)) OVER (ORDER BY re.TIME_LOCAL DESC) ELSE '+
                                  'concat(rj.JOB_ID, ' + QuotedStr(' ') + ',rj.JOB_NAME) end AS JOB_NAME, '+
                                'CONVERT( varchar( 10 ), re.Time_Local, 104 ) AS Datum, '+
                                'convert(char(5), re.Time_Local, 108) AS Startzeit, '+
                                'rd.device_id, '+
                                'rd.device_name, '+
                                'ro.OPERATION_NAME, '+
                                'concat(ry.FIRST_NAME,' +QuotedStr(' ') + ', ry.FAMILY_NAME) AS Operator, '+
                                
...

                         'ORDER BY re.TIME_LOCAL desc ');
         MsQuery.ParamByName('Device_ID').AsString := Machine_ID;
         MsQuery.Open;
         DB_Modul.Write_LM_Protokoll('Refresh Daten Maschine ' + Machine_ID);


         CDMQuery.SQL.Clear;
         CDMQuery.sql.Add('select * from CDM_SM_DEVICE_OP_STATUS '+
                          'where deviceID = :Device '+
                          'and roleID = ' + QuotedStr('ID_Operator'));
         CDMQuery.ParamByName('Device').AsString := MsQuery.FieldByName('device_id').AsString;
         CDMQuery.Open;

         CDMQuery.First;
         MsQuery.First;
         MsQuery.Edit;
         MsQuery.FieldByName('Operator').AsString := CDMQuery.FieldByName('userID').AsString;
         MsQuery.Post;
Ich bekomme erst die Meldung: "Feld Operator kann nicht geändert werden." Das wird wahrscheinlich daran liegen, dass es sich um ein virtuellen Feld, das aus zwei Feldern zusammengesetzt wird.
Wenn ich es dann mit einem anderen Feld teste, bekomme ich die Meldung: "Invalid Field Columnname 'JOB_NAME'.

Das verstehe ich nicht, denn mit diesem Feld mache ich nichts. Es ist aber das erste Feld der MsQuery, sodass ich davon ausgehe, dass er das bei den anderen Feldern auch sagen würde.

Ich habe aber abgeprüft, und vor dem Post ist das Feld vorhanden und hat einen korrekten Wert.

Sieht jemand, was ich falsch mache?

Vielen Dank Patrick
Patrick
  Mit Zitat antworten Zitat
Benutzerbild von Jasocul
Jasocul

Registriert seit: 22. Sep 2004
Ort: Delmenhorst
1.354 Beiträge
 
Delphi 11 Alexandria
 
#2

AW: Manipulation eines Records in einer FDQuery

  Alt 15. Jun 2023, 09:44
Bei deinem ersten concat hast du nur JOB_NAME stehen und nicht rj.JOB_NAME.
Ich vermute, dass es daran liegen könnte.
Peter
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe
Online

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#3

AW: Manipulation eines Records in einer FDQuery

  Alt 15. Jun 2023, 09:49
Sowohl Operator als auch JOB_NAME sind keine echten Felder der Tabelle, sondern werden in der Query mit Concat zusammengesetzt. Das existierende Tabellenfeld JOB_NAME wird in der Abfrage nicht aufgeführt. Ein existierendes Feld mit einem virtuellen gleichen Namens zu kaschieren ist eh keine gute Idee. Wenn du JOB_NAME ändern willst, dann musst du dem virtuellen Feld einen anderen Namen geben und JOB_NAME mit in die Feldliste aufnehmen.

Natürlich könntest du das virtuelle Feld so belassen und JOB_NAME mit einem Alias versehen, aber das würde die Verwirrung nur vergrößern.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Ykcim

Registriert seit: 29. Dez 2006
Ort: NRW
824 Beiträge
 
Delphi 10.4 Sydney
 
#4

AW: Manipulation eines Records in einer FDQuery

  Alt 15. Jun 2023, 12:32
Hallo Zusammen,

vielen Dank für Eure Gedanken. Wenn ich die Daten ohne Manipulation ziehe und an die Clients übergebe, funktioniert das wunderbar. Leider sind die Daten aber in der Datenbank nicht korrekt, worauf ich keinen Einfluss habe. Daher ist es erforderlich die korrekten Daten aus der anderen Datenbank zu holen.

Ich habe mal JOB_NAME in JOB_NAME1 umbenannt:
Delphi-Quellcode:
 MsQuery.SQL.Add('SELECT TOP 1 '+
                                'CASE WHEN ( '+
                                  'concat(rj.JOB_ID, ' + QuotedStr(' ') + ', JOB_NAME) is NULL) then '+
                                  'LAG(Concat(rj.JOB_ID, ' + QuotedStr(' ') + ', rj.JOB_NAME)) OVER (ORDER BY re.TIME_LOCAL DESC) ELSE '+
                                  'concat(rj.JOB_ID, ' + QuotedStr(' ') + ',rj.JOB_NAME) end AS JOB_NAME1, '+
                                'CONVERT( varchar( 10 ), re.Time_Local, 104 ) AS Datum, '+
Dann bekomme ich die gleiche Fehlermeldung beim Post.

Ich hatte ja auch schon getestet, ob die Fehlermeldung ausbleibt, wenn ich ein echtes Feld verwende (OPERATION_NAME). Aber das klappt auch nicht.

Wie gesagt, ohne die Manipulation klappt das wunderbar und derzeit nutze ich die Software auch so, aber es arbeiten manchmal die falschen Mitarbeiter gerade an den Maschinen.

Hat jemand eine Idee, warum mit dem Post ein Problem auftritt?

Vielleicht verwende ich die FDQuery falsch, denn diese habe ich ohne Felder angelegt, sondern lasse die mit dem Open anlegen...

Hier mal die ganze Procedure...
Delphi-Quellcode:
procedure TMxSQL.Get_act_MachineData(Machine_ID: string; LStream: TStream; RefreshData, SendData: boolean);
var Logic: TLogic;
      MsQuery: TFDQuery;
      CDMQuery: TFDQuery;
      Operationslist: string;
begin
   if (RefreshData = false) and (DB_Modul.Tmr_LM_RefreshData.Enabled = false) and (SendData = true) then begin
      RefreshData := true;
      DB_Modul.Tmr_LM_RefreshData.Enabled := true;
      DB_Modul.FLM_OfflineState := 0;
      DB_Modul.Write_LM_Protokoll('RefreshTimer aktiviert.');
   end;

   if (RefreshData = false) and (DB_Modul.Tmr_LM_RefreshData.Enabled = true) and (SendData = true) then begin
      DB_Modul.Tmr_LM_RefreshData.Enabled := true;
      DB_Modul.FLM_OfflineState := 0;
      DB_Modul.Write_LM_Protokoll('OfflineState-Counter zurückgesetzt.');
   end;
   if (DB_Modul.Tmr_LM_RefreshData.Enabled = false) then begin
      DB_Modul.Tmr_LM_RefreshData.Enabled := true;
      DB_Modul.FLM_OfflineState := 0;
      DB_Modul.Write_LM_Protokoll('RefreshTimer aktiviert. OfflineState-Counter zurückgesetzt.');
   end;
   Logic := TLogic.create;
   MsQuery := TFDQuery(DB_Modul.FindComponent('Qry_LM_' + Machine_ID));
   Logic.Set_Query(CDMQuery, DB_Modul.PRINECT_CDM);
   try
      if (RefreshData = true) then begin
         MsQuery.Connection:=DB_Modul.PRINECT_APS;
         MsQuery.SQL.Clear;
         MsQuery.FetchOptions.AutoFetchAll;
         MsQuery.FetchOptions.Mode := fmAll;
         OperationsList := DB_Modul.Read_Einstellungswert('Life_Data_OperationList');
         MsQuery.SQL.Add('SELECT TOP 1 '+
                                'CASE WHEN ( '+
                                  'concat(rj.JOB_ID, ' + QuotedStr(' ') + ', JOB_NAME) is NULL) then '+
                                  'LAG(Concat(rj.JOB_ID, ' + QuotedStr(' ') + ', rj.JOB_NAME)) OVER (ORDER BY re.TIME_LOCAL DESC) ELSE '+
                                  'concat(rj.JOB_ID, ' + QuotedStr(' ') + ',rj.JOB_NAME) end AS JOB_NAME, '+
                                'CONVERT( varchar( 10 ), re.Time_Local, 104 ) AS Datum, '+
                                'convert(char(5), re.Time_Local, 108) AS Startzeit, '+
                                'rd.device_id, '+
                                'rd.device_name, '+
                                'ro.OPERATION_NAME, '+
                                'concat(ry.FIRST_NAME,' +QuotedStr(' ') + ', ry.FAMILY_NAME) AS Operator, '+
                                'CASE WHEN ( '+
                                  'DateDiff(minute, re.Time_Local, LAG(re.Time_Local) OVER (ORDER BY re.TIME_LOCAL DESC)) is NULL) then '+
                                  'Concat(DateDiff(minute, re.Time_Local, GETDATE()),' + QuotedStr(':00 (') + ',convert(char(5), re.Time_Local, 108), ' + QuotedStr(')') + ') ELSE '+
                                  'ConCat(DateDiff(minute, re.Time_Local, LAG(re.Time_Local) OVER (ORDER BY re.TIME_LOCAL DESC)),' + QuotedStr(':00 (') + ',convert(char(5), re.Time_Local, 108), ' + QuotedStr(')') + ') end AS Dauer, '+
                                '(SELECT SPEED FROM RBC_DEVICE_BASIC_INTERVALS RDB WHERE RDB.DEVICE_BASIC_INTERVAL_KEY = '+
                                  '(SELECT MAX(Device_Basic_interval_key) FROM RBC_DEVICE_BASIC_INTERVALS RDBI WHERE RDBI.DEVICE_KEY = re.DEVICE_KEY)) AS Speed, '+
                                'Concat(ws.PERCENT_COMPLETED,' + QuotedStr(' %') + ') AS PERCENT_COMPLETED, '+
                                'ws.PLANNED_GOOD_AMOUNT, '+
                                'ws.GOOD_CYCLES, '+
                                'ro.OPERATION_KEY, '+
                                'ws.WORK_STEP_NAME '+
                         'from RPS_EVENTS re '+
                         'LEFT JOIN RPS_WORK_STEPS ws ON ws.WORK_STEP_KEY = re.WORK_STEP_KEY '+
                         'LEFT JOIN RPS_JOBS rj ON rj.JOB_KEY = ws.JOB_KEY '+
                         'LEFT JOIN RPS_EMPLOYEE_ACTIVITIES ea ON ea.WORK_STEP_KEY = ws.WORK_STEP_KEY '+
                         'LEFT JOIN RPS_OPERATIONS ro ON ro.OPERATION_KEY = re.OPERATION_KEY '+
                         'LEFT JOIN RBC_DEVICES rd ON rd.device_key = re.device_key '+
                         'LEFT JOIN RBC_EMPLOYEES ry ON ry.EMPLOYEE_KEY = ea.EMPLOYEE_KEY '+
                         'WHERE rd.DEVICE_ID = :Device_ID '+
                         'AND CONVERT( date, re.TIME_LOCAL) = CONVERT( date, GETDATE()) '+
                         'AND re.OPERATION_KEY IN ( ' + OperationsList + ' ) '+
                         'GROUP BY rj.JOB_NAME, '+
                                  'rj.job_id, '+
                                  're.Time_Local, '+
                                  're.Device_key, '+
                                  'rd.device_id, '+
                                  'rd.device_name, '+
                                  're.OPERATION_KEY, '+
                                  'ro.OPERATION_KEY, '+
                                  'ro.OPERATION_NAME, '+
                                  'ry.FIRST_NAME, '+
                                  'ry.FAMILY_NAME, '+
                                  'ws.PERCENT_COMPLETED, '+
                                  'ws.PLANNED_GOOD_AMOUNT, '+
                                  'ws.GOOD_CYCLES, '+
                                  'ws.WORK_STEP_NAME '+
                         'ORDER BY re.TIME_LOCAL desc ');
         MsQuery.ParamByName('Device_ID').AsString := Machine_ID;
         MsQuery.Open;
         DB_Modul.Write_LM_Protokoll('Refresh Daten Maschine ' + Machine_ID);


         CDMQuery.SQL.Clear; //Ohne den nachfolgenden Teil bis zum Post klappt alles wunderbar. Felder und Werte sind da.
         CDMQuery.sql.Add('select * from CDM_SM_DEVICE_OP_STATUS '+
                          'where deviceID = :Device '+
                          'and roleID = ' + QuotedStr('ID_Operator'));
         CDMQuery.ParamByName('Device').AsString := MsQuery.FieldByName('device_id').AsString;
         CDMQuery.Open;

         CDMQuery.First;
         MsQuery.First;
         MsQuery.Edit;
         MsQuery.FieldByName('Operator').AsString := CDMQuery.FieldByName('userID').AsString;
         MsQuery.Post; //Hier knallt es
      end;



      if SendData then begin
         if Assigned(LStream) then begin
            if MsQuery.State = dsInactive then begin
               DB_Modul.Write_LM_Protokoll('Query('+Machine_ID+') ist inaktiv. Wartezeit 2 Sek.');
               Sleep(2000);
            end;
            if MsQuery.State = dsBrowse then begin
               MsQuery.SaveToStream(LStream, sfJSON);
               DB_Modul.Write_LM_Protokoll('Sent Daten ('+Machine_ID+') LifeMonitor.');
            end
            else begin
               DB_Modul.Write_LM_Protokoll('ERROR: Query nicht aktiv ('+Machine_ID+').');
            end;
         end
         else begin
            DB_Modul.Write_LM_Protokoll('ERROR: No Stream assigned ('+Machine_ID+').');
         end;
      end;
   Finally
      Logic.Free;
      CDMQuery.Free;
   end;
end;
Vielen Dank
Patrick
Patrick

Geändert von Ykcim (15. Jun 2023 um 12:35 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe
Online

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#5

Query

  Alt 15. Jun 2023, 12:41
Ich habe mal JOB_NAME in JOB_NAME1 umbenannt:
Delphi-Quellcode:
 MsQuery.SQL.Add('SELECT TOP 1 '+
                                'CASE WHEN ( '+
                                  'concat(rj.JOB_ID, ' + QuotedStr(' ') + ', JOB_NAME) is NULL) then '+
                                  'LAG(Concat(rj.JOB_ID, ' + QuotedStr(' ') + ', rj.JOB_NAME)) OVER (ORDER BY re.TIME_LOCAL DESC) ELSE '+
                                  'concat(rj.JOB_ID, ' + QuotedStr(' ') + ',rj.JOB_NAME) end AS JOB_NAME1, '+
                                'CONVERT( varchar( 10 ), re.Time_Local, 104 ) AS Datum, '+
Dann bekomme ich die gleiche Fehlermeldung beim Post.

Ich hatte ja auch schon getestet, ob die Fehlermeldung ausbleibt, wenn ich ein echtes Feld verwende (OPERATION_NAME). Aber das klappt auch nicht.
Das liegt daran, dass weder JOB_NAME noch OPERATION_NAME in der Query explizit in der Feldliste auftauchen. Eine FieldByName auf eines dieser Felder sollte demnach bereits fehlschlagen.

Felder, die du ändern willst, müssen in der Query angegeben sein.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Ykcim

Registriert seit: 29. Dez 2006
Ort: NRW
824 Beiträge
 
Delphi 10.4 Sydney
 
#6

AW: Manipulation eines Records in einer FDQuery

  Alt 15. Jun 2023, 12:50
Genau das verstehe ich nicht.

Wenn ich einen Haltepunkt auf MSQuery.Post setze und dann im Debugger die Werte
Delphi-Quellcode:
   MsQuery.FieldByName('Operation_Name').AsString
   MsQuery.FieldByName('Job_Name').AsString
prüfe, dann finde ich sie und sie haben die aktualisierten Werte. Wenn ich einen Haltepunkt bei MSQuery.First setze, finde ich Werte
Delphi-Quellcode:
   MsQuery.FieldByName('Operation_Name').AsString
   MsQuery.FieldByName('Job_Name').AsString
ebenfalls, nur dass sie dann noch die ursprünglichen Werte haben...
Patrick
  Mit Zitat antworten Zitat
Benutzerbild von Jasocul
Jasocul

Registriert seit: 22. Sep 2004
Ort: Delmenhorst
1.354 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: Manipulation eines Records in einer FDQuery

  Alt 15. Jun 2023, 12:53
group by und dann ein Edit?
Was soll denn in dem Fall geändert werden? Alle Treffer, die in das group by für das Feld fallen?

Ich denke, du wirst ein separates Update-Statement benötigen.

Zu den ganzen True/False vergleichen, spare ich mir an dieser Stelle den Kommentar
Peter
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe
Online

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#8

Query

  Alt 15. Jun 2023, 13:25
group by und dann ein Edit?
Was soll denn in dem Fall geändert werden? Alle Treffer, die in das group by für das Feld fallen?

Ich denke, du wirst ein separates Update-Statement benötigen.
Das GROUP BY hatte ich noch gar nicht entdeckt. In dem Fall geht das mit dem Post natürlich gar nicht, da der einzelne Datensatz ja nicht identifiziert werden kann. In der Regel braucht FireDAC einen Primary Key Wert für ein Post. Den gibt es bei gruppierten Queries aber nicht.

Mit den passenden Einstellungen kann man auch ohne den Primary Key Datensätze ändern, aber es muss eben immer eine 1:1 Beziehung zischen dem aktuellen Record in der Query und dem Datensatz in der zu ändernden Tabelle geben.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Ykcim

Registriert seit: 29. Dez 2006
Ort: NRW
824 Beiträge
 
Delphi 10.4 Sydney
 
#9

AW: Manipulation eines Records in einer FDQuery

  Alt 15. Jun 2023, 14:28
ich glaube, jetzt muss ich eine ganz blöde Frage stellen...

Was mache, wenn ich gar nicht die Daten auf der Datenbank ändern möchte, sondern nur die Ergebnis-Daten der Abfrage in der Query selbst?
Die Query nutze ist als Zwischenspeicher und immer, wenn ein Client die Daten abruft, bekommt er sie aus der Query, via Query.SaveToStream. Dabei werden die Daten aber nicht neu von der Datenbank abgefragt. Das passiert unabhängig davon nach einem Zeitintervall.

Also ich möchte das Ergebnis (Query hat in diesem Fall nur einen Datensatz) ändern, ohne das irgendetwas zur Datenbank gespielt wird...
Patrick
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe
Online

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#10

AW: Manipulation eines Records in einer FDQuery

  Alt 15. Jun 2023, 14:52
Dann solltest du die Daten in einem TFDMemTable bearbeiten, den du aus der Query füllst.

Alternativ kannst du auch bei der Query CachedUpdates auf True stellen und einfach kein ApplyUpdates aufrufen.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:06 Uhr.
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