Delphi XE: TSQLQuery raises "Input parameter mismatch" - sql

I've created a stored procedure (SP_TEST) in Firebird 2.5 that returns a selection and uses 3 input parameters.
This SP_TEST works fine in IBExpress, when I enter e.g. the SQL command: select * from SP_TEST(1,2,3) there's a correct result.
However, when I use the dbExpress components in Delphi XE to do the same selection, the message "Input parameter mismatch" is raised.
I'm using the TSQLQuery component, with the CommandText property set to "select * from SP_TEST(1,2,3)".
When I define the same query in the CommandText property as I've defined in SP_TEST, I have a nice result.
But including the stored procedure name in the select statement (with the right number of parameter) raises this error message.
Can anyone please tell me what I'm doing wrong?
UPDATE - moved from pseudo-answer and formatting added: https://stackoverflow.com/editing-help
SET TERM ^ ;
ALTER PROCEDURE SP_TEST (
NJAAR Integer,
NMAAND Integer,
CREKNR Varchar(6) )
RETURNS (
TOTAAL Numeric(15,2),
CODE Varchar(4),
OMSCHR Varchar(40),
RICHTING Varchar(3),
PROG Numeric(18,2),
TRANS Numeric(18,2) )
AS
BEGIN
FOR
SELECT a.CODE, a.OMSCHR, a.RICHTING,
SUM(iif(richting='AF',-1,1) * COALESCE(p.bedrag,0)) as prog,
SUM(iif(richting='AF',-1,1) * COALESCE(t.bedrag,0)) as trans,
0 as totaal
FROM POSTEN a
left JOIN prognose p on p.POST = a.CODE and p.JAAR = :nJAAR and p.MAAND = :nMAAND
left JOIN TRANSACT t on t.POST = a.CODE and EXTRACT(YEAR FROM t.datum) = :nJAAR and EXTRACT(MONTH FROM t.datum) = :nMAAND
WHERE REKTOEPAS containing :cREKNR
GROUP by a.CODE, a.OMSCHR, a.RICHTING
INTO :CODE,
:OMSCHR,
:RICHTING,
:PROG,
:TRANS,
:TOTAAL
DO
BEGIN
totaal = iif(abs(prog) > abs(trans),prog,trans);
SUSPEND;
END
END^
SET TERM ; ^
Entering the statement in IBExpert:
SELECT * FROM SP_TEST(2014,1,'0001')
returns a result set of several rows.
When I pass the same query to TSQLQuery.CommandText (or to the SQL property, I also tried this), the message "Input parameter mismatch" is raised.
I tried TSQLStoredProc, but then there's a message "Cursor not returned from Query" when I use the Open method.
In fact, my stored procedure is kind of a view, and I like the result in my dbExpress components (TSQLQuery or TSQLStoredProc).
As said, when I put the complete SQL code between "SELECT..." and the "GROUP BY" in the TSQLQuery.SQL propery, I get the resulting rows. Using the stored procedure fails until now.

Your third parameter is a VARCHAR, but you try to use select * from SP_TEST(1,2,3) and here the third argument is an INTEGER. This is also the only difference with the procedure call that does work.
So instead use:
select * from SP_TEST(1,2,'3')
(note the quotes around the 3)

Related

Stored proc temporary table with parameters

Hello in a stored procedure, i create a temp-table filled with a select wich execute a function to return date recurrences.
The creation of my temp table looks like this :
BEGIN
insert into #tmp_recu
SELECT * FROM dbo.CrontabSchedule('0 0 * * *', '2017-2-1', '2017-2-28')
END
After creating this temp-table, i execute a query using this temp table like this :
Select * from mission
Cross Join #temp_recu
The problem is i'd like to remplace the '0 0 * * *' in my temp-table creation by a field from mission table (field named recurrence), so how could i do that?
Thanks !
EDIT
Actually, in my query, i'd like to call the function 'CrontabSchedule' and put in parameter a field from 'mission' table like this :
select * from mission m
cross join select * from dbo.CronTabSchedule(mission.reccurence,'2017-1-1','2017-1-31')
It works when i called the function like this
select * from dbo.CronTabSchedule('0 0 * * *','2017-1-1','2017-1-31')
But when i replace '0 0 * * *' by 'Mission.recurrence' (which contains the recurrence pattern of each mission), i have an error :
The multi-part identifier "Mission.recurrence" could not be bound.
CrontabSchedule code :
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
ALTER FUNCTION [dbo].[CrontabSchedule](#Expression [nvarchar](100), #Start[datetime], #End [datetime])
RETURNS TABLE (
[Occurrence] [datetime] NULL
) WITH EXECUTE AS CALLER
AS
EXTERNAL NAME [NCrontabSQL].[NContab.SQL.SqlCrontab].[GetOccurrences]
The function return a table with one column named 'Occurence' and contains à list of dates.
Pretty vague question here but I am assuming that CronTabSchedule must be a table valued function (hopefully an inline version but that is another topic). If I am correct you could use CROSS APPLY for this quite easily.
select *
from mission m
cross apply dbo.CronTabSchedule(m.reccurence,'2017-1-1','2017-1-31') cts

MonetDB Prepare Statement in Function

I'm trying to create a function that takes the parameters for the column, the table, the limit, and offset. Basically, I want to be able to get a specified number of rows data from a specified table from a specified column.
However, I'm unable to get the following code to work - I get several errors such as:
syntax error, unexpected SELECT, expecting ':' in: "create function get_banana(lim int, off int, tbl varchar(32), col varchar(32)) r"
syntax error, unexpected RETURN in: "return"
syntax error, unexpected END in: "end"
These errors seem kind of meaningless.
My code is as follows:
CREATE FUNCTION GET_BANANA(lim int, off int, tbl varchar(32), col varchar(32))
RETURNS TABLE (clm int)
BEGIN
PREPARE SELECT col FROM tbl LIMIT ? OFFSET ?;
RETURN EXEC (lim, off);
END;
I'd appreciate any help :) Thanks!
I see at least two issues
EXEC needs the identifier that is returned by PREPARE, e.g.:
sql>prepare select * from tables;
execute prepared statement using: EXEC 2(...)
sql>exec 2();
The function parameters tbl and col are string values. You cannot use them as table/column identifiers.
Having said that, I am not even sure if PREPARE can be used inside a function.
No, PREPARE is a top-level statement modifier.

How to parse a VARCHAR passed to a stored procedure in SQL Server?

I have two tables tbl_Products and tbl_Brands, both are joined on BrandId.
I have a stored procedure which should return all the products belong to the brand ids passed to it as parameter.
My code is as follows.
create proc Sp_ReturnPrdoucts
#BrandIds varchar(500) = '6,7,8'
AS
BEGIN
SELECT *
FROM tbl_Products as p
JOIN tbl_Brands b ON p.ProductBrandId = b.BrandId
WHERE b.BrandId IN (#BrandIds)
END
But this is giving error as BrandId is INT and #BrandIds is VARCHAR
When I hard code it this way as follows it works fine and returns the desired data from db ..
create proc Sp_ReturnPrdoucts
#BrandIds varchar(500) = '6,7,8'
AS
BEGIN
SELECT *
FROM tbl_Products AS p
JOIN tbl_Brands b ON p.ProductBrandId = b.BrandId
WHERE b.BrandId IN (6,7,8)
END
Any help :)
If possible, don't use varchar for this kind of things, use a table valued parameter instead.
To use a tabled value parameter you should first declare a user defined table type:
CREATE TYPE IntList As Table
(
IntValue int
)
Then change your stored procedure to accept this variable instead of the nvarchar:
create proc Sp_ReturnPrdoucts
#BrandIds dbo.IntList readonly -- Note: readonly is a must!
AS
BEGIN
SELECT *
FROM tbl_Products as p
join tbl_Brands b on p.ProductBrandId=b.BrandId
join #BrandIds ON(b.BrandId = IntValue)
END
The problem is that the IN() operator expects a list of variables separated by commas, while you provide a single variable that it's value is a comma separated string.
If you can't use a table valued parameter, you can use a string spliting function in sql to convert the value of the varchar to a table of ints. there are many splitters out there, I would recommend reading this article before picking one.
Another alternative is to use 'indirection' (as I've always called it)
You can then do..
create proc Sp_ReturnPrdoucts
#BrandIds varchar(500) = '6,7,8'
AS
BEGIN
if (isnumeric(replace(#BrandIds,',',''))=1)
begin
exec('SELECT * FROM tbl_Products as p join tbl_Brands b on p.ProductBrandId=b.BrandId WHERE b.BrandId IN ('+#BrandIds+')')
end
END
This way the select statement is built as a string, then executed.
I've now added validation to ensure that the string being passed in is purely numeric (after removing all the commas)

DB2 9.7 SQL syntax, what am I doing wrong?

For one reason or other which are out of my control I am attempting to simply pull data over the past 12 months. However, essentially down to the size of data, I have to query each day into a temp table and go from there. Now I'm a newbie to scripting in DB2, but not SQL in general, so I've tried the code below (the logic seems fine to me).
Initially I'm was just interested in how many records will be generated, but ideally I'd want to run the second SELECT code. I've been using Data Studio, but I believe to export the data I would need to run this via CLP. Now my issues are that I'm missing something within syntax that I can't figure out and it's doing my head in. It's most likely something very basic or I'm just doing it totally wrong.
If I try the SELECT COUNT(*) code I'm getting these errors: -
Multiple markers at this line
- DB2 for Linux, UNIX, and Windows: "" was expected after "FROM".
- DB2 for Linux, UNIX, and Windows: "." is invalid.
If I try the other SELECT code I'm getting these errors: -
DB2 for Linux, UNIX, and Windows: "" was expected instead of "SELECT MARKET_ID,
SUPER_REGION,
REGION,
MARKET,
POSA,
DEST_ID,
DEST_NAME,
DEST_TYPE,
STAT...
DB2 for Linux, UNIX, and Windows: "," was expected after "FROM".
DB2 for Linux, UNIX, and Windows: "," was expected after "GROUP"
I just don't get it. Can someone please help? The SESSION.l12_Dest table also doesn't seem to be available afterwards for me to try looking at the table manually.
Code: -
--<ScriptOptions statementTerminator="#"/>
CREATE OR REPLACE PROCEDURE HWW.DM_CHECKLIST()
LANGUAGE SQL
BEGIN
DECLARE GLOBAL TEMPORARY TABLE SESSION.L12_DEST
(
ACTUAL_DATE DATE,
MARKET_ID INTEGER,
SUPER_REGION VARCHAR (100),
REGION VARCHAR (100),
MARKET VARCHAR (100),
POSA VARCHAR (100),
DEST_ID INTEGER,
DEST_NAME VARCHAR (100),
DEST_TYPE VARCHAR (30),
STATUS_CODE SMALLINT,
VISITORS INTEGER
)
ON COMMIT PRESERVE ROWS NOT LOGGED;
COMMIT;
FOR V_ROW AS
SELECT ACTUAL_DATE
FROM DM.DATE_DIM
WHERE ACTUAL_DATE
BETWEEN (CURRENT_DATE - 12 MONTHS) - DAY((CURRENT_DATE - 12 MONTHS)) DAYS + 1 DAYS
AND LAST_DAY((CURRENT_DATE - 1 MONTHS))
DO
INSERT INTO SESSION.L12_DEST
SELECT B.ACTUAL_DATE,
Z.HCOM_SRCH_DEST_PROPERTY_MKT_ID,
Z.HCOM_SRCH_DEST_PROPERTY_MKT_SUPER_REGN_NAME,
Z.HCOM_SRCH_DEST_PROPERTY_MKT_REGN_NAME,
Z.HCOM_SRCH_DEST_PROPERTY_MKT_NAME,
S.SITE_CNTRY_NAME,
Z.HCOM_SRCH_DEST_ID,
Z.HCOM_SRCH_DEST_NAME,
Z.HCOM_SRCH_DEST_TYP_NAME,
LZ.STATUS_CODE,
COUNT(DISTINCT(F.VISITOR_KEY))AS VISITORS
FROM DM.LODG_DEMAND_FACT F
INNER JOIN DM.V_HCOM_SRCH_DEST_DIM Z
ON F.HCOM_SRCH_DEST_KEY = Z.HCOM_SRCH_DEST_KEY
INNER JOIN DM.DATE_DIM B
ON F.LOCAL_DEMAND_DATE_KEY = B.DATE_KEY
INNER JOIN DM.SITE_DIM S
ON S.SITE_KEY = F.SITE_KEY
LEFT JOIN LZ.LZ_HCM_DESTINATION LZ
ON Z.HCOM_SRCH_DEST_ID = LZ.DESTINATION_INT_ID
WHERE F.BRAND_KEY = 101
AND B.ACTUAL_DATE = V_ROW.ACTUAL_DATE
GROUP BY B.ACTUAL_DATE,
Z.HCOM_SRCH_DEST_PROPERTY_MKT_ID,
Z.HCOM_SRCH_DEST_PROPERTY_MKT_SUPER_REGN_NAME,
Z.HCOM_SRCH_DEST_PROPERTY_MKT_REGN_NAME,
Z.HCOM_SRCH_DEST_PROPERTY_MKT_NAME,
S.SITE_CNTRY_NAME,
Z.HCOM_SRCH_DEST_ID,
Z.HCOM_SRCH_DEST_NAME,
Z.HCOM_SRCH_DEST_TYP_NAME,
LZ.STATUS_CODE;
END FOR;
--SELECT COUNT(*) FROM SESSION.L12_DEST;
--EXPORT TO C:\TEMP\MARKETS.TXT OF DEL
SELECT MARKET_ID,
SUPER_REGION,
REGION,
MARKET,
POSA,
DEST_ID,
DEST_NAME,
DEST_TYPE,
STATUS_CODE,
SUM(VISITORS)
FROM SESSION.L12_DEST
GROUP BY MARKET_ID,
SUPER_REGION,
REGION,
MARKET,
POSA,
DEST_ID,
DEST_NAME,
DEST_TYPE,
STATUS_CODE;
END #
I don't think you can do a bare select statement in a stored proc (at least in DB2).
When I try this I get the same results: the most unhelpful error message ever. (thanks IBM)
But, if I put some valid statement after the END FOR; there isn't a problem.
If you want a stored proc to do a select and show you the answer do something like this:
CREATE OR REPLACE PROCEDURE DM_CHECKLIST()
LANGUAGE SQL
DYNAMIC RESULT SETS 1
BEGIN
DECLARE RS CURSOR FOR SELECT COUNT(*) FROM sysibm.sysdummy1;
OPEN RS;
END#
The interesting thing is the DYNAMIC RESULT SETS 1 business. That tells the executor that we will have a result set returned and to show it in the command line interface (cli).
You can have as many result sets as you like. You will see the results on the cli, or you can get them pragmatically.
I did try the EXPORT command and it didn't seem to work.
EXPORT TO "C:\TEMP\MARKETS.TXT" OF DEL SELECT COUNT(*) FROM sysibm.sysdummy1;
It looks like you aren't allowed to use EXPORT in a stored proc, as it is a DB2 command and not a SQL statement. I wouldn't be surprised if there is some way to do it, but not this way.
To use the EXPORT utility in a stored procedure, you have to wrap it in the ADMIN_CMD procedure:
create procedure dm_checklist()
language sql
begin
declare global temporary table results (...)
on commit preserve rows;
-- Steps to build / populate your temporary table
call sysproc.admin_cmd('export to C:\file.del of del select * from session.results');
end

SQL syntax as parameters for a MySQL Routine?

I have the following MySQL routine:
DELIMITER $$
CREATE DEFINER=`root`#`%` PROCEDURE `getGroupOrders`(grp INT,
ord CHAR(20),
srt CHAR(4),
page INT,
count INT)
BEGIN
SELECT *
FROM `dbre`.`order_info`
WHERE username IN (SELECT `dbre`.`users`.`username`
FROM `dbre`.`users`
WHERE `dbre`.`users`.`id_group` = grp)
ORDER BY ord srt LIMIT page,count;
END
As you can see, I want to pass the ordering column and sorting as a parameters, however I get a syntax error is there a way to do this or do I have to make similar routines for each type of ordering?
I don't think this is possible in the way you try it.
You cannot use a variable to define the ORDER BY column an direction.
The only workaround I can think of is to create a prepared statement from a dynamically created string (where you can use the variables to specify the order by details) and then execute that prepared statement.
Here is an example of such a dynamic statement:
http://forums.mysql.com/read.php?98,393613,393642#msg-393642