76

(6 replies, posted in SQL queries)

Hello Vasco,


I come after the battle, but I still think this info can be usefull.


I don't like the last_insert_id, because it will get you the last inserted ID whatever the table.


Consider this : you insert a new product in your product table, and you want it's ID in your combobox. But just after inserting the product, you have a second query inserting the price of the product in another table. Which ID will you get in your combobox ? Yes, the ID of the price record in the price table, and that's not what you want.


Other example : instead of inserting a new product, you update an existing one. Last_insert_id will get you the last inserted ID whatever the table, when what you want is the ID of the updated record.


You only should use last_insert_id if what you use it for occurs immediately after the insertion, and nothing else in between.


Cheers


Mathias

Hello Vasco smile


Yes this is possible.


I will take an example that I know well because it's part of one of my projects.


Let's say you have 3 tables :
- table 1 contains a list of products
- table 2 contains a list of sellers

With such an architecture, I can link a product with one and only one seller.
If I want to be able to link multiple products with multiple sellers, I need a table in between, this is table 3
- table 3 contains products IDs and sellers IDs


Let's start from table 3 and get all the names of all the sellers that are referenced in it (we don't take car of the products right now)

It's just a matter of selecting seller_name from the seller table where the seller ID is in table 3. This translates in SQL like :

SELECT
seller.seller_name
FROM
seller
INNER JOIN product_seller ON product_seller.id_seller = seller.id

Now, with this query, keep in mind that if a seller is referenced 150 times, it will be listed 150 times on the result query.


If you want it only once, even if he appears multiple times, you need an extra something in the query : the DISTINCT keyword :

SELECT DISTINCT
seller.seller_name
FROM
seller
INNER JOIN product_seller ON product_seller.id_seller = seller.id

This ensures that you will get each seller only once BUT...


As soon as you will add parameters to your query, the DISTINCT keyword will act differently.
For example, I you add the product ID to the query like :

SELECT DISTINCT
product.id,
seller.seller_name
FROM
seller
INNER JOIN product_seller ON product_seller.id_seller = seller.id

Even the DISTINCT keyword, the seller name will be repeated as many times as it is linked with unique IDs of products.


Anyway, this is how to do it. Hope this helped.


Mathias

78

(8 replies, posted in Script)

Hello Vasco,


I encountered a similuar situation when I wanted to compare values from my database with values found online. Here is how I solved the problem :

First I create a TStringList :

LocalList := TStringList.Create;

Then I populate the list with the result of a query :

SQLQuery('SELECT asset_sku FROM asset WHERE id_vendor = 1 AND asset_is_reserved = 0',Results);

                        //-----> Now let's fill the localList with the results of the query
                            while not Results.Eof do
                                begin
                                    LocalList.add(Results.FieldByName('asset_sku').AsString);
                                    Results.Next;
                                end;
                            Results.Free;

(in your case this would be id's and not asset_sku)


Now the list is full of local references, I use the same technique to create a second one but with online data.

OnlineList := TStringList.Create;

and I fill it with another procedure.


Comparing both list was just a matter of checking the existence of an item from one list into another like this :

for i := 0 to OnlineList.Count - 1 do
     begin
          ...
          if localList.IndexOf(onlineList.Strings(i)) = -1 then
          ...
     end;

meaning : "if index of element i from OnlineList into LocalList is not found (-1)  then..."
If another value is returned, it means that the element is present in the list and the value is it's index.


Now, regarding your array question. You usually create an Array by splinting a TStingList.


Remember the

LocalList.add(Results.FieldByName('asset_sku').AsString);

command ?


We did not mention any separator for the list, the default one being a comma. So to get an array of strings out of the list, it's just a matter of splitting into after every comma like this :

LocalArray := SplitString(LocalList,',');

(declare your Array of String or Integer into the variable section, but you do not need ti initialize (create) it before using)


SIDE NOTE 1
If you already have a string with value separated by commas, you can load it directly into a TstringList like this :

OnlineList := TStringList.Create;
OnlineList.CommaText := sku_string;

SIDE NOTE 2
So, TstringList or Array ? That's up to you. I personally find it easier with TstingList to handle data in memory, to add or remove values and so on. All those things you can certainly do with an Array as well. But Array, especially multi-dimensional ones can get tricky, so I tend to stick to the following principle : KISS (keep it simple stupid).


Hope this helped a little


Cheers


Mathias

79

(7 replies, posted in General)

Bonjour Jean,


J'ai jeté un œil sur ton code et j'ai vu que tu utilisais les fonctions automatiques de MVD (ce qui est très bien). Cependant, je ne sais pas si tu peux éviter la multiplication des images en procédant de la sorte. C'est une fonction de Windows me semble t'il que ce renommage automatique pour éviter les écrasement de fichiers et, à moins que Dmitry ne rajoute une option pour passer outre, je ne vois pas comment l'éviter sans coder toute la procédure de sauvegarde.


En l'état actuel, tu peux vérifier si le fichier existe déjà (en comparant les noms de fichiers dans le répertoire avec le nom du fichier chargé dans le composant DBImage), mais comme c'est le composant DBImage qui au final se charge de la sauvegarde, cela n'a aucun effet.


Mathias

80

(7 replies, posted in General)

Hello Jean,


There are two approaches : check if file exist or check if file does not exist.


if FileExists('path to the image and name of the image with extension') then
     begin
         Some awesome code
    end;
if not FileExists('path to the image and name of the image with extension') then
        begin
            Some awesome code
        end;

In the situation you described, I'd check for non existence of the file and if true then save to disk and load, else, just load.
This could look like :

with Form1.DBImage1 do
    begin
        if not FileExists('path to the image and name of the image with extension') then
            begin
                HTTPGetFile('URL of the image','path to save image and name of the image with extension',True);
                LoadPicture('path to the image and name of the image with extension');
            end
       else if FileExists('path to the image and name of the image with extension') then
           begin
               LoadPicture('path to the image and name of the image with extension');
           end;
     end;

Hope this helps a little, do not hesitate if you have moire specific questions on the matter.


Cheers


Mathias

81

(3 replies, posted in General)

Hello Dmitry,


Thanks a lot, problem is solved.


Just out of curiosity, was it a SSL key length problem or something else ?


Cheers


Mathias

82

(10 replies, posted in Script)

Bonjour Jean-Marc,


I've been pocking around your script and found two interesting details.


The first one is that assertion at the beginning :

uses 'toolbox.pas';   

I found the file in the script folder but was wondering if you managed to really use it by including it at the beginning of your script, or if it was just some leftover code you forgot to delete smile


Second this is that 'wbGetFile.exe' application that you distribute with your compiled project.

Would you mind showing us how you managed to pass the download URL from MVD to that application ?


Cheers


Mathias (de Nouvelle Calédonie)

83

(3 replies, posted in General)

Hello Dmitry,


Since the last few days, I have this error message showing up while trying to read HTTPS pages :


http://i.imgur.com/ebIIDVs.png


The faulty code is as follows :

try
     source_url := 'https://www.renderosity.com/mod/bcs/?br=new&page_number='+IntToStr(page);
     raw_source := HTTPGet(source_url,True);
     ... //some more instructions
except
     update_rend.Memo1.Lines.add('Error : '+ExceptionMessage);
end

What's surprising is that this code has been working for months without problem, so I suppose the site changed some code in the page.


Do you have an idea ?


Thanks in advance


Cheers


Mathias

84

(2 replies, posted in Script)

Thanks for your answer Dmitry,


I'll find another way to proceed smile


Cheers


Math

85

(4 replies, posted in General)

Hello Vasco,


I think your logic is correct, but in order to "activate" the color change, you need to put it into an event that would trigger the logic.


Did you pout your code in the OnChange event or OnClick event of the combobox ?


Math

86

(2 replies, posted in Script)

Hello Dmitry and al MVD fans,


The following instructions

GetDirectories(,)

GetFilesList(,)

as long as you provide an path and a search pattern, let you build a list of files recursively, as well as a list of directories ans subdirectories which is great.


Is there a way to limit the number of levels that the instruction will use like for example just 1 or 2 levels of recursion ?


Also, when using :

GetFilesList(path,'*.*');

you can replace the *.* by *.zip, or *.exe but only one at a time?
is the a way we could do something like :

GetFilesList(path,'*.zip;*.exe;*.jpeg');


Cheers


Mathias

87

(3 replies, posted in General)

Hello Vasco,


I usually set the desired size of my columns in the OnChange event of the Tablegrid, this way, each time new data are loaded in it, the size remain the same :

procedure vendors_TableGrid1_OnChange (Sender: string);
begin
    vendors.TableGrid1.Columns[0].Width := 120;
    vendors.TableGrid1.Columns[1].Width := 200;
    vendors.TableGrid1.Columns[2].Width := 70;
    vendors.TableGrid1.Columns[3].Width := 70;
end;

For text alignment in the columns or the headers of the columns you can do :

procedure Form1_TableGrid1_OnChange (Sender: string);
begin
     Form1.TableGrid1.Columns[0].Alignment := taRightJustify; // first column
     Form1.TableGrid1.Columns[1].Alignment := taCenter; 
     Form1.TableGrid1.Columns[2].Alignment := taLeftJustify; 

     Form1.TableGrid1.Columns[1].Header.Alignment := taCenter; //this is for the header text
end;

Hiding a column :

procedure Form1_TableGrid1_OnChange (Sender: string);
begin
    Form1.TableGrid1.Columns[2].Visible := False;
end;

And accessing the value of the hidden column :

procedure Form1_TableGrid1_OnCellClick (Sender: string; ACol, ARow: Integer);
var
    sValue: string;
begin
    sValue := Form1.TableGrid1.Cells[2,ARow];
end;

Cheers


Mathias

Hello Teco,


Not sure what

Rechnerverwaltung.RSoftware

is. If this is a Tablegrid that you want to fill with a query, you should try :


Rechnerverwaltung.RSoftware.dbSQL:= 'select software.id,software.softwarename from software left outer join softwarerechner on software.id=softwarerechner.id_software where softwarerechner.id_rechner='+inttostr(rechnerid);
Rechnerverwaltung.RSoftware.dbSQLExecute;

The first instruction loads the query and the second on executes it.


Hope this helped.


Cheers


Mathias


PS :
You can add before the dbSQLExecute command this line :

Rechnerverwaltung.RSoftware.dbListFieldsNames := 'Software ID,Sowftare Name';

This would result in setting the names you want for the Tablegrid columns you are filling instead of those coming from the query.


Also, using 'delete_col' in place of one of the column name would result in hiding the column.

I personally prefer setting visibility, column width, alignment, names etc. on a unique 'OnChange' event of the Tablegrid.

89

(2 replies, posted in General)

Hello all,


Little addition if that can help identify the problem because I found the source of the error.


On the Form I had a Tablegrid and a couple of SQL Query buttons.
Everything worked fine until I added a combobox to the form, manually filed with this code :


    folder_reading.ComboBox3.Clear;
    folder_reading.ComboBox3.Items.add('DIM files (IMxxxx.zip)');           //index0
    folder_reading.ComboBox3.Items.add('Exe files (old DAZ sku format)');   //index1
    folder_reading.ComboBox3.Items.add('Rar files');                      //index2
    folder_reading.ComboBox3.ItemIndex := 0;

With this code added, clicking on a SQL Query button triggers the error message "Index out of bound (0)".


After investigation, I got ride of the last line :

    folder_reading.ComboBox3.ItemIndex := 0;

and now the error message is gone.


Still, this is stange smile


Cheers


Math

90

(5 replies, posted in General)

Hello teco,


I don't have all your answers but :


Regarding the script size and limits : I'm well over 12.000 lines of script and it work without problems. The script.pas size is 600Ko and the script.dcu is 2,3Mo and it works.


Regarding the error message : I had the same one with v3.5b biut the situation was special. On my form there was :
- a tablegrid
- a few SQL query buttons
this worked until I hadded a combobox filled by script like this :

folder_reading.ComboBox3.Clear;
    folder_reading.ComboBox3.Items.add('DIM files (IMxxxx.zip)');           //index0
    folder_reading.ComboBox3.Items.add('Exe files (old DAZ sku format)');   //index1
    folder_reading.ComboBox3.Items.add('Rar files');    Index2
    folder_reading.ComboBox3.ItemIndex := 0;

This addition triggered the "Index out of bound (0)" when a SLQ Query button was clicked.


Getting ride of the last line

folder_reading.ComboBox3.ItemIndex := 0;

made the error disappear

Just in case you were in the same situation and this could help you.


Cheers


Math

91

(2 replies, posted in General)

Hello all,


Since a few days, while working on my long time project, I receive two kinds of errors :

  • While setting up a Tabelgrid or a SQL button, when I click OK to validate I get a "Access violation at address xxxx"

  • When running the application a click on a SQL button with a simple query triggers a "List Index out of bounds (0)"


What is surprising is that older SQL buttons (set up a long time ago) do not trigger the same error and work fine.


I'm using v3.5b, the latest version I guess.


Any idea ?


Cheers


Math

92

(4 replies, posted in General)

Hello Derek,


I had a look at you project and I have to admit that, without script, I don't see how to solve your problem.
I have the same behavior that the one you described.


Guess you'll have to wait for Dmitry.


Sorry


Cheers


Mathias

93

(5 replies, posted in General)

Hello,


Since the result is a string, before displaying the result you can try something like :

//TO WORDS
procedure Form1_Button1_OnClick (Sender: string; var Cancel: boolean);
var
    input : real;
    output : String;
begin
    input := strToFloat(Form1.Edit1.text);
    output := ToWords(input);

    Form1.Edit2.Text := ReplaceStr(output,'dollars','Pesos');
    Form1.Edit2.Text := ReplaceStr(Form1.Edit2.Text,'dollar','Pesos');
end;;

Note that I first replaced the plurial case and then the singular. If you do it reverse, you will end-up with 's' alone that would be harder to clean.


Cheers


Math

94

(1 replies, posted in General)

Hello lupo1st,


There is no embedded function to convert Hexadecimal to Integer because there is no need for it : hex are just strings.
3877 is an integer with a value and $F25 is the same value but presented in a different way.
You tried IntToStr while you should have used the other one : StrToInt smile


All you have to do is treat that hex value as a string and use the StrToInt function to convert it to integer, keeping the $ or it won(t be recognized.



In the following example, I setup and edit field to receive the hex value and a button to convert it :

procedure Form1_Button1_OnClick (Sender: string; var Cancel: boolean);
var
    hex : String;
    int : Integer;
begin
    hex := Form1.edHex.Text; //Hex value with $ sign
    int := StrToInt(hex);

    ShowMessage(IntTostr(int));
end;

Of course, I had to convert again the int to an Str to display it but after conversion. I you use your converted value right away, you don't need to re-convert it.


Hope this helps


Cheers



Math

95

(2 replies, posted in General)

Nothing to add smile


This is exactly the way to do it : to main tables and a relation table in between.


Cheers


Math

96

(7 replies, posted in FAQ)

Hello again Dmitry,


Works perfectly with beta 3.5, thanks a million times.


Subsidiary question : Is there a limit of icons you can add to a TImageList (Like after 8, you have to create a second list) ?



ADDITIONAL HELP FOR PEOPLE WHO WANT TO USE CUSTOM IMAGELIST


Until now, we could only add icons to Menus and PopupMenus with format Bitmap with transparency which were... well... ugly smile


With this new addition from Dmitry, you can now use PNG images with transparency for your Menus and PopupMenus very easily.


Here is an example on how to add a nice icon to a PopupMenu Item attached to a Tablegrid (of course, you'll have created you TImageList like shown in Dmitry's example)

procedure Form1_OnShow (Sender: string; Action: string);
var
    Pop : TPopupMenu;
    MyItem1 : TMenuItem;
begin
    Pop := TPopupMenu.Create(Form1);    //Create main PopupMenu
    Pop.Images := ImageList;            //Assign TImageList to PopupMenu

    MyItem1 := TMenuItem.Create(Pop);   //First Item of the PopupMenu
    MyItem1.Caption := 'Test pop Menu'; //Caption of the Item
    MyItem1.ImageIndex := 1;            //Image index assigned to the Item
    Pop.Items.Add(MyItem1);             //Add Item to PopupMenu

    Form1.TableGrid1.PopupMenu := Pop;  //Assign PopupMenu to Tablegrid
end;

Hope this helps


Cheers


Math

97

(7 replies, posted in FAQ)

Hey Dmitry ,


TImageList !! You did it !!  That's great !!


Unfortunately, I get an "UnknownType" error with 3.4 stable and with the 3.4 beta (found on this post http://myvisualdatabase.com/forum/viewt … p?id=3352) that seemed to be the latest beta version...


Is there a newer beta I missed somewhere ?


Cheers


Math

98

(7 replies, posted in General)

Juste une information en passant : cela fonctionne chez moi sous Windows 10 64 bits sans erreur.


Ha... et j'allais oublier.... magnifique catalogue !!


Mathias

99

(2 replies, posted in General)

Hello domebil,

If you use the MVD bouton to open a form from a button click, it is like writing :

     Form2.Shomodal;

The modal term means the new form opening has focus and you can not open another form until this one is closed.


If you want to open a form but with the possibility to open another one, had the following code manually to a OnClick event of any button :

    Form2.Show;

That way, Form2 is displayed but does block you from opening another form.


Caution though... if you open multiple form targeting the same record, you might face synchronisation problems while saving infor from a form and not having them updated on other opened forms.


Hopefully this makes sens, I am not quite awake yet smile


Math

100

(6 replies, posted in General)

Hello domebil,


Thank you for your answer, I saw that, but I was looking for the details about this release : what's new and so on smile


Cheers


Math