I want to pass 2 parameters to my stored procedure, one of which I wish to use as a part of a variable definition. I am using SQL Server Management Studio 2018. My stored procedure will take a consignment number as a parameter and append it to the variable where the definition will appear similar to this:
passed parameter = #ConsignmentNo
variable #TmpDictionary = 'tmp.' + #ConsignmentNo + '_Dictionary'
So that I may have a generated table name such as
tmp.Cons1234_Dictionary
SQL is throwing an error
Must declare the table variable "#TmpDictionary"
Please see my attempt here:
/****** Object: --------------- Script Date: 29/06/2022 16:17:32 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE InsertProcedureNameHere
#Source varchar (max),
#ConsignmentNo varchar(max)
AS
DECLARE
#sql varchar(MAX),
#loop int,
#max_loop int,
#TmpDictionary nvarchar(max) = 'tmp.' + #ConsignmentNo + '_Dictionary',
#TmpThesaurus nvarchar(max) = 'mail.' + #ConsignmentNo + '_Thesaurus'
--set #TmpLookup = 'tmp.' + #JobNumber + '_Mailing_Lookup'
--set #MailSelection = 'mail. + #JobNumber + '_Mailing_Selection'
SELECT #loop = MIN(ID) FROM #TmpDictionary
WHERE [Source] = #Source
SELECT #max_loop = MAX(ID) FROM #TmpDictionary
WHERE [Source] = #Source
--print #loop print #max_loop
WHILE #loop <= #max_loop
BEGIN
SELECT
---------
FROM #TmpDictionary t
WHERE ID = #loop
BEGIN
SET #sql = '
update t
-------------------
from #Thesaurus t
where 1=1
-------------------
PRINT (#sql)
-- EXEC (#sql)
END
SET #loop = #loop +1
END
Please accept the fact that anything with dashes is just a placeholder for parts of the query that I cannot share or are needed for the purpose of this question. In a nutshell, I need to be able to pass a variable to my stored procedure, and use it within a variable definition to be able to reference tables dynamically using dynamic queries.
I hope this question makes sense!
Related
I'm facing deadlock
was deadlocked on lock resources with another process and has been
chosen as the deadlock victim.
problem In SQL-Server as i'm inserting data in database by picking max id against a specific column then add a increment got the value against which record will be inserted.
i'm calling a procedure as code mentioned below:
CREATE
PROCEDURE [dbo].[Web_GetMaxColumnID]
#Col_Name nvarchar(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
DECLARE #MaxID BIGINT;
SET NOCOUNT ON;
-- Insert statements for procedure here
BEGIN
BEGIN TRAN
SET #MaxID = (
SELECT Col_Counter
FROM Maintenance_Counter WITH (XLOCK, ROWLOCK)
WHERE COL_NAME = #Col_Name
)
UPDATE Maintenance_Counter
SET Col_Counter = #MaxID + 1
WHERE COL_NAME = #Col_Name
COMMIT
END
SELECT (
CONVERT(
VARCHAR,
(
SELECT office_id
FROM Maintenance
)
) + '' + CONVERT(VARCHAR, (#MaxID))
) AS MaxID
END
any one help me out .....
As Marc already answered, use SEQUENCE. It's available in all supported versions of SQL Server, ie 2012 and later. The only reason to avoid it is targeting an unsupported version like 2008.
In this case, you can set the counter variable in the same statement you update the counter value. This way, you don't need any transactions or locks, eg:
declare #counterValue bigint
UPDATE Maintenance_Counter
SET Col_Counter = Col_Counter + 1 , #counterValue=Col_Counter+1
WHERE COL_NAME = #Col_Name
select #counterValue
Yo can use sequences to generate incremental values avoiding any blocking.
I have adapted my own Counter Generator to be a direct replacement for yours. It creates dynamically the SQL statements to manage sequences, if a Sequence doesn't exist for the value we are looking for, it creates it.
ALTER PROCEDURE [dbo].[Web_GetMaxColumnID]
#Col_Name nvarchar(50)
AS
declare #Value bigint;
declare #SQL nvarchar(64);
BEGIN
if not exists(select * from sys.objects where object_id = object_id(N'dbo.MY_SEQUENCES_' + #Col_Name) and type = 'SO')
begin
set #SQL = N'create sequence dbo.MY_SEQUENCES_' + #Col_Name + ' as bigint start with 1';
exec (#SQL);
end
set #SQL = N'set #Value = next value for dbo.MY_SEQUENCES_' + #Col_Name;
exec sp_executesql #SQL, N'#Value bigint out', #Value = #Value out;
select #Value ;
END
The only inconvenience is that your values can get gaps within (because you could have retrieved a value but finally not used it). This is not a problem on my tables, but you have to consider it.
I have several queries that drop the proc if it exists, recreate it, and set permissions on it, similar to this:
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
GO
if exists (select *
from dbo.sysobjects
where id = object_id(N'[dbo].[spMyStoredProcedureName]')
and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[spMyStoredProcedureName]
GO
CREATE PROCEDURE [dbo].[spMyStoredProcedureName]
AS
/* more proc stuff */
GRANT EXECUTE ON [dbo].[spMyStoredProcedureName]
TO Some_User_Group
My question is: is there some way to define a variable for [dbo].[spMyStoredProcedureName] so that I can declare it once and refer to the variable? I need to use the variable two ways - once as a string in the select statement and the rest of the time as a reference to the stored proc I'm creating/dropping.
I'm assuming your goal is to replace your "several scripts" with just one script that can be used by changing the value of the variable that holds the name of the stored procedure.
If so you could try a dynamic approach:
Declare #spMyStoredProcedureName nvarchar(255);
--either use a cursor or whatever means to populate the variable.
--for this example I will simply set it
SET #spMyStoredProcedureName = '[dbo].[spMyStoredProcedureName]';
DECLARE #sql nvarchar(max);
SET #sql='
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
GO
if exists (select *
from dbo.sysobjects
where id = object_id(N''#spMyStoredProcedureName'')
and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure #spMyStoredProcedureName
GO
CREATE PROCEDURE #spMyStoredProcedureName
AS
/* more proc stuff */
GRANT EXECUTE ON #spMyStoredProcedureName
TO Some_User_Group
';
SET #sql = REPLACE(#sql, '#spMyStoredProcedureName', #spMyStoredProcedureName)
EXECUTE(#sql)
Note that you'll need to escape all the single quotes in your stored proc code when doing this. Also I'm not so sure you can use the GO command in dynamic sql. If not, you'd need to do two separate dynamic statements per stored proc.
Use dynamic sql for your intended ddl statement. A sample implementation below.
-- Declare variable to store the procedure name
Declare #proc varchar(100) = 'myProc';
-- Construct the ddl statement
DECLARE #script nvarChar(MAX);
SET #script =
'
if exists (select *
from dbo.sysobjects
where id = object_id(N'''+ #proc + ''')
and OBJECTPROPERTY(id, N''IsProcedure'') = 1)
drop procedure ' + #proc + ';
GO
CREATE PROCEDURE ' + #proc + '
AS
print ''Hello World!'';
/* more proc stuff */
GO
GRANT EXECUTE ON ' + #proc + '
TO Some_User_Group;
'
SET #script = 'EXEC (''' + REPLACE(REPLACE(#script, '''', ''''''),
'GO', '''); EXEC(''') + ''');'
-- Run the dynamic ddl
EXEC (#script);
-- Test
exec myproc;
I need to get data from a table in a database who's database name will be determined as a variable during a trigger. I then, knowing this variable need to get a seqno from a table in the determined database for a item which was also determined as a variable during a trigger.
I am trying this route as I assume I need to build the SQL statement before I set it to a variable.
This is not working and I need to know the best way on how I can do this:
DECLARE #SU_SEQNO INTEGER, #SU_NAME VARCHAR(50), #SU_OWNER VARCHAR(15), #SUD_SEQNO INTEGER, #SQL NVARCHAR(500)
SET #SU_OWNER = 'XXX'
SET #SU_NAME = '1ABC234'
SET #SQL ='SELECT #SUD_SEQNO=SEQNO FROM ' + (#SU_OWNER) + '.SU_MAIN
WHERE UNITNAME= ' + #SU_NAME
SET #SUD_SEQNO = (EXECUTE (#SQL))
Thanks alot for any help with this
From: Get result from dynamic SQL in stored procedure
SET #SQL = N'SELECT DISTINCT #FiscalYear = FiscalYear FROM ' + #DataSource;
EXEC sp_executesql #SQL, N'#FiscalYear INT OUTPUT', #FiscalYear OUTPUT;
PRINT #FiscalYear;
I'd re-engineer to use the sp_executesql method as shown above. That should do the trick.
I have amended the code, and it works
declare #su_owner varchar(15) = 'DBTEST'
declare #SU_SEQNO INTEGER=1, #SUD_SEQNO INTEGER=0, #SQL NVARCHAR(500)
DECLARE #ParmDefinition NVARCHAR(500), #SU_NAME_INPUT VARCHAR(50)='SU123'
SET #SU_NAME_INPUT = (SELECT UNITNAME FROM SU_MAIN WHERE SEQNO=#SU_SEQNO)
SET #SU_NAME = (SELECT UNITNAME FROM SU_MAIN WHERE SEQNO=#SU_SEQNO)
SET #SQL = N'SELECT #sud_seqnoOUT=MAX(SEQNO) FROM ' + quotename(#su_owner) + '.[dbo].[SU_MAIN] WHERE UNITNAME]=#SU_NAME_INPUT' ;
SET #ParmDefinition = N'#SU_NAME_INPUT VARCHAR(50),#sud_seqnoOUT INT OUTPUT'
EXEC sp_executesql #SQL,#ParmDefinition,#SU_NAME_INPUT = #SU_NAME,
#sud_seqnoOUT = #SUD_SEQNO OUTPUT
How do I use a variable for Column name in Scalar-Valued Function?
CREATE FUNCTION [dbo].[GetValue]
(
#ID varchar(36),
#PreprtyName varchar(150)
)
RETURNS varchar(250)
AS
BEGIN
DECLARE #RetVal varchar(MAX)
DECLARE #SQL varchar(MAX)
SET #RetVal =''
SET #SQL = 'SET #RetVal = (Select '+ #PreprtyName + ' FROM TableMedia WHERE ID = '''+ #ID +')'''
exec #SQL
SET #RetVal = #RetVal
RETURN #RetVal
END
Getting error Could not find "Could not find stored procedure"
Here is what I'm trying to avoid.
SELECT pr.ProductID, tManufacturerImage.Image, tMediaCenter.ManualFileName,tMediaCenter.BrochureFileName, tMediaCenter.AssemblyFileName
FROM tMediaCenter RIGHT OUTER JOIN
tProduct AS pr INNER JOIN
tmp_dmi AS dmi ON REPLACE(REPLACE(pr.SKU, 'ACS', ''), 'DMI', '') = RTRIM(LTRIM(dmi.pri_SKU)) ON tMediaCenter.ProductID = pr.ProductID LEFT OUTER JOIN
tManufacturer INNER JOIN
tManufacturerImage ON tManufacturer.ManufacturerID = tManufacturerImage.ManufacturerID ON pr.ManufacturerID = tManufacturer.ManufacturerID
WHERE (pr.ManufacturerID = 'f35fc01680-4938-4070-a367-38c31efb01f') AND (dmi.MAP IS NULL) AND (pr.ParentID <> '')
this does not work for me.
You can't. A user-defined function does not support dynamic SQL. You will need to do this with a stored procedure instead, or better define your ultimate goal instead of telling us you need to solve it with dynamic SQL in a function.
CREATE PROCEDURE [dbo].[GetValues]
#PreprtyName VARCHAR(150)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'SELECT ' + #PreprtyName + ' FROM dbo.Table;';
EXEC sp_executesql #sql;
END
GO
You won't have an easy time doing this inline in your query, sorry. The issue is that there is no way to do this from a function, and there is no way to call a stored procedure for each row in a single query. You could construct a loop and everything else but I think the above procedure fits your requirement without all that extra work and overhead.
If you need to limit it to a certain set of ID values, you'll need to describe how you're trying to do that now.
if i want to write a procedure like below, is there some other way that,
to avoid using concatenate SQL statement, i am just afraid, if the input is too long, exceed the limit of max varchar, the code will have big problem.
Thanks
CREATE PROCEDURE UPDATE_ALL_STATUS
#IDs varchar(MAX) = null,
#status int = null
AS
BEGIN
IF #IDs is null
BEGIN
RETURN
END
DECLARE #SQL VARCHAR(MAX)
SET #SQL = 'UPDATE mytable SET status = ' + #status + ' WHERE id in (' + #IDs + ')'
EXECUTE #SQL
END
Instead of dynamic SQL (which is also vulnerable to SQL Injection Attacks) and passing in a VARCHAR(MAX), consider using Table Valued Parameters:
-- Creates the TVP type - only needed once!
CREATE TYPE IntegerTableType AS TABLE
( Identities INT );
GO
CREATE PROCEDURE UPDATE_ALL_STATUS
#IDs IntegerTableType READONLY,
#status int = null
AS
BEGIN
UPDATE mytable
SET status = #status
WHERE id IN
(SELECT Identities FROM #IDs)
END
This MSDN article shows how to call these from your .NET code.