How to use a temporary table with dynamic sql? - stored-procedures

Im want to use a temporary table with dynamic sql but i have an error saying that the column Column, parameter, or variable #3: Cannot find data type MyTable. Must declare the table variable "#CountriesFound".
Here's my code
ALTER PROCEDURE sqlDynamic #countryId int
AS
CREATE TYPE MyTable AS TABLE ([countries] varchar(50));
DECLARE #statement NVARCHAR(MAX)
DECLARE #CountriesFound AS MyTable
INSERT INTO #CountriesFound(countries)
select Name
FROM CountriesFound
SET #statement =
'SELECT name, CASE WHEN (c.name IN (SELECT countries FROM #CountriesFound)) THEN 1
ELSE 0
END as countryFound FROM Country c WHERE c.countryId = #countryId'
EXECUTE sp_executesql #statement,
N'#countryId int, #CountriesFound MyTable READONLY',
#countryId = #countryId,
#CountriesFound=#CountriesFound;
Any idea how to fix it ?

The error you are getting has nothing to do with dynamic sql. You cannot create a stored procedure that uses a User-Defined DataType (MyTable in your example) in the same procedure that is going to create the TYPE. The TYPE has to already be created before the procedure will even let the code compile.
Consider this simplified code:
CREATE PROCEDURE TypeTest
AS
CREATE TYPE MyTable AS TABLE ([Id] int);
DECLARE #mt AS MyTable;
Just executing this will give the error:
Msg 2715, Level 16, State 3, Procedure TypeTest, Line 1 Column,
parameter, or variable #1: Cannot find data type MyTable. Parameter or
variable '#mt' has an invalid data type.
You need to CREATE the TYPE outside of the procedure code before you try to create the procedure. It doesn't make sense to CREATE a TYPE inside a procedure code, since TYPE objects are permanent on the server until they are dropped anyway, and procedures are usually created to be run multiple times.
It would be nice if the SQL Server gave an error message more to this effect, but SQL Server isn't famous for having the most helpful error messages.

Related

MULE 4 : STORED PROCEDURE : Executing mule flow to run stored procedure returns "The index 1 is out of range"

I am trying to execute a stored procedure in using MULE 4.
It expects two inputs, one is a table value parameter and another is an integer.
For the table value parameter, i am using SQLServerDataTable and specifying the tvpName using the public method setTvpName. After that I add the column metadata and add rows with the provided Arraylist of values.
In the DB:Stored Procedure component I use the syntax
CALL [database_name].[stored_procedure_name(:argument1,:argument 2)]
where argument 1 is the TVP and argument 2 is the integer.
But I get the error :
Message : The index 1 is out of range.
Error type : DB:QUERY_EXECUTION
Any ideas on how to better debug the issue or solve it is appreciated.

SAP HANA Stored Procedure optional output parameter with text type

Let's imagine that I have created the stored procedure in SAP HANA database and would like to have optional out parameter with text type, like error details. As I have read to achieve this I should use some default value thus I have done like this:
PROCEDURE "myProcedure"
(
IN inSomeParameter BIGINT,
OUT outResult INTEGER, -- output, result of the operation
OUT outErrorDetail NVARCHAR(32) default ''
)
Unfortunately build failed with the following error:
OUT and IN OUT parameters may not have default expressions
So, I decided to try with null, but it failed the same way. Later I changed the type to integer just to try and it failed exactly same way again.
In the same time this works:
PROCEDURE "myProcedure"
(
IN inSomeParameter BIGINT,
OUT outResult INTEGER, -- output, result of the operation
OUT outErrorDetail TABLE(errorDetails NVARCHAR(32)) default empty
)
but it feels like a huge overkill - to make a table to return only one text value.
Do you have any suggestion how to add optional output parameter?
SQL Script in its current state doesn’t allow for optional OUT parameters.
Why don’t you just set the OUT parameter default value in the procedure body right before the code?
This adds boilerplate code, but you could also use it to convey explicit success messages.

jooq generates not compiled code from Postgres procedures

Now I am trying to use JOOQ in new version of program that communicate with 2 DBs simultaneously. But problem is coming from Postgres procedures which I cant deactivate cause of Routine generation cannot be deactivated, even if I don't need them in my program.
Problem 1
Jooq understand some procedures like a tables. I am not pro with SQL so I don't know why this happens, maybe cause of procedure return type? Code for generate one of procedures that have this "bug":
CREATE OR REPLACE FUNCTION dblink_get_notify(IN conname text, OUT notify_name text, OUT be_pid integer, OUT extra text)
RETURNS SETOF record AS
'$libdir/dblink', 'dblink_get_notify'
LANGUAGE c VOLATILE STRICT
COST 1
ROWS 1000;
ALTER FUNCTION dblink_get_notify(text)
OWNER TO postgres;
Maybe cause of problem is fact that there is another procedure with the same name, but without IN parameter:
CREATE OR REPLACE FUNCTION dblink_get_notify(OUT notify_name text, OUT be_pid integer, OUT extra text)
RETURNS SETOF record AS
'$libdir/dblink', 'dblink_get_notify'
LANGUAGE c VOLATILE STRICT
COST 1
ROWS 1000;
ALTER FUNCTION dblink_get_notify()
OWNER TO postgres;
Problem 2
Some generated classes from procedures have compile errors (procedure above have this bug too )
I will give you another example:
CREATE OR REPLACE FUNCTION bt_page_stats(IN relname text, IN blkno integer, OUT blkno integer, OUT type "char", OUT live_items integer,
OUT dead_items integer, OUT avg_item_size integer, OUT page_size integer, OUT free_size integer, OUT btpo_prev integer,
OUT btpo_next integer, OUT btpo integer, OUT btpo_flags integer)
RETURNS record AS '$libdir/pageinspect', 'bt_page_stats'
LANGUAGE c VOLATILE STRICT
COST 1;
ALTER FUNCTION bt_page_stats(text, integer)
OWNER TO postgres;
JOOQ understands this procedure as a routine. But generated code have identical twice Parameter<Integer> BLKNO field. And what I found strange is constructor of that class:
/**
* Create a new routine call instance
*/
public BtPageStats() {
super("bt_page_stats", Public.PUBLIC);
addInParameter(RELNAME);
addInOutParameter(BLKNO);
addInOutParameter(BLKNO);
addOutParameter(TYPE);
addOutParameter(LIVE_ITEMS);
addOutParameter(DEAD_ITEMS);
addOutParameter(AVG_ITEM_SIZE);
addOutParameter(PAGE_SIZE);
addOutParameter(FREE_SIZE);
addOutParameter(BTPO_PREV);
addOutParameter(BTPO_NEXT);
addOutParameter(BTPO);
addOutParameter(BTPO_FLAGS);
}
Look at double addOutParameter(BLKNO)!
Wooh, think thats all. Hope you can help me with that problems :)
You ran into bug #4055. As of jOOQ 3.6, overloaded table-valued functions generate code that doesn't compile.
But problem is coming from Postgres procedures which I cant deactivate cause of Routine generation cannot be deactivated, even if I don't need them in my program.
That's true, but you can exclude them from the code generator explicitly by name, e.g. by specifying:
<excludes>dblink_get_notify|bt_page_stats</excludes>
More info about the code generator configuration can be found here

Script always throws an error if CREATE/ALTER is not first statement

I am getting an error when I try to execute the script that is given at end of this post. My requirement is to check for procedure's existence, then drop it if it exists and finally create the procedure.
How would I do this using a single script file?
Procedure Proc_GenerateTestData. 'CREATE/ALTER PROCEDURE' must be the first statement in a query batch. SQL2.sql 12 1
The SQL script that always throws above error is as below.
IF OBJECT_ID('dbo.Proc_GenerateTestData', 'p') IS NOT NULL
BEGIN
DROP PROCEDURE dbo.Proc_GenerateTestData
END
CREATE PROCEDURE dbo.Proc_GenerateTestData #numberOfRecords INT = 100
AS
--drop table #temp1
DECLARE #currentTime AS TIME = CAST(GETDATE() AS TIME);
DECLARE #currentWorkShiftDate AS DATETIME = CAST(CAST(GETDATE() AS DATE) AS DATETIME);
DECLARE #startTime TIME,
#lastShiftStartTime TIME;
DECLARE #tenantId AS UNIQUEIDENTIFIER = (SELECT TOP (1)
Tenants.Id
FROM Tenants
ORDER BY Tenants.Id ASC);
DECLARE #workshiftId INT,
#lastShiftStartDate DATETIME;
--more statements for this procedure follow
As the error clearly says - the CREATE PROCEDURE must be the first statement in a query batch.
This is not the case here, since you have the check for the DROP before hand.
You need to change your script so that the CREATE PROCEDURE statement is really the first in the query batch. If you're running this in SQL Server Management Studio, just add a GO delimiter before the CREATE.

How to execute SubSonic3 StoredProcedure with return value

How do I execute a SP and get the return value. The below code always returns null object. The storedprocedure has been tested in the database using the same parameters as in code, but the SubSonic sp always returns null. When executed in the db via sql, it returns the correct values.
This is using SubSonic 3.0.0.3.
myDB db = new myDB();
StoredProcedure sp = db.GetReturnValue(myParameterValue);
sp.Execute();
int? myReturnValue = (int?)sp.Output;
In the above code, sp.Output is always null. When executed in the database, the returned variable is a valid integer (0 or higher) and is never null.
Stored procedure code below:
CREATE PROCEDURE [dbo].[GetReturnValue]
#myVariable varchar(50)
AS
declare #myReturn int
BEGIN
set #myReturn = 5;
return #myReturn;
END
When executing the stored proc in SQL Server, the returned value is '5'.
I copied your sproc and stepped through the SubSonic code and .Output is never set anywhere. A work around would be using an output parameter and referring to it after executing: sproc.OutputValues[0];
Here's a simple way to do it:
In the stored procedure, instead of using RETURN, use SELECT like this:
SELECT ##ROWCOUNT
or
SELECT #TheIntegerIWantToReturn
Then in the code use:
StoredProcName.ExecuteScalar()
This will return the single integer you SELECTED in your stored procedure.
CREATE PROCEDURE [dbo].[GetReturnValue]
#myVariable varchar(50)
#myReturn BIGINT OUTPUT
AS
declare #myReturn int
BEGIN
set #myReturn = 5;
return #myReturn;
END

Resources