I'm trying to append table name dynamically to SQL Server stored procedure, but I get an error:
couldn't find the stored procedure 's'
Code:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[atest_demo_sp]
#name varchar(10)
AS
BEGIN
Declare #tname nvarchar
Declare #sql nvarchar
set #tname = #name
Set #sql = 'select * from ' + convert(varchar(10), #tname)
-- select #sql
execute sp_executesql #sql
END
You need to explicitly define a length for your string variables!
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[atest_demo_sp]
#name varchar(10)
AS
BEGIN
Declare #tname nvarchar(200) -- DEFINE A LENGTH HERE !!!
Declare #sql nvarchar(200) -- DEFINE A LENGTH HERE !!!
set #tname = #name
Set #sql = N'select * from ' + convert(nvarchar(10), #tname)
-- select #sql
execute sp_executesql #sql
END
Otherwise, your variables #tname and #sql will be exactly 1 character long! Probably not what you want!
See this blog post for more details: Bad habits to kick : declaring VARCHAR without (length)
Also, as a side note: either pick varchar (non-Unicode), or use nvarchar (Unicode) - but don't mix the two. And if you use nvarchar, you should always use the N'...' notation for assigning string literals.
The issue with the set #tname = #name, no need to assign the varchar to nvarchar here. Avoid the #tname variable and directly use #name in the SET statement since it is already varchar.
Hope the #name's first character only assigning to #tname. Also need to define the #sql to some length.
Use the below statement, it will work:
Declare #sql varchar(100);
Set #sql = 'select * from ' + #name
Related
I have a database with 40 tables. I want to select data from a certain table by using a single stored procedure. First table (TblSPAU1) has 6 columns, named: ID, COL_SPAU1_EA, COL_SPAU1_EQ, COL_SPAU1_ore, COL_SPAU1_nivel, DateTime. Fourth table (TblSPAU4), for example, has this 6 columns: ID, COL_SPAU4_EA, COL_SPAU4_EQ, COL_SPAU4_ore, COL_SPAU4_nivel, DateTime. So what I want is to select data from table X from DateStart to DateStop. What I've done so far is:
USE [DBRapBreaza]
GO
/****** Object: StoredProcedure [dbo].[PS_SpauOPompa] Script Date: 12/19/2018 15:48:38 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[PS_SpauOPompa]
#DataStart datetime,
#DataStop datetime,
#val int
AS
BEGIN
SET NOCOUNT ON;
declare #sql NVARCHAR(max)
declare #col1 varchar
set #col1='ID'
declare #col2 varchar(25)
set #col2='COL_SPAU'+CONVERT(VARCHAR, #val)+'_EA'
declare #col3 varchar
set #col3='DateTime'
set #sql='select [ID]'+#col2+' FROM [DBRapBreaza].[dbo].[TblSPAU'+CONVERT(VARCHAR, #val)+ '] WHERE DateTime between'+CONVERT(VARCHAR(25), #DataStart,121)+ 'and'+CONVERT(VARCHAR(25), #DataStop,121)+';'
END
EXEC sp_sqlexec #sql, N'#DataStart datetime,#DataStop datetime,#val int', #DataStart, #DataStop, #val
I want to select, let's say, the ID and fist column from a certain table. #val represents the number of the table I want to select data from.
On sp_sqlexec I have a tool-tip which says that I have too many arguments specified. When I execute the EXEC, it throws me this error: Msg 137, Level 15, State 2, Line 1. Must declare the scalar variable "#sql".
My question is how should I execute this stored procedure?
Many thanks in advance!
First, you need some spaces in your string build. Specifically, change it to:
set #sql= 'select [ID], '+#col2+' FROM [DBRapBreaza].[dbo].[TblSPAU'+CONVERT(VARCHAR, #val)+ '] WHERE DateTime between '''+CONVERT(VARCHAR(25), #DataStart,121)+ ''' and '''+CONVERT(VARCHAR(25), #DataStop,121)+''';'
This will make your SQL look like this:
select [ID], COL_SPAU1_EA FROM [DBRapBreaza].[dbo].[TblSPAU1] WHERE DateTime between '2018-12-20 14:18:02.170' and '2018-12-20 14:18:02.170';
As opposed to the following:
select [ID]COL_SPAU1_EA FROM [DBRapBreaza].[dbo].[TblSPAU1] WHERE DateTime between2018-12-20 14:19:13.167and2018-12-20 14:19:13.167;
Which is missing:
A comma after the first column
Space between comma names (semantics)
Space after the word between
Quotes around the dates that will be evaluated from your parameters
Space before and after and in the where clause on your between statement
This is why it's always wise to use PRINT #sql while testing your dynamic SQL.
Then, once you move the END to the very bottom of the script, change your execution to:
EXEC sp_executesql
#sql,
N'#DataStart datetime, #DataStop datetime, #val int',
#DataStart, #DataStop, #val
This will leave you with the following code:
USE [DBRapBreaza]
GO
/****** Object: StoredProcedure [dbo].[PS_SpauOPompa] Script Date: 12/19/2018 15:48:38 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[PS_SpauOPompa]
#DataStart datetime,
#DataStop datetime,
#val int
AS
BEGIN
SET NOCOUNT ON;
declare #sql NVARCHAR(max)
declare #col1 varchar --missing a length here
declare #col2 varchar(25)
declare #col3 varchar --missing a length here
set #col1='ID'
set #col2='COL_SPAU'+CONVERT(VARCHAR, #val)+'_EA'
set #col3='DateTime'
set #sql= 'select [ID], '+#col2+' FROM [DBRapBreaza].[dbo].[TblSPAU'+CONVERT(VARCHAR, #val)+ '] WHERE DateTime between '''+CONVERT(VARCHAR(25), #DataStart,121)+ ''' and '''+CONVERT(VARCHAR(25), #DataStop,121)+''';'
--print #sql;
EXEC sp_executesql
#sql,
N'#DataStart datetime, #DataStop datetime, #val int',
#DataStart, #DataStop, #val;
END
Of note, you didn't specify a length for #col1 or #col3 which would default to 8 so be careful there. You never used this variable, so I'm not sure what it's purpose is.
Am unable to insert record when given all the column names in insert
Below is the SP
ALTER PROCEDURE [dbo].[test]
#tab_name nvarchar(50),
#tab_id int,
#tab_n nvarchar(50),
#tab_q int
as
Begin
declare #sql as nvarchar(50);
declare #counts as int;
select #sql='select #cnt=count(*) from '+#tab_name+' where id='+cast(#tab_id as varchar)+';'
exec sp_executesql #sql,N'#cnt int output', #cnt=#counts output
select #counts as counts
if #counts=1
begin
declare #sql1 as nvarchar(50);
select #sql1='update '+#tab_name+' set quantity='+cast(#tab_q as varchar)+' where id='+cast(#tab_id as varchar)+';'
exec sp_executesql #sql1
end
else
begin
declare #sql2 as nvarchar(50);
set #sql2='insert into '+#tab_name+' (id,name,quantity) values ('+CAST(#tab_id as varchar)+','''+#tab_n+''''
set #sql2+=','+CAST(#tab_q as varchar)+');'
select #sql2
exec sp_executesql #sql2
end
End
"
command: exec dbo.test #tab_name='inventory',#tab_id=4,#tab_n='chiku',#tab_q=123
record gets inserted when column names are removed but does not work with column names during insert.
Please help.
Thanks
It is better to use A nvarchar(max) for dynamic queries with parameters.
Because u never know how long the string can be. unless you know the max lenght of the string.
A dba also told me to use N' as prefix before the string to denote Unicode string literals.
Increase #sql variables size like below:
declare #sql as nvarchar(max);
....
declare #sql1 as nvarchar(max);
...
declare #sql2 as nvarchar(max);
I have a problem with treating table name as variable as I need to put the results to different table each month automatically (without using any advanced procedures to make this query dynamic). Can somebody help me to modify this code and make it work?
declare #exp_dte as date;
set #exp_dte='2015-12-31';
print (#exp_dte);
declare #tab_mth as nvarchar(max);
set #tab_mth=year(#exp_dte)*100+month(#exp_dte);
print (#tab_mth);
declare #tab_name as nvarchar(max)
set #tab_name='mis_anl.dbo.BIK_' + #tab_mth
print (#tab_name);
IF OBJECT_ID (N'#tab_name', N'U') IS NOT NULL
begin
drop table #tab_name
end
select distinct
*
into #tab_name
from table_x
You have to use dynamic SQL to set name at runtime:
DECLARE #exp_dte DATE = '2015-12-31';
DECLARE #tab_name SYSNAME = '[dbo].' + QUOTENAME('BIK_' + FORMAT(#exp_dte, 'yyyyMM'));
IF OBJECT_ID (#tab_name, N'U') IS NOT NULL
BEGIN
EXEC('DROP TABLE' + #tab_name);
END
DECLARE #sql NVARCHAR(MAX) = N'SELECT DISTINCT *
INTO #tab_name
FROM table_x';
SET #sql = REPLACE(#sql, '#tab_name', #tab_name);
EXEC [dbo].[sp_executesql] #sql;
LiveDemo
Remarks:
Try to be more conscise
You could use FORMAT to get yyyyMM (SQL Server 2012+)
Always QUOTENAME generated identifiers to avoid SQL Injection attacks
I strongly recommend to read The Curse and Blessings of Dynamic SQL especially CREATE TABLE #tbl.
use dynamic sql ,you cant user table names as variables
declare #exp_dte as date;
set #exp_dte='2015-12-31';
declare #tab_mth as nvarchar(max);
set #tab_mth=year(#exp_dte)*100+month(#exp_dte);
declare #tab_name as nvarchar(max)
set #tab_name='mis_anl.dbo.BIK_' + #tab_mth
declare #sql1 nvarchar(max)
set #sql1='drop table '+#tab_name;
IF exists(select 1 from information_schema.tables where table_name=#tab_name)
begin
exec(#sql1);
end
declare #sql nvarchar(max)
set #sql='
select distinct
*
into '+#tab_name+'
from table_x'
exec (#sql)
I have a procedure with following code
CREATE PROCEDURE customer_panel_insert(
#Panel_Name VARCHAR(200),
#Panel_description VARCHAR(5000),
#Type_of_change CHAR(5))
AS
DECLARE #data_set VARCHAR(MAX);
DECLARE #sql VARCHAR(MAX);
begin
set #sql = 'select * from customer_details where panel_type = 1 AND PANEL_DATATYPE = ''VARCHAR'''
exec #sql
END
I want to change the varchar datatype to nvarchar and char to nchar. Change the varchar variable with size more than 4000 characters to NVARCHAR(MAX). I want to change with help of a query.
Is there any query that can replace
Hope this works for you. Be careful before executing it.
update sys.sql_modules set definition = REPLACE(definition,'VARCHAR(5000)','NVARCHAR(MAX)')
where definition like '%VARCHAR(5000)%'
I tried to create dynamic SQL using sp_executesql, but it gives me this error message:
Msg 137, Level 15, State 2, Line 20
Must declare the scalar variable "#start".
Here is my stored procedure script
CREATE PROCEDURE sp_test (#start datetime, #end datetime)
AS
BEGIN
DECLARE #sql nvarchar(MAX)
SET #sql = 'SELECT * FROM table1 WHERE '
SET #sql = #sql + N'startDate BETWEEN #start AND #end'
EXEC sp_executesql #sql
Any input will be appreciated.
The below T-SQL should take care of your problem. Although, I would not recommend prefixing your stored procedure name with "sp_" since the system stored procedures use this naming convention. You wouldn't want to have your stored procedures confused with system stored procedures, or worse, Microsoft decides to name one of their future system stored procedures with the name of yours.
Things to note:
You define/declare all the custom parameters that you want to pass into your dynamic SQL statement in the #ParameterDefinition variable.
You add each of your custom variables to the sp_executesql call as if they were already part of the procedure.
IF OBJECT_ID('sp_test', 'P') IS NOT NULL DROP PROCEDURE sp_test
GO
-- ============================================================================
-- CALLING EXAMPLE:
-- EXEC sp_test '01/01/1901', '01/02/1901'
-- ============================================================================
CREATE PROCEDURE sp_test (#start datetime, #end datetime)
AS
BEGIN
DECLARE #sql nvarchar(max)
SET #sql = 'SELECT * FROM table1 WHERE '
SET #sql = #sql + N'startDate BETWEEN #start AND #end'
-- Build the Parameter Definition list for the dynamic SQL statement below
DECLARE #ParameterDefinition nvarchar(1000);
SELECT #ParameterDefinition = ''
+ ' #start datetime'
+ ',#end datetime'
EXEC sp_executesql
#statement = #sql
,#params = #ParameterDefinition
-- Assign values to any of custom parameters defined in #ParameterDefinition:
,#start = #start
,#end = #end
END
GO