I wanna create a stored procedure to check if a sequence is with a given name is exist or no to create it or alter its value to max(Id) selected from given table name, So I create the below procedure but it throws a syntax error.
CREATE PROCEDURE EBPP_CORE.CREATE_OR_ALTER_SEQUENCE
#sequence_name VARCHAR2,
#table_name VARCHAR2
AS
BEGIN
DECLARE #MAX_ID_VAL NUMBER;
DECLARE #sequence_exist NUMBER;
SELECT #MAX_ID_VAL = CAST(ISNULL(MAX(id) + 1, 1) as nvarchar(10)) FROM #table_name ;
SELECT #sequence_exist = COUNT(*) FROM sys.sequences WHERE name = #sequence_name;
IF #sequence_exist>0
' ALTER SEQUENCE #sequence_name RESTART WITH #MAX_ID_VAL';
ELSE
'CREATE SEQUENCE #sequence_name START WITH #MAX_ID_VAL INCREMENT BY 1' ;
END
You have to use dynamic SQL to both find the current max ID and to create or alter the SEQUENCE objects. Something like this:
CREATE OR ALTER PROCEDURE EBPP_CORE.CREATE_OR_ALTER_SEQUENCE
#sequence_name nvarchar(128),
#table_name nvarchar(128)
AS
/*
drop table if exists foo
go
create table foo(id int)
exec EBPP_CORE.CREATE_OR_ALTER_SEQUENCE 'foo_seq','foo'
insert into foo(id) values (3)
exec EBPP_CORE.CREATE_OR_ALTER_SEQUENCE 'foo_seq','foo'
*/
BEGIN
DECLARE #MAX_ID_VAL bigint;
DECLARE #sequence_exist bigint;
declare #sql nvarchar(max) = concat('select #MAX_ID_VAL = MAX(id) + 1 FROM ', quotename(#table_name));
print #sql;
exec sp_executesql #sql, N'#MAX_ID_VAL bigint output', #MAX_ID_VAL=#MAX_ID_VAL output;
set #MAX_ID_VAL = coalesce(#MAX_ID_VAL,1)
SELECT #sequence_exist = COUNT(*) FROM sys.sequences WHERE name = #sequence_name;
IF #sequence_exist>0
BEGIN
set #sql = concat('ALTER SEQUENCE ', quotename(#sequence_name), ' RESTART WITH ', #MAX_ID_VAL) ;
print #sql;
exec (#sql);
END
ELSE
BEGIN
set #sql = concat('CREATE SEQUENCE ', quotename(#sequence_name), ' START WITH ', #MAX_ID_VAL,' INCREMENT BY 1') ;
print #sql;
exec (#sql);
END
END
Related
create PROC usp_delete_qu (
#table NVARCHAR(128),
#new_date datetime) AS BEGIN
DECLARE #sql NVARCHAR(MAX);
-- construct SQL
SET #sql = N'delete FROM ' + #table + N' where modified_date < ' +#new_date
-- execute the SQL
EXEC sp_executesql #sql;
END;
I create a stored procedure which I need to delete rows with modified date. But while I tried to execute this I got error:
Msg 241, Level 16, State 1, Procedure usp_query, Line 10 [Batch Start Line 19]
Conversion failed when converting date and/or time from character string.
My intention is to use this stored procedure to delete rows in all tables in my database.
Just use a parameter in your dynamic statement:
CREATE PROCEDURE usp_delete_qu
#table NVARCHAR(128),
#new_date datetime
AS BEGIN
DECLARE #sql NVARCHAR(MAX);
DECLARE #rc int
-- construct SQL
SET #sql = N'delete FROM ' + QUOTENAME(#table) + N' where modified_date < #new_date'
-- execute the SQL
EXEC #rc = sp_executesql #sql, N'#new_date datetime', #new_date
IF #rc <> 0 PRINT 'Error'
END
You'll have to convert your date into string when using dynamic query.
create PROC usp_delete_qu (
#table NVARCHAR(128),
#new_date datetime) AS BEGIN
DECLARE #sql NVARCHAR(MAX);
-- construct SQL
SET #sql = N'delete FROM ' + #table + N' where modified_date < ''' + CONVERT(NVARCHAR(50), #new_date) + ''' '
-- execute the SQL
EXEC sp_executesql #sql;
END;
Since Transact-SQL does not allow for construction like select * from exec ..,
sometimes it is very time consuming when we have to call dynamic query or other stored procedure and save output records in the table. We have to look for column names, data types and length in proper order etc. etc.
I prepared the procedure which is doing it automatically: just call UDP_DynSQLToTable with code to execute and table name to store output.
Procedure also works with temporary tables, but local temp tables have to be created before call, with any structure (will be altered by procedure).
Example of usage:
create table #CurrentUsers (dummy_field bit)
exec UDP_DynSQLToTable N'sp_who', '#CurrentUsers'
if exists (select 1 from #CurrentUsers where name='MyBoss') ...
I did not test it so intensively, so use it on you own responsibility and any comments or improvements are welcome.
Regards
create procedure UDP_DynSQLToTable
#sqlcode nvarchar(max),
#table nvarchar(2048),
#overwrite bit = 0
as
begin
set nocount on
/*
exec dbo.UDP_DynSQLToTable 'sp_who', 'myTable', 1 select * from myTable drop table myTable
*/
declare
#cmd nvarchar(max)='',
#dropcols nvarchar(max)='',
#createsql nvarchar(max),
#fieldList nvarchar(max),
#altersql nvarchar(max),
#sqltable nvarchar(max)
select #table=ltrim(rtrim(isnull(#table,'')))
begin try
if len(#table)=0
begin
print object_name(##procid)+': missing table name'
return
end
if left(#table,1)='[' and right(#table,1)=']'
select
#sqltable=#table,
#table=substring(#table,2,len(#table)-2)
else
select #sqltable='['+#table+']'
if (left(#table,1)='#' and left(#table,2)!='##')
begin
if object_id('tempdb..'+#table) is null
begin
print object_name(##procid)+': #table '+#table+' must be created (any structure) before call this proc'
return -4
end
else
begin
select #cmd = 'if (select count(*) from '+#sqltable+') > 0 delete from '+#sqltable
exec sp_executesql #cmd
if not exists (select name from tempdb.sys.columns where object_id=object_id('tempdb..'+#table) and name='dummy___field')
begin
select #cmd = 'alter table '+#sqltable+' add dummy___field bit'
exec sp_executesql #cmd
end
if exists (select name from tempdb.sys.columns where object_id=object_id('tempdb..'+#table) and name!='dummy___field')
begin
select #dropcols = 'alter table '+#sqltable+' drop column '
select #dropcols = #dropcols+name+','
from tempdb.sys.columns where object_id=object_id('tempdb..'+#table) and name!='dummy___field'
select #dropcols=left(#dropcols,len(#dropcols)-1)
exec sp_executesql #dropcols
end
end
end
else if OBJECT_ID(case when left(#table,2)='##'then 'tempdb.' else '' end +#table) is not null
begin
if #overwrite=0
begin
print object_name(##procid)+': object '+#table+' already exists'
return -2
end
else
begin
select #cmd = 'drop table '+#sqltable
exec sp_executesql #cmd
end
end
select #createsql = 'create table '+#sqltable+' ('+char(13)
select #fieldList = ''
select #altersql = 'alter table '+#sqltable+' add '
select
#createsql=#createsql+char(9)+isnull(name,'column_'+convert(nvarchar,column_ordinal))+' '+system_type_name+' '+
case when isnull(is_identity_column,0)=1 then 'IDENTITY ' else '' end +
case when isnull(is_part_of_unique_key,0)=1 then 'UNIQUE ' else '' end+
case when isnull(is_nullable,1)=0 then 'NOT NULL ' else '' end +','+char(13),
#fieldList=#fieldList+name+',',
#altersql=#altersql++char(9)+isnull(name,'column_'+convert(nvarchar,column_ordinal))+' '+system_type_name+' '+
case when isnull(is_identity_column,0)=1 then 'IDENTITY ' else '' end +
case when isnull(is_part_of_unique_key,0)=1 then 'UNIQUE ' else '' end+
case when isnull(is_nullable,1)=0 then 'NOT NULL ' else '' end +','+char(13)
from
(
select top 1000000
column_ordinal, name, system_type_name, is_identity_column, is_nullable, is_part_of_unique_key
from
sys.dm_exec_describe_first_result_set(#sqlcode, null, null) order by column_ordinal
) a
print #createsql
select #altersql=left(#altersql,len(#altersql)-2)
select #createsql=left(#createsql,len(#createsql)-2)+char(13)+char(9)+')'
select #fieldList=left(#fieldlist,len(#fieldlist)-1)
if left(#table,2)='##' or left(#table,1)!='#'
exec sp_executesql #createsql
else
begin
exec sp_executesql #altersql
select #cmd = 'alter table '+#sqltable+' drop column dummy___field'
exec sp_executesql #cmd
end
select #cmd = 'insert into '+#sqltable+' ('+#fieldList+') exec sp_executesql N'+''''+#sqlcode+''''
exec sp_executesql #cmd
end try
begin catch
declare #m nvarchar(max)=object_name(##procid)+' error: '+error_message()+char(13)+'Line '+convert(nvarchar,ERROR_LINE())
raiserror(#m,1,1)
end catch end
I want to pass table name as parameter and I want to that parameter in where clause
CREATE PROC [dbo].[bb_GetPrepositionInfo]
#userid INT,#propId INT,#tabName varchar(50)
AS
SET NOCOUNT ON
SET XACT_ABORT ON
BEGIN TRAN
SELECT *
FROM #tblname
WHERE ([acq_id] = #propId AND [user_id] = #userid)
COMMIT
GO
Not tested but You need to use Dynamic SQL.
CREATE PROC [dbo].[bb_GetPrepositionInfo]
#userid INT,#propId INT,#tabName varchar(50)
AS
SET NOCOUNT ON
SET XACT_ABORT ON
BEGIN TRAN
DECLARE #SQL varchar(250)
SELECT #SQL = 'SELECT * FROM ' + QuoteName(#tabName) + ' where acq_id=' + Quotename(#propId) + ' AND user_id=' + Quotename(#userid)
EXEC (#SQL)
COMMIT
GO
CREATE PROC [dbo].[bb_GetPrepositionInfo]
DECLARE #userid INT
DECLARE #propId INT
DECLARE #tabName varchar(50)
DECLARE #sqlCommand varchar(200)
AS
SET NOCOUNT ON
SET XACT_ABORT ON
BEGIN TRAN
SET #sqlCommand = 'SELECT * from ' + #tabName +'WHERE [acq_id]='+ #propId +'AND [user_id] = '+ #userid
EXEC (#sqlCommand)
COMMIT
GO
I have a sql stored procedure which calls another sql stored procedure. I works fine when excuted in sql server. But when I called from function in class it returns the DataTable returned by subprocedure. I want to return data returned by main procedure.
My Main Procedure:
ALTER PROCEDURE [dbo].[StoredProcedure2]
#QuaterList varchar(50) = NULL
AS
BEGIN
DECLARE #sql nvarchar(4000)
SELECT #sql='SELECT Id, Suggester, Requester, Date_Created from CRM.dbo.CRM_Doctor_Request WHERE 1=1 '
If (#QuaterList) IS NOT NULL
BEGIN
DECLARE #MonthsList varchar(1000)
EXEC dbo.SPGetMonthsListforMultipleQuaters #QuaterList, #MonthsList OUTPUT
SELECT #MonthsList
SELECT #sql=#sql + ' AND MONTH(Date_Created) in ('
+ SUBSTRING(#MonthsList, 1, LEN(#MonthsList)-1) +')'
END
EXEC sp_executesql #sql, N' #QuaterList varchar(50) ',
#QuaterList
END
Sub Procedure SPGetMonthsListforMultipleQuaters:
ALTER PROCEDURE dbo.SPGetMonthsListforMultipleQuaters
#InputList varchar(10),
#MonthsList varchar(1000) OUTPUT
AS
BEGIN
SELECT #MonthsList= ''
/* Create temp table */
CREATE TABLE #TempListTable
(
TableField int
)
/* add data into temp table */
DECLARE #TableField varchar(10), #Pos int
SET #InputList = LTRIM(RTRIM(#InputList))+ ','
SET #Pos = CHARINDEX(',', #InputList, 1)
IF REPLACE(#InputList, ',', '') <> ''
BEGIN
WHILE #Pos > 0
BEGIN
SET #TableField = LTRIM(RTRIM(LEFT(#InputList, #Pos - 1)))
IF #TableField <> ''
BEGIN
INSERT INTO #TempListTable (TableField) VALUES (CAST(#TableField AS int)) --Use Appropriate conversion
END
SET #InputList = RIGHT(#InputList, LEN(#InputList) - #Pos)
SET #Pos = CHARINDEX(',', #InputList, 1)
END
END
/* fetch data from temptable using cursor */
DECLARE #ArrayItem nvarchar(100)
DECLARE #Array_Cursor CURSOR
SET #Array_Cursor = CURSOR FAST_FORWARD FOR select TableField
from #TempListTable
OPEN #Array_Cursor
FETCH NEXT FROM #Array_Cursor INTO #ArrayItem
WHILE ##FETCH_STATUS = 0
BEGIN
/* creating list of months */
IF (#ArrayItem = 1)
SELECT #MonthsList=#MonthsList + '4,5,6,'
IF (#ArrayItem = 2)
SELECT #MonthsList=#MonthsList + '7,8,9,'
IF (#ArrayItem = 3)
SELECT #MonthsList=#MonthsList + '10,11,12,'
IF (#ArrayItem = 4)
SELECT #MonthsList=#MonthsList + '1,2,3,'
FETCH NEXT FROM #Array_Cursor INTO #ArrayItem
END
/*print #MonthsList*/
Close #Array_Cursor
deallocate #Array_Cursor
END
Problem solved. It was because I wrote SELECT #MonthsList so it was returning that too which is not required, and was also creating problems. So I removed it and problem solved.
New Procedure code is :
ALTER PROCEDURE [dbo].[StoredProcedure2]
#QuaterList varchar(50) = NULL
AS
BEGIN
DECLARE #sql nvarchar(4000)
SELECT #sql='SELECT Id, Suggester, Requester, Date_Created from CRM.dbo.CRM_Doctor_Request WHERE 1=1 '
If (#QuaterList) IS NOT NULL
BEGIN
DECLARE #MonthsList varchar(1000)
EXEC dbo.SPGetMonthsListforMultipleQuaters #QuaterList, #MonthsList OUTPUT
SELECT #sql=#sql + ' AND MONTH(Date_Created) in ('
+ SUBSTRING(#MonthsList, 1, LEN(#MonthsList)-1) +')'
END
EXEC sp_executesql #sql, N' #QuaterList varchar(50) ',
#QuaterList
END
DECLARE #dbName nvarchar(128) = 'myDb'
DECLARE #siteId int
exec ('SELECT TOP 1 #siteId = Id FROM ' + #dbName + '..myTbl')
select #siteId
When I run the script above I get the following error
Msg 137, Level 15, State 1, Line 1
Must declare the scalar variable "#siteId".
(1 row(s) affected)
Why and how to fix it?
Thank you
You can use output parameters with sp_executesql.
DECLARE #dbName nvarchar(128) = 'myDb'
DECLARE #siteId int
DECLARE #SQL nvarchar(max) = N'SELECT TOP 1 #outputFromExec = Id FROM ' + quotename(#dbName) + N'..myTbl'
exec sp_executesql #SQL, N'#outputFromExec int out', #siteId out
select #siteId
The dynamic SQL is a different scope to the outer, calling SQL: so #siteid is not recognised
You'll have to use a temp table/table variable outside of the dynamic SQL:
DECLARE #dbName nvarchar(128) = 'myDb'
DECLARE #siteId TABLE (siteid int)
INSERT #siteId
exec ('SELECT TOP 1 Id FROM ' + #dbName + '..myTbl')
select * FROM #siteId
Note: TOP without an ORDER BY is meaningless. There is no natural, implied or intrinsic ordering to a table. Any order is only guaranteed by the outermost ORDER BY
You can try like below
DECLARE #sqlCommand NVARCHAR(4000)
DECLARE #ID INT
DECLARE #Name NVARCHAR(100)
SET #ID = 4
SET #sqlCommand = 'SELECT #Name = [Name]
FROM [AdventureWorks2014].[HumanResources].[Department]
WHERE DepartmentID = #ID'
EXEC sp_executesql #sqlCommand, N'#ID INT, #Name NVARCHAR(100) OUTPUT',
#ID = #ID, #Name = #Name OUTPUT
SELECT #Name ReturnedName
Source : blog.sqlauthority.com
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: Andrew Foster
-- Create date: 28 Mar 2013
-- Description: Allows the dynamic pull of any column value up to 255 chars from regUsers table
-- =============================================
ALTER PROCEDURE dbo.PullTableColumn
(
#columnName varchar(255),
#id int
)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #columnVal TABLE (columnVal nvarchar(255));
DECLARE #sql nvarchar(max);
SET #sql = 'SELECT ' + #columnName + ' FROM regUsers WHERE id=' + CAST(#id AS varchar(10));
INSERT #columnVal EXEC sp_executesql #sql;
SELECT * FROM #columnVal;
END
GO
A slight change in the execute query will solve the problem:
DECLARE #dbName nvarchar(128) = 'myDb'
DECLARE #siteId int
exec ('SELECT TOP 1 **''#siteId''** = Id FROM ' + #dbName + '..myTbl')
select #siteId