Jump to content
PenelopeSkye

Must have multiple var sections

Recommended Posts

Unless I want to have a lot of undeclared identifiers I have to have multiple var sections, see below.  That is so wrong!

 

Also, this array declaration doesn't work under any circumstances even though I lifted it from another unit in the project and made sure it has the same uses list.

x: array[0..9] of variant;

The procedure in the other unit was not a (Sender: TObject) procedure (sorry for my ignorance of what to call that).

 

 

What am I doing wrong?

 

The list below has no errors when I put in all the var sections.

procedure TfDesignMaster.PopulatePdlNotesWithValuePack(Sender: TObject);
begin
var
  stocknummm,value,value1,value2,keyfields, fieldname: string;
  var
  F: TField;
  var
  i: integer;
  var
  lresult: boolean;
  var
  fn:=tstringlist.create;
  var
  sl:=tstringlist.create;


 

Share this post


Link to post

The var goes before the begin.

procedure TfDesignMaster.PopulatePdlNotesWithValuePack(Sender: TObject);
var
  stocknummm,value,value1,value2,keyfields, fieldname: string;
  F: TField;
  i: integer;
  lresult: boolean;
  fn: TStringList;
  sl: TStringList;
begin
  fn:=tstringlist.create;
  sl:=tstringlist.create;

Surprisingly the DocWiki does not clarify this: https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Variables_(Delphi) at least on that page.

Share this post


Link to post

when using:

Quote

begin

   var MyVar: string;

    ....

    showmessage( MyVar );

   ...

end; 

you can understand like this:

Quote

begin

   var MyVar: string;

   BEGGIN

    ....

    showmessage( MyVar );

    END;

   ...

end; 

like into a "BLOCK" = SCOPE

Edited by programmerdelphi2k

Share this post


Link to post
27 minutes ago, PenelopeSkye said:

Unless I want to have a lot of undeclared identifiers I have to have multiple var sections, see below.  That is so wrong!

 

Also, this array declaration doesn't work under any circumstances even though I lifted it from another unit in the project and made sure it has the same uses list.

x: array[0..9] of variant;

The procedure in the other unit was not a (Sender: TObject) procedure (sorry for my ignorance of what to call that).

 

There are two ways to declare variables inside a method or standalone procedure or function.

Sherlock's reply shows the traditional way of declaring all variables in a single var section before the begin keyword that starts the body of the method. That has been part of the Pascal language since the time of its inception by Wirth; variables you declare this way are accessible in every place inside the body of the method. What you showed in your post is a fairly new way to declare variables inline, near the place of first use. In my opinion this should only be used if you need to reduce the scope of a variable to a specific block (e.g. a begin ... end block for an if statement or for loop).  In fact in my real opinion it should not be used at all :classic_dry:; for one it is alien to the general structure of the language, and some IDE features do not work correctly (in the current version) when they are used, e.g. refactorings and things depending on the LSP server, like code completion.

If you need a lot of variables in a method this is actually a "code smell", it indicates your method is too large and tries to do too many things. Refactor it to call several smaller methods that each do a single task. If that gets complex (i.e. you find you actually need a lot of methods to partition the code correctly) the solution may be to create a new class that does the required work internally and isolates it from the calling code.

The array issue you mentioned probably has a different cause. If you declare a variable with a syntax like

 x: array [1..9] of variant;

you are using what is called an anonymous type for the variable. This is allowed for classical variables declared at the top of the method but may not be allowed for inline variables. If in doubt declare a proper type and use that for the variable:

procedure....
type
  T9Variants = array [1..9] of variant;
var
  x: T9Variants;

 

  • Like 2

Share this post


Link to post

FYI I am trying to get the values from a query into an array. I am trying a lot of stuff cause I am not sure how I do it, hence all the variables!

 

I will get rid of a lot of them once I figure out how to do this!

Share this post


Link to post

I think that "a class" for this would help better than works with "variants", because you will need always "trusth" in each "variant value" when in use!

using a class you can do it with more trusth (or same using a record type with all types-for-your-fields!

some like this...

// using a record for example
type
  TMyRecordToManyTypes = record
    id: integer;
    name: string;
    birthday: TDate;
    active: boolean;
  end;

procedure TForm1.procedureXXXXX(Sender: TObject);
var
  MyDatas   : TMyRecordToManyTypes;
  MyArrDatas: TArray<TMyRecordToManyTypes>;  // same that: array of TMyRecordToManyTypes
begin
  // where needs stored in your array of values
  while FDMemTable1.Eof do
    begin
      MyDatas.id := FDMemTable1.FieldByName('xxxx').AsInteger;
      // ... another fields...
      //
      MyArrDatas := MyArrDatas + [MyDatas]; // like a dictionary usage!
    end;
  //
  // if needs arbitrary values...
  //
  // MyDatas.id       := 1;
  // MyDatas.name     := 'hello world';
  // MyDatas.birthday := now;
  // MyDatas.active   := false;
  //
  // MyArrDatas := MyArrDatas + [MyDatas];
  //
  //
  // when needs read it
  for var MyData in MyArrDatas do
    ShowMessage(MyData.name);
end;

 

Edited by programmerdelphi2k

Share this post


Link to post

Since you are kind enough to look into getting values from an array this is what I have so far. I can get the 2 values I want n each pass of the loop, but I want to be able to put both values together in a sentence and display them in a memo box.

You were kind enough to provide code but will it work if I use the code below to get the both values into a sentence since it is already set up and the code above makes my brain hurt?  I wish I were more experienced! Thanks!

 

procedure TfDesignMaster.PopulatePdlNotesWithValuePack(Sender: TObject);
begin
//var designid: string;
var
stocknummm: string;
var
F: TField;
  stocknummm := dm.tb_design_master.fieldbyname('jmc_stock_num').asstring;
  ShowMessage(stocknummm);
    with  dm do
    Begin

      q_GetStockNumFromValuePackLinks.SQL.Clear;
      q_GetStockNumFromValuePackLinks.SQL.Add('select Stock_pack,Qty1 from ValuePackLinks where Pack_component1 = '+stocknummm) ;
      q_GetStockNumFromValuePackLinks.Open;
               while not q_GetStockNumFromValuePackLinks.EOF do begin
    for F in q_GetStockNumFromValuePackLinks.Fields do begin
    ShowMessage(F.Value);
     q_GetStockNumFromValuePackLinks.Next;
  end;
    q_GetStockNumFromValuePackLinks.Close;
   end;
    End;
end;

Share this post


Link to post

@PenelopeSkye

if you necessity is just read and show the records, then, you dont needs so much... just use your SQL to find the record, and using a "While not xxxxx.EOF do..." it's enough! But you need read and store this values in some place (object, var, array, etc...) then, it's not more complicated too! look

// defining my record-body...
type
  TMyRecordToMyData = record
    ID: integer;       // my EmpNo field
    FirstName: string; // my FirstName field
    // ...
  end;

  TMyArrOfMyDatas = TArray<TMyRecordToMyData>; // my dictionary for my datas

procedure TForm1.Button1Click(Sender: TObject);
var
  MyDatas       : TMyRecordToMyData; // for each record readed in my table...
  MyArrOfMyDatas: TMyArrOfMyDatas;   // like a dictionary off-line...
  LText         : string;            // just for tmp usage...
begin
  // example: Employee (Interbase) from Embarcadero DB demo!
  //
  // Clearing and defining new "SQL" command...
  // 1º "empno" = field in the table
  // 2º "empno" = the "param name" that im using for indicating my Employee number...
  FDQuery1.Close; // always closing before any action...
  //
  // your select with your params, where, filter, etc... your SQL command!!!
  // the param-name can be any name, not used in reserved-word SQL!!!
  //
  // ex.: "select id, name from mytable where empno = :MyParamNameForEmpno"
  //
  FDQuery1.SQL.Text := 'select * from employee where empno = :empno'; // param-name = "empno"
  //
  FDQuery1.Params.ParamByName('empno').AsInteger := 2; // always using same param-name above!
  //
  FDQuery1.Open; // you can use "FDQuery1.Open( ' your SQL command here ' );" in some situations.... ok?
  //
  // simple way to catch all fields (if it can be casting to "string") for example!!!
  // no needs any "var, array, etc..." just read and write in your memo or any other target...
  while not FDQuery1.Eof do
    begin
      LText := '';
      //
      for var i: integer := 0 to (FDQuery1.Fields.Count - 1) do // field name + field value
        LText            := LText + FDQuery1.FieldDefs[i].Name + ' = ' + FDQuery1.Fields[i].AsString + slinebreak;
      //
      Memo1.Lines.Add(LText);
      //
      FDQuery1.Next; // to avoid "infinity looping" and catch next values...
    end;
  //
  //
  // another way, if you need store you values in a "array" or another type (class, record, etc...)
  //
  FDQuery1.First;
  //
  while not FDQuery1.Eof do
    begin
      // another ways:
      // FDQuery1.Fields.FieldByName('...').AsInteger;
      // FDQuery1.Fields[0].AsInteger;
      // FDQuery1.FieldByName('...').AsInteger;
      // etc...
      MyDatas.ID        := FDQuery1['empno']; // FireDAC accept this way too!
      MyDatas.FirstName := FDQuery1['firstname'];
      //
      // building my list of datas
      MyArrOfMyDatas := MyArrOfMyDatas + [MyDatas];
      //
      FDQuery1.Next;
    end;
  //
  for var MyData in MyArrOfMyDatas do
    Memo1.Lines.Add('ID=' + MyData.ID.ToString + ', Name=' + MyData.FirstName);
  //
  // you can delete an item in your array, dont worry, nothing will be delete from your table!!!
  //
  // let's say that exists 10 items, and you want delete the 2nd item just... no more!
  Delete(MyArrOfMyDatas, 2, 1); // deleting from 2º item, and only 1 item ... if exists, of course!
  //
end;

image.thumb.png.61d034e034681ddcb8af64f9e3f19d58.png    Project1_3dXRO7fSAW.thumb.gif.8dcc452cf59a3a4542a03cf623a94052.gif

Edited by programmerdelphi2k

Share this post


Link to post

I have started working with your code, thank you so much for adding comments!!!  I am having some issues that I am working on, I will post back here if I can't solve them if you wouldn't mind.

 

Thank you!

 

 

Share this post


Link to post

I spoke too soon!  It works!  It feels too impersonal to thank your handle, so I shall call you Victor. 

 

Thank you so much Victor!!!

Share this post


Link to post

not for that... call myself "Bond"... (... suspense music in the air...)  ...James Bond  😂😁

Edited by programmerdelphi2k

Share this post


Link to post

Hi James, I hope you will see this, I will wait a bit then post is in a new topic.

 

I have a table with the following fields.  It was not my design choice but I was overruled.

I needed to search every pack_component field in every row for a specific value, so I chose union to bring that about.

You gave me most of the code I used to create this procedure which finds the value and its' position and display it in a memo box.

The code works perfectly but every now and then I get the attached error.

Can you tell me why since the code works?  Thank you!

 

[vp_id]
,[Presentation]
,[Design_id]
,[Stock_pack]
,[Order1],[Pack_component1],[Qty1]
,[Order2],[Pack_component2],[Qty2]
,[Order3],[Pack_component3],[Qty3]
,[Order4],[Pack_component4],[Qty4]
,[Order5],[Pack_component5],[Qty5]
,[Order6],[Pack_component6],[Qty6]
,[Order7],[Pack_component7],[Qty7]
,[Order8],[Pack_component8],[Qty8]
,[Order9],[Pack_component9],[Qty9]
,[Order10],[Pack_component10],[Qty10]
,[Order11],[Pack_component11],[Qty11]
,[Order12],[Pack_component12],[Qty12]

 

 

procedure TfDesignMaster.PopulatePdlNotesWithValuePack2(Sender: TObject);
begin
//var designid: string;
var
stocknummm,LText1,LText2,StockFromVP: string;
var
F: TField;
  stocknummm := dm.tb_design_master.fieldbyname('jmc_stock_num').asstring;
  StockFromVP := dm.tblValuePackLinks.fieldByName('Stock_pack').asString;
  Panel35.Visible :=false;
  Memo1.Clear;
  //ShowMessage(stocknummm);

    with  dm do
  begin

    q_GetStockNumFromValuePackLinks.SQL.Clear;
    q_GetStockNumFromValuePackLinks.SQL.Add('select Stock_pack,stockOrder = 1 from ValuePackLinks where Pack_component1 = ' +stocknummm ) ;
    q_GetStockNumFromValuePackLinks.SQL.Add('union' ) ;
    q_GetStockNumFromValuePackLinks.SQL.Add('select Stock_pack,stockOrder = 2 from ValuePackLinks where Pack_component2 = ' +stocknummm  ) ;
    q_GetStockNumFromValuePackLinks.SQL.Add('union  ' ) ;
    q_GetStockNumFromValuePackLinks.SQL.Add('select Stock_pack,stockOrder = 3 from ValuePackLinks where Pack_component3 = ' +stocknummm ) ;
    q_GetStockNumFromValuePackLinks.SQL.Add('union '  ) ;
    q_GetStockNumFromValuePackLinks.SQL.Add('select Stock_pack,stockOrder = 4 from ValuePackLinks where Pack_component4 = ' +stocknummm  ) ;
    q_GetStockNumFromValuePackLinks.SQL.Add('union '  ) ;
    q_GetStockNumFromValuePackLinks.SQL.Add('select Stock_pack,stockOrder = 5 from ValuePackLinks where Pack_component5 = ' +stocknummm  ) ;
    q_GetStockNumFromValuePackLinks.SQL.Add('union'   ) ;
    q_GetStockNumFromValuePackLinks.SQL.Add('select Stock_pack,stockOrder = 6 from ValuePackLinks where Pack_component6 = ' +stocknummm  ) ;
    q_GetStockNumFromValuePackLinks.SQL.Add('union' ) ;
    q_GetStockNumFromValuePackLinks.SQL.Add('select Stock_pack,stockOrder = 7 from ValuePackLinks where Pack_component7 = ' +stocknummm  ) ;
    q_GetStockNumFromValuePackLinks.SQL.Add('union' ) ;
    q_GetStockNumFromValuePackLinks.SQL.Add('select Stock_pack,stockOrder = 8 from ValuePackLinks where Pack_component8 = ' +stocknummm ) ;
    q_GetStockNumFromValuePackLinks.SQL.Add('union' ) ;
    q_GetStockNumFromValuePackLinks.SQL.Add('select Stock_pack,stockOrder = 9 from ValuePackLinks where Pack_component9 = ' +stocknummm  ) ;
    q_GetStockNumFromValuePackLinks.SQL.Add('union' ) ;
    q_GetStockNumFromValuePackLinks.SQL.Add('select Stock_pack,stockOrder = 10 from ValuePackLinks where Pack_component10 = ' +stocknummm  ) ;
    q_GetStockNumFromValuePackLinks.SQL.Add('union' ) ;
    q_GetStockNumFromValuePackLinks.SQL.Add('select Stock_pack,stockOrder = 11 from ValuePackLinks where Pack_component11 = ' +stocknummm  ) ;
    q_GetStockNumFromValuePackLinks.SQL.Add('union'  ) ;
    q_GetStockNumFromValuePackLinks.SQL.Add('select Stock_pack,stockOrder = 12 from ValuePackLinks where Pack_component12 = ' +stocknummm ) ;


      //ShowMessage(   q_GetStockNumFromValuePackLinks.SQL.Text)  ;
      q_GetStockNumFromValuePackLinks.Open;


    while not q_GetStockNumFromValuePackLinks.EOF do begin
          for F in q_GetStockNumFromValuePackLinks.Fields do begin

       LText1 := '';
      //
      for var i: integer := 0 to (q_GetStockNumFromValuePackLinks.Fields.Count - 1) do // field name + field value
        LText1            :=  q_GetStockNumFromValuePackLinks.Fields[0].Value;
        LText2            :=  q_GetStockNumFromValuePackLinks.Fields[1].Value;
        //ShowMessage(LText1);

      dm.q_GetStockNumFromValuePackLinks.Next; // to avoid "infinity looping" and catch next values...
    end;
                  //ShowMessage(LText1);
                  if    q_GetStockNumFromValuePackLinks.Fields[0].Value <> ''
                  then
                  Panel35.Visible :=true
                  else
                  Panel35.Visible :=false;

           q_GetStockNumFromValuePackLinks.Next;
        end;

        Memo1.Lines.Add('Bag '+stocknummm+' is in Value Pack ('+LText1+') in Position (' +LText2+')' );

                  q_GetStockNumFromValuePackLinks.Close;

         end;

end;

UnionError.jpg

Share this post


Link to post

your initial error is in 

.Add('select Stock_pack,stockOrder = 1 from ValuePackLinks where Pack_component1 = ' +stocknummm ) ;

 

try some like this:

procedure TForm1.Button1Click(Sender: TObject);
const
  LSQLSelect: string = 'SELECT xFieldx from xTablex WHERE yFieldy = %d';
var
  LValues : TArray<integer>;
  LSQLText: string;
begin
  for var i: integer := 1 to 10 do // just for test values... not necessar!
    LValues          := LValues + [i];
  //
  LSQLText := '';
  //
  for var i in LValues do  // more quick than use a component.property 
    LSQLText := LSQLText + '***' + Format(LSQLSelect, [i]); // + slinebreak + ' UNION ' + slinebreak;
  //
  if not(LSQLText.IsEmpty) then
    begin
      // LSQLText := LSQLText.Remove(0, 3);                                        // remove 3 chars on init... '***';
      LSQLText := LSQLText.Remove(0, 3).Replace('***', slinebreak + ' UNION ' + slinebreak); // replace '***' for another text
      //
      Memo1.Text := LSQLText;
      //
      // if all it's ok, then you can use it:   MyFDQuery.SQL.Text := LSQLText; // directly
    end;
end;

end.

image.png.4355bfdf28b3ca753f15183fea4836d2.png

Edited by programmerdelphi2k

Share this post


Link to post

you can use "Format(...)" function to replace values in your string:

Quote

  LSQLText := Format('SELECT %s from %s WHERE %s = %d', ['field1', 'table1', 'field2', 12345 ]);

 

you can try use "MACRO" in FireDAC, too:

Quote

SELECT !FieldX    from   !TableX where !FieldY  !Sign !FieldValue

 

...  for each macro type/value you create your Param definitions:

  MyMacro:= qryMain.Macros.Add;
  MyMacro.Name := 'xxxxx';
  MyMacro.DataType := TFDMacroDataType.mdString;
  MyMacro.Value := 'xxxxx';

....

see on Help for more details!!!

 

Share this post


Link to post

more one tip:  "IF"  (I said "IF") possible, forget "WITH" usage... mainly when for while... it's very confused...  when you are a "master", then, all it's allowed 🙂

Share this post


Link to post

another BIG TIP... when you're posting a "CODE" like above use the button image.png.7b3f39cb7da78a21713c8079a3d380de.png  and choice "Delphi" as your language and "Insert..." next, next...

Share this post


Link to post

Doh!  It should have been obvious that that button is what brackets code!  Thank you!  

 

I am going to start studying the code you gave my above until I understand it, thanks again James!

Share this post


Link to post

What database? Some databases have UNPIVOT to more easily convert columns to rows (the reverse of PIVOT which converts rows to columns). 

Edited by Brian Evans

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×