Syntax issue on the source - sql

I'm migrating a SQL Server 2008 database to SQL Server 2019, I have used Microsoft Data Migration Assistant, to look for search any breaking changes, issues or syntax errors.
I getting errors for some of my procedures:
Object [dbo].[PROCEDURE1] has syntax errors. Must declare the variable or parameter "#SINI". Error number 70590. For more details, please see: Line 9, Column 16.
This is my procedure:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[PROCEDURE1]
#Refer AS varchar,
#Ret Decimal OUTPUT
AS
DECLARE #SIni AS Decimal
SET #SIni= (SELECT Ini FROM Table1 WHERE Refer = #Refer)
SET #Ret = #SINI

Probably you have a server with case sensitive collation. As is explained in the documentation, the identifiers for variables, GOTO labels, temporary stored procedures, and temporary tables are in the default collation of the server instance.. You may check this with the following simple statement:
SELECT SERVERPROPERTY('collation');
But, to fix the error, use the correct case-sensitive variable name:
...
SET #Ret = #SIni
...
As an additional note, declare your data types with the appropriate length (as #Larnu commented). The length attribute is optional, and in case of parameter declaration the SQL Server assigns 1 as length, so the #Refer parameter has data type varchar(1).

Related

How to use SET OPTION within a DB2 stored procedure

I read (and tried) that I cannot use WITH UR in DB2 stored procedures. I am told that I can use SET OPTION to achieve the same. However, when I implement it in my stored procedure, it fails to compile (I moved around its location same error). My questions are:
Can I really not use WITH UR after my SELECT statements within a procedure?
Why is my stored procedure failing to compile with the below error
message?
Here is a simplified version of my code:
CREATE OR REPLACE PROCEDURE MySchema.MySampleProcedure()
DYNAMIC RESULT SETS 1
LANGUAGE SQL
SET OPTION COMMIT=*CHG
BEGIN
DECLARE GLOBAL TEMPORARY TABLE TEMP_TABLE AS (
SELECT 'testValue' as "Col Name"
) WITH DATA
BEGIN
DECLARE exitCursor CURSOR WITH RETURN FOR
SELECT *
FROM SESSION.TEMP_TABLE;
OPEN exitCursor;
END;
END
#
Error Message:
SQL0104N An unexpected token "SET OPTION COMMIT=*CHG" was found
following " LANGUAGE SQL
Here is code/error when I use WITH UR
CREATE OR REPLACE PROCEDURE MySchema.MySampleProcedure()
LANGUAGE SQL
DYNAMIC RESULT SETS 1
--#SET TERMINATOR #
BEGIN
DECLARE GLOBAL TEMPORARY TABLE TEMP_TABLE AS (
SELECT UTI AS "Trade ID" FROM XYZ WITH UR
) WITH DATA;
BEGIN
DECLARE exitCursor CURSOR WITH RETURN FOR
SELECT *
FROM SESSION.TEMP_TABLE;
OPEN exitCursor;
END;
END
#
line 9 is where the DECLARE GLOBAL TEMPORARY ... is
DB21034E The command was processed as an SQL statement because it was
not a valid Command Line Processor command. During SQL processing it
returned: SQL0109N The statement or command was not processed because
the following clause is not supported in the context where it is
used: "WITH ISOLATION USE AND KEEP". LINE NUMBER=9. SQLSTATE=42601
Specifying the isolation level:
For static SQL:
If an isolation-clause is specified in the statement, the value of that clause is used.
If an isolation-clause is not specified in the statement, the isolation level that was specified for the package when the package was bound to the database is used.
You need to bind the routine package with UR, since your DECLARE GTT statement is static. Before CREATE OR REPLACE use the following in the same session:
CALL SET_ROUTINE_OPTS('ISOLATION UR')
P.S.: If you want to run your routine not only 1 time in the same session without an error, use additional WITH REPLACE option of DECLARE.
If your Db2 server runs on Linux/Unix/Windows (Db2-LUW), then there is no such statement as SET OPTION COMMIT=*CHG , and so Db2 will throw an exception for that invalid syntax.
It is important to only use the matching Db2 Knowledge Centre for your Db2 platform and your Db2-version. Don't use Db2-Z/OS documentation for Db2-LUW development. The syntax and functionalities differ per platform and per version.
A Db2-LUW SQL PL procedure can use with ur in its internal queries, and if you are getting an error then something else is wrong. You have to use with ur in the correct syntax however, i.e in a statement that supports this clause. For your example you get the error because the clause does not appear to be valid in the depicted context. You can achieve the desired result in other ways, one of them being to populate the table in a separate statement from the declaration (e.g insert into session.temp_table("Trade ID") select uti from xyz with ur; ) and other ways are also possible.
One reason to use the online Db2 Knowledge Cenbtre documentation is that it includes sample programs, including sample SQL PL procedures, which are also available in source code form in the sample directory of your DB2-LUW server, in addition to being available on github. It is wise to study these, and get them working for you.

Selecting data from a different schema within a stored procedure

Consider this:
CREATE PROCEDURE [dbo].[setIdentifier](#oldIdentifierName as varchar(50), #newIdentifierName as varchar(50))
AS
BEGIN
DECLARE #old_id as int;
DECLARE #new_id as int;
SET #old_id = (SELECT value FROM Configuration WHERE id = #oldIdentifierName);
SET #new_id = (SELECT value FROM Configuration WHERE id = #newIdentifierName);
IF #old_id IS NOT NULL AND #new_id IS NOT NULL
BEGIN
UPDATE Customer
SET type = #new_id
WHERE type = #old_id;
END;
END
[...]
EXECUTE dbo.setIdentifier '1', '2';
What this does is create a stored procedure that accepts two parameters which it then uses to update a Customer table.
The problem is that the entire script above runs within a schema other than "dbo". Let's just assume the schema is "company1". And when the stored procedure is called, I get an error from the SELECT statement, which says that the Configuration table cannot be found. I'm guessing this is because MS SQL by default looks for tables within the same schema as the location of the stored procedure, and not within the calling context.
My question is this:
Is there some option or parameter or switch of some kind that will
tell MS SQL to look for tables in the "caller's default schema" and
not within the schema that procedure itself is stored in?
If not,
what would you recommend? I don't really want to prefix the tables
with the schema name, because it would be kind of unflexible to do
that. So I'm thinking about using dynamic sql (and the schema_name()
function which returns the correct value even within the procedure),
but I am just not experienced enough with MS SQL to construct the
proper syntax.
It would be a tad more efficient to explicitly specify the schema name. And generally speaking, schema's are mainly used to divide a database into logical area's. I would not anticipate on tables schema-hopping often.
Regarding your question, you might want to have a look at the 'execute as' documentation on msdn, since it allows to explicitly control your execution context.
I ended up passing the schema name to my script as a property on the command line for the "sqlcmd" command. Like this:
C:/> sqlcmd -vSCHEMANAME=myschema -imysqlfile
In the SQL script I can then access this variable like this:
SELECT * from $(SCHEMANAME).myTable WHERE.... etc
Not quite as flexible as dynamic sql, but "good enough" as it were.
Thanks all for taking time to respond.

Sql Server - Any way to find which stored procedures return sets and which not?

I need to build a service which expose metadata about stored procedures in an sql server database.
Is there any way to find out which stored procedure return sets, and which don't, so they can be called, correspondingly, through ExecuteReader or ExecuteNonQuery?
Thank you
It turns out (I Googled) that the way to do this is to set the FMTONLY FLAG to ON on Sql Server.
See here.
Here's an example taken from here:
SET FMTONLY ON;
EXEC dbo.MyTestSproc #param1 = NULL, #param2 = NULL, #param3 = NULL
SET FMTONLY OFF;
In the case where a stored proc does not return any data, you won't see any output (at least that was my observation in SSMS). When the proc does return data, you see the column names being displayed without actually anything being returned.
So it is sort of a trial an error kind of thing.
NOTE: I tested with a proc that uses a table-valued parameter and it did not produce any output even though the proc does return data. Setting the parameter to NULL did not work and SSMS complained with a nasty error. The error seems to be related to a temp table being used inside the proc and not necessarily with the table-value parameter but still didn't produce the empty resultset:
Msg 208, Level 16, State 0, Procedure spWhatever,
Line 20 Invalid object name '#temp'.
Looking at the link posted by Michael, it appears that if the proc returns different result sets depending on a parameter passed in, for example, it's impossible to know with certainty. See Marc Gravell's answer.

Why can't I pass in a uniqueidentifier/GUID to a stored procedure

I have this SP
USE [TestDB]
GO
/****** Object: StoredProcedure [dbo].[sp_test] Script Date: 06/12/2010 11:47:27 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[sp_test]
#id uniqueidentifier
AS
BEGIN
select * from TestTbl where ProductId= #id
END
I then went to the SP with ms sql 2005 and clicked execute. It comes up with a box where I entered in the GUID. I copied and pasted it straight from my test database.
I get this error.
Msg 102, Level 15, State 1, Line 5
Incorrect syntax near 'cac671b'.
So why can't I sent in GUIDs? even ones that are copied right from the database and must be valid as they where allowed into the db.
Two hints:
first of all, do not call your stored procedures sp_(something) - Microsoft specifically warns against that
We recommend that you do not create
any stored procedures using sp_ as a
prefix. SQL Server uses the sp_ prefix
to designate system stored procedures.
The name you choose may conflict with
some future system procedure.
secondly: I have no trouble calling your stored proc like this:
EXEC proc_test 'B551F2C8-8380-491B-A51F-436E51CDD08F'
How are you calling your stored proc?? Show us!
The message
Incorrect syntax near 'cac671b'.
Must mean that it is trying to parse the GUID itself. Try delimiting it in single quotes.
I imagine you're copying-and-pasting a string. Can you declare and use it like this?
CREATE PROCEDURE [dbo].[sp_test]
#guidstr varchar(37)
AS
DECLARE #guid uniqueidentifier
SET #guid = CONVERT(uniqueidentifier, #guidstr)
...

Sql server 2005 acting case sensitive inspite of case insensitive collation

I am having following issue.Even after case insensitive collation. SQL server is treating #Result and #result differently. Am i missing something.Please help.
SELECT DATABASEPROPERTYEX('OA_OPTGB_0423', 'Collation') SQLCollation;
SQL_Latin1_General_CP1_CI_AS
DECLARE #Result varchar(2000)
SELECT TOP 1 #result = addr.address_id
FROM dbo.address addr
JOIN dbo.company_address compadd ON addr.address_id = compadd.address_id
ORDER BY addr.address_id desc
...throws this error:
Msg 137, Level 15, State 1, Line 2
Must declare the scalar variable "#result".
Edit:-
This same query works in my local machine.I tried it and got no error.
From MSDN:
Identifier Collation
The collation of an identifier depends
on the level at which it is defined.
Identifiers of instance-level objects,
such as logins and database names, are
assigned the default collation of the
instance. Identifiers of objects
within a database, such as tables,
views, and column names, are assigned
the default collation of the database.
Variables, GOTO labels, temporary
stored procedures, and temporary
tables can be created when the
connection context is associated with
one database and then referenced when
the context has been switched to
another database. Therefore, the
identifiers for variables, GOTO
labels, and temporary tables are in
the default collation of the instance.
So even though you're attempting to declare the collation of the database, variables are always going to use the default collation of your SQL Server instance.
If you've just reinstalled your database into a new instance, you should consider either upgrading your code to comply with the new collation (probably what I would do), or else follow this document on how to change the instance collation.
Really though, it seems a bit sloppy to have randomly cased variable references ;)
Collation deals with data (values); not identifier names.
There is no reason for your sample to fail unless you're running the statements as separate batches as your declarations only have scope local to the batch.
If you're running the statements one-at-a-time .... there's your problem!
Otherwise check what you have configured as a batch separator; the default is GO