EXEC works with value of variable, but not variable itself - sql

I'm attempting to run a series of dynamically created sql statements that are stored in a table through exec statements. While troubleshooting, I've simplified the process down to just attempting a single statement, and I've encountered a problem I'm not quite sure how to make sense of.
Essentially, I have a declared nvarchar(max) variable, #str_query. It's initialized with a valid sql select statement from my table of statements. Trying exec(#str_query) returns an 'Incorrect Syntax" error (message 102), and proceeds to list the statement in string form. When I print(#str_query) and copy the same line into exec(), however, it works as expected. I then made a separate nvarchar(max) variable #test_var and set it explicitly to that same string. Running exec(#test_var) works as expected, running the sql statement stored in the string. Setting #test_var to #str_query and then running exec(#test_var) also produces the error.
Basically, exec() is working with the explicit value of the variable, but not with the variable itself, despite the value of the variable being a static string coming out of a table. Any help would be appreciated to get it to work with the variable. Thanks!
Code below:
DECLARE #Queries TABLE (ID INT IDENTITY(1,1), ColumnName VARCHAR(100), TableName VARCHAR(100),SQLScript VARCHAR(MAX))
DECLARE #Results TABLE (TableName VARCHAR(100), ColumnName VARCHAR(100), Result VARCHAR(MAX))
DECLARE #STR_QUERY NVARCHAR(MAX)
DECLARE #StartLoop INT
DECLARE #EndLoop INT
declare #searchValue varchar(max)
set #searchValue = 'search'
DECLARE #searchColumn VARCHAR(MAX)
set #searchColumn = 'addr_line_1'
INSERT INTO #Queries(ColumnName,TableName,SQLScript)
SELECT
COLUMN_NAME AS 'ColumnName'
, TABLE_NAME AS 'TableName'
, 'select '''''+TABLE_NAME+''''' as ''''TABLENAME'''','''''+COLUMN_NAME+''''' as ''''COLUMNNAME'''','+COLUMN_NAME+' as ''''RESULT'''' from '+TABLE_NAME+' where '+COLUMN_NAME+' like ''''%'+#searchValue+'%''''' as 'Statement'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE COLUMN_NAME LIKE '%'+#searchColumn+'%'
SELECT #EndLoop = MAX(ID), #StartLoop = MIN(ID)
FROM #Queries
set #STR_QUERY = (SELECT top(1) SQLScript FROM #Queries WHERE ID = #StartLoop)
set #STR_QUERY = ''''+#STR_QUERY+''''
print(#STR_QUERY) -- prints 'select ''Table1'' as ''TABLENAME'',''ADDR_LINE_1'' as ''COLUMNNAME'',ADDR_LINE_1 as ''RESULT'' from Table1 where ADDR_LINE_1 like ''%search%'''
exec('select ''Table1'' as ''TABLENAME'',''ADDR_LINE_1'' as ''COLUMNNAME'',ADDR_LINE_1 as ''RESULT'' from Table1 where ADDR_LINE_1 like ''%search%''') --works
exec(#STR_QUERY) -- error
declare #test_var nvarchar(max)
set #test_var = 'select ''Table1'' as ''TABLENAME'',''ADDR_LINE_1'' as ''COLUMNNAME'',ADDR_LINE_1 as ''RESULT'' from Table1 where ADDR_LINE_1 like ''%search%'''
exec(#test_var) -- works
set #test_var = #STR_QUERY
exec(#test_var) --error

Related

How to use table as variable in stored procedure

There is this query that I keep using over and over:
SELECT column_name, count(column_name) FROM table_name GROUP by column_name ORDER BY COUNT(column_name) DESC
I use this to check which different values there are in a column and how often they occur.
Because I use this query so often and it's repeating the same 4 times: column_name, I was like: why not make a stored procedure:
CREATE PROCEDURE countcv #table_name VARCHAR(50),#column_name VARCHAR(50)
AS
BEGIN
SELECT #column_name,COUNT(#column_name) FROM #table_name GROUP BY #column_name ORDER BY COUNT(#column_name)
END
Here is where I get stuck, I can not manage to get a variable tablename:
Must declare the table variable "#table_name"
I believe that #Julien Vavasseur and #Dark Knight has already addressed to your question.
However, I would like to add here that, Sql Server 2008 introduced Table-Valued Parameter by using which we can pass table type variable to the stored procedures. e.g.
Assuming you have a table by the name tblTest with the below columns
ID INT,
Name VARCHAR(50)
Step 1: Declare a new table User Defined Type
CREATE TYPE tblTestType AS TABLE
(
ID INT,
Name VARCHAR(50)
)
Step 2: Create a STORED PROCEDURE that has tblTestType as parameter
CREATE PROCEDURE countcv
(
#tblName tblTestType readonly
)
AS
INSERT INTO tblTest (ID, Name)
SELECT ID, Name
FROM
#tblName;
Then you can use DataTable (if you are using C#) and pass this data table as a parameter to the Stored Procedure.(you can find an example in the link I provided).
There is no way to do it directly. You need to use dynamicSQL approach. Assuming you pass correct table and column names. Below one should work.
CREATE PROCEDURE countcv #table_name VARCHAR(50),#column_name VARCHAR(50)
AS
BEGIN
declare #SQL nvarchar(max)
set #SQL = 'SELECT '+#column_name+',COUNT('+#column_name+')
FROM '+#table_name+'
GROUP BY '+#column_name+'
ORDER BY COUNT('+#column_name+')'
EXEC sp_executesql #SQL
END
If you want to do something like this, you must use dynamic SQL:
CREATE PROCEDURE countcv #table_name sysname, #column_name sysname
AS
BEGIN
Declare #sql nvarchar(max)
Set #sql = 'SELECT ' + QUOTENAME(#column_name)+', COUNT(' + QUOTENAME(#column_name)+')
FROM ' + QUOTENAME(#table_name)+'
GROUP BY ' + QUOTENAME(#column_name)+' ORDER BY COUNT(' + QUOTENAME(#column_name)+')'
EXEC sp_executesql #sql
END
Use sysname for data type for column and table names (buitin datatype for object names, alias to nvarchar(128))
Use QUOTENAME to add delimeter to column and table names

Is it possible in a Sybase SQL query to substitute a string variable for the where clause?

I have two stored procedures that have different input signatures, but are otherwise identical and would like to consolidate them. I tried to simulate "overloading" the signature and then just testing which input variable is null to appropriately set the final where clause. I haven't figured out how to de-reference the string literal.
Procedures:
CREATE PROCEDURE get_providers (#p_id bigint)
SELECT
...
WHERE p.p_id = #p_id
CREATE PROCEDURE get_providers (#ssn varchar(9))
SELECT
...
WHERE p.ssn = #ssn
Trying to add this logic to set a dynamic WHERE clause:
CREATE PROCEDURE get_providers (#ssn varchar(9), #p_id bigint)
DECLARE #clause varchar(100);
SELECT clause = 'p.p_id = #provider_id';
IF #ssn is null
select clause = 'p.ssn = #ssn';
SELECT
...
WHERE #clause
Output:
ERROR: SQL Anywhere Error -131: Syntax error near '(end of line)'
on line 50 Error Code: 102
(note: line 50 is "WHERE #clause")
You can construct a complete query string and execute it Here is an example
declare #sql nvarchar(max);
select #sql = '
select . . .
from . ..
#whereclause';
select #sql = replace(#sql, '#whereclause', coalesce('where ' + #clause, ''));
exec(#sql);
You can't have just one part of the query be a string.
You're mixing up Watcom SQL and T-SQL. Both are supported by SA but you cannot mix them.
The following both work:
-- Watcom
begin
declare #c varchar(25);
set #c = "select ##version";
execute immediate #c;
end;
-- T-SQL
declare #c varchar(25)
set #c = "select ##version"
execute(#c)

How to access a database given a string of its name

Alright so say I have code that looks like this.
CREATE Table database_info
(
DBName NVARCHAR (MAX)
);
INSERT INTO database_info (DBName)
VALUES ('db1')
SELECT * FROM database_info
DECLARE #temp nvarchar(MAX)
SET #temp = (SELECT DBName FROM database_info where database_info.DBName = 'db1')
--How I want it to work SELECT * FROM #temp
Is there any kind of operation I could do on this temporary variable to have the string act as a regular SQL command?
Thanks
You may execute a dynamic sql using EXEC. Now, declaring the #sql variable would be quite too much in this case, but it is useful when you are not sure of the length of the statement you will pass to it.
DECLARE #sql AS VARCHAR(MAX)
SET #sql = 'SELECT * FROM ' + #temp
EXEC(#sql)

Conversion failed when converting the nvarchar value ... to data type int

I created the procedure listed below:
CREATE procedure getdata
(
#ID int,
#frm varchar(250),
#to varchar(250)
)
AS
BEGIN
DECLARE #SQL nvarchar(500)
set #SQL = 'select'
set #SQL = #SQL + ' EmpName, Address, Salary from Emp_Tb where 1=1 '
IF (#ID <> '' and #ID is not null)
Begin
SET #sql=#sql+' AND Emp_Id_Pk=' +#ID
End
END
print #sql
--execute (#sql)
I try to execute it using:
**execute getdata 3,'','';**
But I'm getting the following error:
Conversion failed when converting the nvarchar value 'select EmpName,
Address, Salary from Emp_Tb where 1=1 AND Emp_Id_Pk=' to data type int
Please help.
You are trying to concatenate a string and an integer.
You need to cast #ID as a string.
try:
SET #sql=#sql+' AND Emp_Id_Pk=' + CAST(#ID AS NVARCHAR(10))
Try Using
CONVERT(nvarchar(10),#ID)
This is similar to cast but is less expensive(in terms of time consumed)
I was using a KEY word for one of my columns and I solved it with brackets []
I use the latest version of SSMS or sql server management studio. I have a SQL script (in query editor) which has about 100 lines of code. This is error I got in the query:
Msg 245, Level 16, State 1, Line 2
Conversion failed when converting the nvarchar value 'abcd' to data type int.
Solution - I had seen this kind of error before when I forgot to enclose a number (in varchar column) in single quotes.
As an aside, the error message is misleading. The actual error on line number 70 in the query editor and not line 2 as the error says!
don't use string concatenation to produce sql, you can use sp_executesql system stored prcedure to execute sql statement with parameters
create procedure getdata #ID int, #frm varchar(250), #to varchar(250) as
begin
declare #sql nvarchar(max), #paramDefs nvarchar(max);
set nocount on;
set #sql = N'select EmpName, Address, Salary from Emp_Tb where #id is null or Emp_Id_Pk = #id';
set #paramDefs = N'#id int';
execute sp_executesql #sql, #paramDefs, #id = #ID;
end
see sp_executesql
I got this error when I used a where clause which looked at a nvarchar field but didn't use single quotes.
My invalid SQL query looked like this:
SELECT * FROM RandomTable WHERE Id IN (SELECT Id FROM RandomTable WHERE [Number] = 13028533)
This didn't work since the Number column had the data type nvarchar. It wasn't an int as I first thought.
I changed it to:
SELECT * FROM RandomTable WHERE Id IN (SELECT Id FROM RandomTable WHERE [Number] = '13028533')
And it worked.
You got this Error because you tried to convert column DataType from String to int which is
leagal if and only if
you dont have row in that table with string content inside that column
so just make sure your previously inserted Rows is compatible with the new changes
I have faced to the same problem, i deleted the constraint for the column in question and it worked for me. You can check the folder Constraints.
Capture :
You must use CONCAT and not the +
SET #sql = CONCAT(#sql,' AND Emp_Id_Pk=' ,#ID )

Using a variable through a Query located in a table

Basically I have a procedure that is supposed to take queries from a table and run them. This works fine except when I try to define a variable in the procedure that is referenced in the query. I simply define the variable using:
DECLARE #spcode as varchar(255)
SET #spcode = 'C'
And then in the table I reference it here:
...
where sp_flag = #spcode
...
My procedure then runs through the table and executes all of the queries in the table, this works if I simply set sp_flag = 'C', but if I try to set it to the variable defined in the procedure I get the following error:
Msg 137, Level 15, State 2, Line 7
Must declare the scalar variable "#spcode".
I have searched around but I have not been able to find a solution to this problem, perhaps someone has an idea of how I would go about fixing this problem?
Thanks,
Sam
Look at this example.
First snippet execute SQL statement without using variable. Second with.
create table tbl1 (id int identity(1,1), value varchar(100));
insert into tbl1 (value) values ('abc'), ('def'), ('xyz');
-- first snippet (without using variable)
declare
#sql varchar(max);
set #sql = 'select * from tbl1 where value = ''abc''';
exec(#sql);
-- second snippet (with variable)
declare
#sql nvarchar(max),
#param nvarchar(100);
set #param = N'#val varchar(100)'
set #sql = N'select * from tbl1 where value = #val';
exec sp_executesql #sql, #param, #val = 'abc';