How to call sp_executesql from inside a multistatement TVF? - sql

I have created a function and when calling its giving this message.
Only functions and some extended stored procedures can be executed
from within a function.
The function is given below, when i am calling only logic so it is giving me result. When ever i came to execute the function it gives me error and not returning result.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
ALTER FUNCTION [getallparameterdetails]()
RETURNS #test TABLE
(
showboth nvarchar(20),
showonlycustomno nvarchar(50)
)
AS
-- Fill the table variable with the rows for your result set
begin
DECLARE #ListOWeekDays AS TABLE(DayAbb nVARCHAR(40) , WeekName nVARCHAR(40))
DECLARE #cols AS NVARCHAR(MAX)
DECLARE #query AS NVARCHAR(MAX)
DECLARE #rows AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(ParamCode)
from ec_ParameterDetail
group by ParamValue, ParamCode
order by 1
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = N'SELECT ' + #cols + N' from
(select ParamValue, ParamCode
from ec_ParameterDetail) x
pivot
(
max(ParamValue)
for ParamCode in (' + #cols + N')
) p '
exec sp_executesql #query;
return
end
its not executing, i am unable to get my desired result.

Related

Stored procedure with string as parameters not working -SQL

In my database 'Student_name' is set as varchar. And the stored procedure is:
ALTER PROCEDURE [dbo].[SP_STUDENT]
#STUDENT_NAME NVARCHAR(MAX),
AS
DECLARE
#columns NVARCHAR(MAX) = '',
#columnsname NVARCHAR(MAX) = '',
#columnsnameA NVARCHAR(MAX) = '',
#columnsB NVARCHAR(MAX) = '',
#columnsnameB NVARCHAR(MAX) = '',
#sql NVARCHAR(MAX) = '';
-- select the question num
SET #columns = STUFF((SELECT distinct ',' + QUOTENAME(cast(Question_no as varchar))
FROM submission1_details WHERE Submission1_id=100
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #columnsname = STUFF((SELECT distinct ',' + QUOTENAME(cast(Question_no as varchar)) + ' sub1_Q'+ cast(Question_no as varchar)
FROM submission1_details WHERE Submission1_id=100
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #columnsnameA = STUFF((SELECT distinct ','+' sub1_Q'+ cast(Question_no as varchar)
FROM submission1_details WHERE Submission1_id=100
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #columnsB = STUFF((SELECT distinct ',' + QUOTENAME(cast(Question_no as varchar))
FROM submission2_details WHERE Submission2_id=500
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #columnsnameB = STUFF((SELECT distinct ',' + QUOTENAME(cast(Question_no as varchar)) + ' sub2_Q'+ cast(Question_no as varchar)
FROM submission2_details WHERE Submission2_id=500
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
print #columns
SET #sql =N'
select Submission_id,DRA_submission_id,SubmittedOn,Driver,VehicleType,VehicleNo,Interval, '+#columnsnameB +','+ #columnsnameA+ ' from (
select Submission_id,DRA_submission_id,SubmittedOn,Driver ,VehicleType,'+#columnsname+',Question_no, Answer,VehicleNo,Interval from (
select distinct t1.Submission_id,t1.DRA_submission_id,t1.Submitted_time AS SubmittedOn,t1.Driver_id as Driver, dvc_vehicle_types.vehicle_type_name AS VehicleType,dvc_vehicles.Vehicle_RegNo AS VehicleNo,
dvc_checklist_intervals.Interval_description AS Interval,t2.Question_no t,t2.Answer A,t3.Question_no,t3.Answer from dvc_submission_header t1
inner JOIN dvc_submission_details t2 ON t1.Submission_id= t2.Submission_id
inner JOIN dvc_DRAsubmission_details t3 ON t1.DRA_submission_id=
t3.Submission_id INNER JOIN dvc_vehicles ON
t1.Vehicle_id=dvc_vehicles.Vehicle_id INNER JOIN dvc_vehicle_types ON
dvc_vehicles.Vehicle_type_id=dvc_vehicle_types.Vehicle_type_id
INNER JOIN dvc_checklist_intervals ON t1.Interval_id =
dvc_checklist_intervals.Interval_id
WHERE t1.Student_name= '+ #STUDENT_NAME +' ';
SET #sql +=N'
) as a
PIVOT(
MAX(A)
for t IN ('+ #columns +')
) AS pivot_table
) as b
PIVOT(
MAX(Answer)
for Question_no IN ('+ #columnsB +')
) AS pivot_table1;';
print #sql
-- execute the dynamic SQL
EXECUTE sp_executesql #sql;
And I have executed the stored procedure as below:
EXEC [SP_STUDENT] #STUDENT_NAME='Yuvan'
But it shows an error:
Conversion failed when converting the nvarchar value 'Yuvan' to data type int.
Please help to correct.
Do not concatenate string to build a statement. Use sp_executesql correctly and use parameters (if you really want to use a dynamic statement):
ALTER PROCEDURE [dbo].[SP_STUDENT]
#STUDENT_id NVARCHAR(MAX),
#STUDENT_name NVARCHAR(MAX),
#EXAM_date NVARCHAR(MAX)
AS
BEGIN
DECLARE
#sql nvarchar(max),
#err int
SET #sql =
N'SELECT * FROM student_details ' +
N'WHERE student_id = #STUDENT_id AND student_name = #STUDENT_name AND exam_date = #EXAM_date';
PRINT #sql
EXECUTE #err = sp_executesql
#sql,
N'#STUDENT_id NVARCHAR(MAX), #STUDENT_name NVARCHAR(MAX), #EXAM_date NVARCHAR(MAX)',
#STUDENT_id, #STUDENT_name, #EXAM_date
RETURN (#err)
END
Notes:
Define parameters data types carefully. Using nvarchar(max) is not needed. Use the appropriate data type, based on the columns data types.
Pass datetime values using an unambiguous datetime format
If possibe, use simple SELECT statement:
ALTER PROCEDURE [dbo].[SP_STUDENT]
#STUDENT_id NVARCHAR(MAX),
#STUDENT_name NVARCHAR(MAX),
#EXAM_date NVARCHAR(MAX)
AS
BEGIN
SELECT *
FROM student_details
WHERE
student_id = #STUDENT_id AND
student_name = #STUDENT_name AND
exam_date = #EXAM_date
END

Passing a variable out of a SQL query

Is it possible to pass a variable out of a SQL query?
I am building up the initial query using a variable. I have added a simplified subset of my query below.
Thanks
declare #query Nvarchar(max)
declare #ColumnName Nvarchar(max)
set #ColumnName = 'MyColumn'
SET #query = 'Select ' + #ColumnName + ' from [MyTable] WHERE [MyCondition]'
EXECUTE sp_executesql #query
Can I return this result as a variable to pass to another query?
Yes. You use an output parameter:
declare #query Nvarchar(max);
declare #ColumnName Nvarchar(max);
declare #outval <type>; -- whatever type
set #ColumnName = 'MyColumn'
set #query = 'Select #outval =' + #ColumnName + ' from [MyTable] where [MyCondition]';
execut sp_executesql #query,
N'#outval <type> output',
#outval = #outval output;
Store the results in table variable and then convert it into XML.
Declare #xml XML
declare #query Nvarchar(max)
declare #ColumnName Nvarchar(max)
set #ColumnName = 'MyColumn'
declare #Table as TABLE(
MyColumn varchar(Max)-- Your Column datatype
)
SET #query = 'Select ' + #ColumnName + ' from [MyTable] WHERE [MyCondition]'
INSERT INTO #Table
EXECUTE sp_executesql #query
select #xml=MyColumn from #Table for XML PATH('')
How you want to pass returned result to other query?
What i can think of create a function return a table and call that function on other query:
CREATE FUNCTION test (#id int)
RETURNS #testTable TABLE(id int)
AS
begin
insert into #testTable select id from #your_table where id = #id
return
end
This will return a table you can check using :
select * from test(2); --will give you a table
If you want to use in a query:
`select * from #second_table where id in (select * from test2(#id parameter))` --- will filter query by id returned by function.

SQL add a variable to a query

How do I create variables that are specified once and then used in queries later in a script? These variables may be used multiple times in a query, and in multiple queries in a script. I use #x as such a variable in the examples below.
What I want to do is something like:
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name]
, ' + #x + ' as [TestCase]
From mytable'
Exec (#Query)
-- returns "Invalid column name 'test'"
Which returns the error mentioned above. I would like it to achieve the equivalent of:
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name]
, ''test'' as [TestCase]
From mytable'
Exec (#Query)
-- Returns e.g.
-- Name TestCase
-- Alice Test
-- Bob Test
I also note that the following doesn't work and returns the same error as the first:
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name]
, ' + 'test' + ' as [TestCase]
From mytable'
Exec (#Query)
-- returns "Invalid column name 'test'"
Based on the error and since I'm not trying to use the #x as a column name, but just as a variable, I assume I'm using an invalid implementation of a variable.
Since you're not trying to use a variable as a column name, you do not need to use dynamic SQL at all. (Which is a Good Thing(TM) since dynamic SQL should only be used with a great deal of caution due to it being a great attack surface.)
A simple:
declare #x nvarchar(40)
set #x = 'test'
select [Name], #x as TestCase
from mytable
will do.
That being said, if you have a use case for dynamic SQL (again the particular query in question here does not but perhaps an ad-hoc query is being passed in to the procedure), the thing to do would be to pass your variable as a parameter to the query via sp_executesql. This is akin to creating a stored procedure with parameters:
declare #x nvarchar(40)
declare #query nvarchar(1000)
set #x = 'test'
set #query = 'select [Name], #x as TestCase from mytable'
exec sp_executesql #query, N'#x nvarchar(1000)', #x
You were missing quotes. Thats it. Try below code.
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name]
, ''' + #x + ''' as [TestCase]
From mytable'
Exec (#Query)
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name],'++''''+#x+''''+ ' as [TestCase]
From mytable'
print #query
Output:
Select [Name],'test' as [TestCase]
From mytable

Substitute Column name in dynamic queries

I have a procedure , in which i am receiving a parameter column name and creating the dynamic query by substituting column name.
when i am directly running this dynamic query its working fine.
declare #a datetime,
#b varchar(50) ='CREATED_DATE',--column name
#query varchar(500);
select #a= CONVERT(datetime,LAST_RUN_PROC,121) from TEST_TABLE_MASTER
exec( 'select '+#b+' from TEST1 where '+#b+' = '+''''+#a+'''' )
But when i am storing query in a variable and then executing,its showing error.
Below code showing error
declare #a datetime,
#b varchar(50) ='CREATED_DATE',--column name
#query varchar(500);
select #a= CONVERT(datetime,LAST_RUN_PROC,121) from TEST_TABLE_MASTER
SET #query= 'select '+#b+' from TEST1 where '+#b+' = '+''''+#a+'''' --this line showing error Conversion failed when converting date and/or time from character string.
exec (#query)
I got stuck here.please help
Concatenating SQL string is not the best idea, because of multiple '''' needed. It is error-prone and hard to debug.
Use correct types (table name, column name) - SYSNAME, query -NVARCHAR(MAX).
You can use REPLACE placeholder to fill values or pass them as parameter to EXEC dbo.sp_executesql.
Always quote table/column names.
SELECT #a= CONVERT(datetime, LAST_RUN_PROC,121) FROM TEST_TABLE_MASTER; will set #a last read value from table, you should add TOP 1 and ORDER BY.
Code:
DECLARE #a DATETIME,
#b SYSNAME ='CREATED_DATE',
#query NVARCHAR(MAX);
SELECT #a= CONVERT(datetime, LAST_RUN_PROC,121) FROM TEST_TABLE_MASTER;
SET #query =
N'SELECT <col_name>
FROM TEST1
WHERE <col_name> = ''<col_value>'';';
SET #query = REPLACE(#query, '<col_name>', QUOTENAME(#b));
SET #query = REPLACE(#query, '<col_value>', #a);
--SELECT #query;
EXEC [dbo].[sp_executesql]
#query;
SqlFiddleDemo
Recommended version with parameter passing and dbo.sp_executesql instead of EXEC:
DECLARE #a DATETIME,
#b SYSNAME ='CREATED_DATE',
#query NVARCHAR(MAX);
SELECT #a= LAST_RUN_PROC FROM TEST_TABLE_MASTER;
SET #query =
N'SELECT <col_name>
FROM TEST1
WHERE <col_name> = #a;';
SET #query = REPLACE(#query, '<col_name>', QUOTENAME(#b));
EXEC [dbo].[sp_executesql]
#query
,N'#a DATETIME'
,#a;
SqlFiddleDemo2
Warning:
Using Dynamic-SQL is great resposibility. If you don't understand it, don't use Dynamic-SQL at all.
EDIT:
I've managed to run your example, but I strongly recommend to use one of the solution above:
SET #query= 'select '+#b+' from TEST1 where '+#b+' = '+''''+CONVERT(varchar(19),#a, 121)+''''
SqlFiddleDemo3

while passing parameter in stored procedure getting error

alter procedure [dbo].[ParkingDeatailsReport]
as
begin
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#locid INTEGER
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(Vtype)
from VType_tbl
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
set #query = 'SELECT Date, ' + #cols + '
from
(
select v.Vtype, convert(date, dtime) as Date
from Transaction_tbl t
inner join VType_tbl v on t.vtid = v.vtid
where locid = ' + CAST(#locid as varchar(max)) + ') d
pivot
(
count(Vtype)
for Vtype in (' + #cols + ')
) p '
execute(#query)
end
Notice the difference between #cols and #locid in dynamic SQL.
Replace
where locid = #locid
With
where locid = ' + CAST(#locid as varchar(max)) + '
Note: while this is a quick fix please see answer from RBarryYoung for best practice with dynamic SQL.
the error clearly say, your current SP code not accepting any parameters and you trying to pas parameters to SP. if you want to accept parameters in SP, syntax is:
Create Procedure Procedure-name
(
Input parameters ,
Output Parameters (If required)
)
As
Begin
Sql statement used in the stored procedure
End
So in your case SP can be change to :
alter procedure [dbo].[ParkingDeatailsReport]
(
#cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#locid INTEGER
)
as
begin
..... you code go hear
END