How to Combine fields in AdoQuery sql statement in delphi? - delphi

with AdoQuery do
begin
Close;
SQL.Clear;
SQL.Add('SELECT (name+' '+surname+' '+father) as initihal, address from user');
Open;
end;
How to add space between name surname and father ?
i want to see result in DbGrid like that
Lionel Andrés Messi

The ADO layer/backend server should be fine with returning a column value which is an expression including a number of column values and string literals.
As you are trying to construct your SQL statement in Delphi source code (rarely a good idea, ime) you need to express what you want in a way which is syntactically correct from the compiler's point of view, as well as producing the desired result from your RDMS. To do this, all of the single quotes inside SQL.Add(...) except the outer two need to be doubled-up, otherwise you will get a syntax error on compilation.
However, even once you've done that, your SQL still may not execute correctly at run-time depending on whether your naming of the columns in your result-set is digestible by your back-end server. It's best to create and test your Select statement using whatever query tool is available for your RDMS, then attempt to set it up in Delphi only after you've got it working correctly from the RDMS's pov.
Btw, you will encounter fewer problems if you get into the habit of using the QuotedStr function in constructing the column values you want - you obviously need the syntax practice so I leave you to look that up in the Online Help.
Also, if you need to constrain the result set by specifying a Where clause, be sure to do it in a way which minimizes the risk of Sql Injection (https://en.wikipedia.org/wiki/SQL_injection) which arises when the SQL includes input text from the user. The bet way to do this is to use a parameterized Where clause.

If using inline SQL you have escape the quote characters or use a function that returns spaces. You will not be able to update the result. Another option is to add a calculated field in your Delphi ADOQuery component and do the combine client side in OnCalcFields.
with AdoQuery do
begin
Close;
SQL.Clear;
SQL.Add('SELECT name+'' ''+surname+'' ''+father as initihal, address from user');
Open;
end;
If using SQL Server for a database you can use the space() function.
with AdoQuery do
begin
Close;
SQL.Clear;
SQL.Add('SELECT name+ space(1) + surname+ space(1) +father as initihal, address from user');
Open;
end;

Related

DB2 simple Select SP

i try to get an SP to run on DB2 connected with Squirrel
CREATE OR REPLACE PROCEDURE BOCA.TESTSP
(IN CASID INTEGER)
READS SQL DATA
DETERMINISTIC
LANGUAGE SQL
BEGIN
SELECT * FROM BOCA.TCASE C WHERE C.ID = CASID
END;
I get various errors based on where I put the ; (at end of statement etc)
i tried to follow this approach:
CREATE PROCEDURE [qualifier.]<procedure_name>
([IN | OUT | INOUT <argument_name> <datatype>,...])
{MODIFIES SQL DATA |
NO SQL |
CONTAINS SQL |
READS SQL DATA}
[[NOT] DETERMINISTIC]
LANGUAGE SQL
BEGIN [ATOMIC]
<procedure_body>
END
But did not succeed.
Anyone have a simple select that runs?
Stange is that an sample update I was able to create
Take some time to study the sample code that IBM supplies for SQL PL procedures, get these samples built and working in your environment. The samples are in the documentation, also they are on github, also they are in the SAMPLES directory of your Db2-server installation (for DB2 on Linux/Unix/Windows).
Your procedure has some mistakes:
missing statement separator after the SELECT statement
incorrect usage of SELECT in a routine. You either want to declare and open a cursor to return a result set to the caller or client, or you want to use SELECT...INTO to process the result of the query inside your routine.
missing valid separator at the end of the block of code (after the final END)
For SQuirrel SQL Client, before you connect to the database:
File > New Session Properties > SQL
(scroll down the list of properties until you see:
Statement Separator ;
Change the Statement Separator to #
Click OK.
Now connect to the database.
When you then type any SQL statement inside Squirrel (or a block, such as a trigger, stored-procedure, user defined function etc), you must now use the new statement separator instead of the previous default value at the end of the whole statement.
Inside of your routines , you will still need to use the semicolon to delimit statements inside the block, but remember to specify the new statement separator at the end of the block (after the final END in the stored procedure in your case).

DB2 Stored Procedure Not able to assign data to a variable

I have a simple stored procedure to calculate the sum of salaries of employees, sum of their squares and number of rows.
This is the stored procedure I have written:
I get an error in fetching the number of rows from the database and assigning it to a variable. What do I do? Using DB2 11.5
It helps to specify the exact error code when asking questions (don't write get an error, do write instead 'get error SQL0104N ...`.
Your mistake is that you have not followed the documented order for SQL statements in compound SQL blocks.
The SELECT statement can only appear after any cursor definitions, local procedures , and handlers if you have any.
So move the statement SELECT COUNT(*) INTO TOTAL_ROWS FROM EMPLOYEE; so that it appears after the DECLARE CURSOR1 ... line, the try to recompile.

Return 2 resultset from cursor based on one query (nested cursor)

I'm trying to obtain 2 different resultset from stored procedure, based on a single query. What I'm trying to do is that:
1.) return query result into OUT cursor;
2.) from this cursor results, get all longest values in each column and return that as second OUT
resultset.
I'm trying to avoid doing same thing twice with this - get data and after that get longest column values of that same data. I'm not sure If this is even possible, but If It is, can somebody show me HOW ?
This is an example of what I want to do (just for illustration):
CREATE OR REPLACE PROCEDURE MySchema.Test(RESULT OUT SYS_REFCURSOR,MAX_RESULT OUT SYS_REFCURSOR)
AS
BEGIN
OPEN RESULT FOR SELECT Name,Surname FROM MyTable;
OPEN MAX_RESULT FOR SELECT Max(length(Name)),Max(length(Surname)) FROM RESULT; --error here
END Test;
This example compiles with "ORA-00942: table or view does not exist".
I know It's a silly example, but I've been investigating and testing all sorts of things (implicit cursors, fetching cursors, nested cursors, etc.) and found nothing that would help me, specially when working with stored procedure returning multiple resultsets.
My overall goal with this is to shorten data export time for Excel. Currently I have to run same query twice - once for calculating data size to autofit Excel columns, and then for writing data into Excel.
I believe that manipulating first resultset in order to get second one would be much faster - with less DB cycles made.
I'm using Oracle 11g, Any help much appreciated.
Each row of data from a cursor can be read exactly once; once the next row (or set of rows) is read from the cursor then the previous row (or set of rows) cannot be returned to and the cursor cannot be re-used. So what you are asking is impossible as if you read the cursor to find the maximum values (ignoring that you can't use a cursor as a source in a SELECT statement but, instead, you could read it using a PL/SQL loop) then the cursor's rows would have been "used up" and the cursor closed so it could not be read from when it is returned from the procedure.
You would need to use two separate queries:
CREATE PROCEDURE MySchema.Test(
RESULT OUT SYS_REFCURSOR,
MAX_RESULT OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN RESULT FOR
SELECT Name,
Surname
FROM MyTable;
OPEN MAX_RESULT FOR
SELECT MAX(LENGTH(Name)) AS max_name_length,
MAX(LENGTH(Surname)) AS max_surname_length
FROM MyTable;
END Test;
/
Just for theoretical purposes, it is possible to only read from the table once if you bulk collect the data into a collection then select from a table-collection expression (however, it is going to be more complicated to code/maintain and is going to require that the rows from the table are stored in memory [which your DBA might not appreciate if the table is large] and may not be more performant than compared to just querying the table twice as you'll end up with three SELECT statements instead of two).
Something like:
CREATE TYPE test_obj IS OBJECT(
name VARCHAR2(50),
surname VARCHAR2(50)
);
CREATE TYPE test_obj_table IS TABLE OF test_obj;
CREATE PROCEDURE MySchema.Test(
RESULT OUT SYS_REFCURSOR,
MAX_RESULT OUT SYS_REFCURSOR
)
AS
t_names test_obj_table;
BEGIN
SELECT Name,
Surname
BULK COLLECT INTO t_names
FROM MyTable;
OPEN RESULT FOR
SELECT * FROM TABLE( t_names );
OPEN MAX_RESULT FOR
SELECT MAX(LENGTH(Name)) AS max_name_length,
MAX(LENGTH(Surname)) AS max_surname_length
FROM TABLE( t_names );
END Test;
/

Can't replace an existing stored procedure that creates a table

I have a stored procedure that drops/creates a table. The first time the procedure is created it succeeds and the procedure runs fine. However, if I try and replace the procedure it gives the error:
The name of the object to be created is identical to the existing name "TABLENAME" of type "TABLE".
It does this even though the procedure has a drop statement for "TABLENAME" immediately before the table creation statement. A stripped down example:
create or replace procedure example
LANGUAGE SQL
BEGIN
DECLARE CONTINUE HANDLER FOR SQLSTATE '42704'
BEGIN END;
drop table TABLENAME;
create table TABLENAME(AN INTEGER);
END;
Is there any way to either get DB2 to recognize the drop statement or to ignore the error?
I'm on DB2 v10.1.0.3.
To run a series of commands as a stand-alone block of SQL, make sure that you use a different SQL delimiter instead of the semi-colon. The semi-colon is used as a statement terminator in SQL PL so you will need to use a different character to delimit multiple commands within your scripts. Change the semi-colon (";") at the end of procedure to something else like "#"
See SQL Procedural Language (SQL PL)

Get name of table that TField is from

I'm using a TDataSet where the CommandText property is set to an SQL query. I have also made the following function which creates part of an SQL query based on the fields of TDataSet. It is however incomplete. As you can see I still need to get the name of the table that a TField is from. How do I achieve this?
function GetDataSetFieldsMSSQL(Dataset: TDataSet): String;
var
I, L: Integer;
TableName: String;
begin
Result := '';
L := Dataset.Fields.Count;
if (L > 0) then
begin
TableName := ... // Name of the table for the Dataset.Fields[0] field.
Result := '[' + TableName + '].[' + Dataset.Fields[0].FieldName + ']';
I := 1;
while (I < L) do
begin
TableName := ... // Name of the table for the Dataset.Fields[I] field.
Result := Result + ',[' + TableName + '].[' + Dataset.Fields[I].FieldName + ']';
Inc(I);
end;
end;
end;
You can use the Delphi Function GetTableNameFromQuery(SQL : String):String; from the DBCommon unit. Just Add The DBCommon on the uses. =)
Maybe there is no solution at all for a simple TDataSet?
I believe not. Because an TDataset can source its' data not only from RDBMS' tables.
It can be:
an RSS feed
An XML file. Example: TCliendataset is an TDataset descendant that can read XML from its'
own format or using an XMLTransformProvider.
It can be an SQL for reading an Excel spreadsheet or a text file if you have an ODBC driver for
that and configured the datasource.
Sky (and the imagination of Delphi's programmers around the world) is the limit for what a field can represent in an TDataset.
You have some alternatives, since you are using an ADODataset:
Parsing the commandText of ADOCommand
Using the BASETABLENAME property of ADORecordSet (as in kobik's comment)
Guessing by convention ( Abelisto's answer )
As I know there is no any way to get the name of the table from the SQL query component.
However you can give aliases for fields, for example: "select foo_field as foo_dot_foo_field from foo" and then replace them to the correct syntax: "Result := '[' + StringReplace(DataSet.Fields[0].FieldName, 'dot', '].[', [rfReplaceAll]) + ']'"
What you are trying to do is impossible if you have no knowledge or control over the SQL used in the query.
The query could contain calculated/computed fields or could be returning fields from a view etc. Furthermore the database might have several tables that contain the same field names.
If possible you can query the SQL server view INFORMATION_SCHEMA.COLUMNS and that way try to figure out what table a fieldname is from. However if the field names are not unique this might also prove impossible.

Resources