Tweaking a TDbGrid - delphi

I am taking my first stumbling steps into DB aware controls (any good tutorials?).
I have a MySql table with 6 columns and have managed to load it into a TDbGrid.
One of the columns however is an index into another table. It is a bar code and, rather than display that, I would like to display the product name associated with it.
How do I do that?
(and can I hide the "gutter" (?) down the left whcih shows the current row?)
Thanks

You should always perform a join from the SQL side, it's much easier then doing it programaticaly
Such as:
SELECT mytable.id, mytable.column1, another_table.barcode
FROM mytable
JOIN another_table ON another_table.id = mytable.barcode_id
To remove gutter you need to uncheck the DBGrid property dgIndicator in Options.
As for "DB-Aware controls" you should try delphi help.

Instead of a table, make use of a query. Then, use a join to select the product name with it, like this:
SELECT
t.*,
p.name
FROM
YourTable t
INNER JOIN Product p on p.barcode = t.barcode
I use t.*, because I don't know the exact columns. In practise, I would not use select *, but specify specific columns instead. If you are going to use * anyway, you can hide speicfic columns by setting the Visible property of the TField object in the dataset/query to False.
I don't know which components you are using to connect to the table, but most of them do have a query-counterpart that allows you to insert SQL instead of a table name.
The gutter can be hidden by going to the property Options in the object inspector, expand it, and set dgIndicator to False.

Just for the record: with ISAM databases like Paradox and DBF typical solution would be so-called master-detail tables relations and it still might work for SQL. Though it would be very inefficient and slow. You'd definitely read som books about SQL.

Use a TQuery component instead of a TTable and set SQL property using the suggested select statements above. If you just add the columns you want to display in your sql statement, you get the result as expected. As for "gutter" you would have to hack the grid in some way at runtime.

Related

Create DBGrid columns at runtime with diffrent dataset (Table)

I want to create only certain columns on my "dbgrid" at run-time, and set them to
other table field(s) or same field . How do you do that :
illustration:
I have 3 Tables :
Student(IdStudent, NameStudent ...) ,
Module(idModul,NameModule...),
Notes(idNote,idStudent,idModul,Note).
I Want to insert All Notes in one Dbgrid and names of columns of DBgrid are names of Module Table. I have No idea?
Thanks.
You cannot do this with a dbgrid; dbgrids have only one datasource and a datasource has only one dataset. If you are using an SQL compliant database you should look into a join and/or crosstab to return a single dataset. (I think this is what MartynA is talking about) Or create a clientdataset at run-time and build it with the columns/data you want if you want data-aware. I would look into using a stringgrid, listview or treeview and build the whole thing by hand.

In Firebird can you use a cursor with EXECUTE STATEMENT?

I would like to pass, to a stored procedure, a table and field name, and then do a FOR SELECT on the table and, for some records, change the field value. I just learned about cursors which is a very convenient way to make changes in a FOR SELECT loop. But can I use cursors with EXECUTE STATEMENT?
I want this stored procedure to work for a variety of tables with a similar structure so I want it to be generic hence passing in the table name and field name.
I'm pretty sure the answer is "No." so how could I do this?

how to change the order of columns

I got the data by 'MODEL.all' command in rails console
I want to put the column 'cgi_name' in the 3rd position when I run MODEL.all in the rails console
I use the postgres for my DB
How to get it ?
To answer your question directly, you'll have to move the columns at DB level
Currently, I only know MYSQL to support this functionality:
ALTER TABLE Employees CHANGE COLUMN empName empName VARCHAR(50) AFTER department;
Postgres, to my knowledge, does not support this functionality:
Many people new to postgresql often ask if it has support for altering
column positions within a table. Currently it does not; if you want to
change column positions, you must either recreate the table, or add
new columns and move data
In the view, you'll have to either manually display the columns, or create a helper method to cycle through them in an order of your choosing
Simple answer is YOU CANNOT
There is no way to re-order the column names to be displayed when you select using Model.all.
Otherwise, you can re-order this by selecting each column in the order you want.
Model.select("column1, column2, cgi_name, column4 etc..")
Hope it helps :)

Delphi - TUpdateObject versus OnUpdateRecord for a join SQL statement

I have a pFibdataset(which is working similar to BDEDataset) in which I need to make the following join selection
select table.Name as name,
table1.Name as name_1,
table2.Name as name_2
from table
left join table table_1 on table.id=table_1.id
left join table table_2 on table.id=table_2.id
Fields name, name_1 and name_2 are linked to some data-aware edits. Now, I want after I'm modifying(update,delete,insert operations) the name,name_1 and name_2 fields to be updated in the tables. Based on the wiki Using_Multiple_Update_Objects_Index I can use UpdateObjects, or OnUpdateRecord event.
The problem is that I don't understand how this need to be implemented. I have the join select on the query, how I need to define and work with name_1 and name_2 fields. Can someone provide me an example for this?
I know how to use subqueries in order to accomplish this. I need to see how can I can make it by using UpdateObjects or OnUpdateRecord.
TpFibUpdateObject works like a trigger on client side. To make it work, set the following properties:
DataSet - dataset (master) to monitor
KindUpdate - Insert/Update/Delete - action to monitor
SQL - command to execute when action is fired, params are taken from DataSet
ExecuteOrder - AfterDefault/BeforeDefault - probably you need after / master
BUT, instead using a lot of UpdateObject components and such tangled approach, I recommend two alternative (read better) ways:
Updatable view. It will work like a "virtual table". Create a view that joins these theee tables and write Before Insert/Update/Delete triggers. In Delphi use it as a regular table: select from view / insert into view / update view and delete from view. Anyway I suppose you need in many places these tables linked toghether.
Use EXECUTE BLOCK statements in your TpFIBDataSet SQLs. Insert / Update / Delete in a batch all tables.
Solution : OnUpdateRecord it must be created an TUpdateObject for each field from the joined table.
UpdateObjectvariable.DataSet := Dataset;
fill the SQL text
Apply.
After all update objects are set, UpdateAction := uaApplied; must be called.

Deleting rows in joined tables using ADO

Now I have seen this question in another forum but it didn't had an acceptable answer.
Suppose I have two tables, the Groups table and the Elements table. The tables have no defined relationships. The Elements table has an IdGroup field that refers to the IdGroup (PK) field of the Groups table.
I use the following query through an ADO recordset to populate the tables values to a datagrid:
SELECT Elements.*, Groups.GroupName
FROM Elements
INNER JOIN Groups ON Elements.IdGroup = Groups.IdGroup
From that grid I want to press Delete in order to delete an Element. Here is my problem. When I used DAO, the DAO Delete() function deleted only the record in the Elements group. This was the expected behavior.
When I changed to ADO, the Delete() function deleted records in both tables, the element record and the group to which the element belonged!
Is there any way to reproduce the DAO behavior in ADO without having to define relationships into the tables?
Note: I know there are alternatives (executing DELETE querys could do the job). Just show me a way to do this in ADO, or say it cannot be done.
Rewrite you query to:
replace the INNER JOIN with a WHERE clause consisting of an EXISTS;
use a subquery in the SELECT clause to return the value of Groups.GroupName.
Example:
SELECT Elements.*,
(
SELECT Groups.GroupName
FROM Groups
WHERE Elements.IdGroup = Groups.IdGroup
)
FROM Elements
WHERE EXISTS (
SELECT *
FROM Groups
WHERE Elements.IdGroup = Groups.IdGroup
);
I've tested this using SQL Server 2008 with a ADO recordset set as the DataSource property of a Microsoft OLEDB Datagrid Control (MSDATGRD.OCX) then deleting the row via the gird (I assume you are doing something similar) and the row is indeed deleted from table Elements only (i.e. the row in Groups remains undeleted).
Note the revised query may have a negative impact on performance when fetching rows.

Resources