SQL Store nvarchar(max) from temp table to sql_variant - sql

How can I check if a column in a temp table is nvarchar(max) and if so convert it or cast it to nvarchar(4000) so I can store it in sql_variant?
Here is the part of the code where #audit_oldvalue is sql_variant and #Item from #tempTrigT is nvarchar(max):
set #sql = 'select #audit_oldvalue=[' +#Item +'] from #tempTrigT';
EXEC SP_EXECUTESQL #sql,N'#audit_oldvalue sql_variant OUTPUT',#audit_oldvalue OUTPUT
#tempTrigT:
Select * into #tempTrigT from (select * from deleted where #Action in ( 'U','D')) A UNION (select * from inserted where #Action ='I')

set #sql = 'set #audit_oldvalue=(select cast([' +#Item +'] as NVARCHAR(4000)) from #tempTrigT)';
EXEC SP_EXECUTESQL #sql,N'#audit_oldvalue sql_variant OUTPUT',#audit_oldvalue OUTPUT

Just cast the NVARCHAR(MAX) to NVARCHAR(4000) before casting to SQL_VARIANT.
DECLARE #String NVARCHAR(MAX) = N'test string';
SELECT CAST(#String AS SQL_VARIANT); --fail
SELECT CAST(CAST(#String AS NVARCHAR(4000)) AS SQL_VARIANT); -- success

Related

How to get dynamic SQL query output into declared variable in SQL Server? [duplicate]

I have a piece of dynamic SQL I need to execute, I then need to store the result into a variable.
I know I can use sp_executesql but can't find clear examples around about how to do this.
If you have OUTPUT parameters you can do
DECLARE #retval int
DECLARE #sSQL nvarchar(500);
DECLARE #ParmDefinition nvarchar(500);
DECLARE #tablename nvarchar(50)
SELECT #tablename = N'products'
SELECT #sSQL = N'SELECT #retvalOUT = MAX(ID) FROM ' + #tablename;
SET #ParmDefinition = N'#retvalOUT int OUTPUT';
EXEC sp_executesql #sSQL, #ParmDefinition, #retvalOUT=#retval OUTPUT;
SELECT #retval;
But if you don't, and can not modify the SP:
-- Assuming that your SP return 1 value
create table #temptable (ID int null)
insert into #temptable exec mysp 'Value1', 'Value2'
select * from #temptable
Not pretty, but works.
DECLARE #vi INT
DECLARE #vQuery NVARCHAR(1000)
SET #vQuery = N'SELECT #vi= COUNT(*) FROM <TableName>'
EXEC SP_EXECUTESQL
#Query = #vQuery
, #Params = N'#vi INT OUTPUT'
, #vi = #vi OUTPUT
SELECT #vi
DECLARE #tab AS TABLE (col1 VARCHAR(10), col2 varchar(10))
INSERT into #tab EXECUTE sp_executesql N'
SELECT 1 AS col1, 2 AS col2
UNION ALL
SELECT 1 AS col1, 2 AS col2
UNION ALL
SELECT 1 AS col1, 2 AS col2'
SELECT * FROM #tab
Return values are generally not used to "return" a result but to return success (0) or an error number (1-65K). The above all seem to indicate that sp_executesql does not return a value, which is not correct. sp_executesql will return 0 for success and any other number for failure.
In the below, #i will return 2727
DECLARE #s NVARCHAR(500)
DECLARE #i INT;
SET #s = 'USE [Blah]; UPDATE STATISTICS [dbo].[TableName] [NonExistantStatisticsName];';
EXEC #i = sys.sp_executesql #s
SELECT #i AS 'Blah'
SSMS will show this
Msg 2727, Level 11, State 1, Line 1
Cannot find index 'NonExistantStaticsName'.
If you want to return more than 1 value use this:
DECLARE #sqlstatement2 NVARCHAR(MAX);
DECLARE #retText NVARCHAR(MAX);
DECLARE #ParmDefinition NVARCHAR(MAX);
DECLARE #retIndex INT = 0;
SELECT #sqlstatement = 'SELECT #retIndexOUT=column1 #retTextOUT=column2 FROM XXX WHERE bla bla';
SET #ParmDefinition = N'#retIndexOUT INT OUTPUT, #retTextOUT NVARCHAR(MAX) OUTPUT';
exec sp_executesql #sqlstatement, #ParmDefinition, #retIndexOUT=#retIndex OUTPUT, #retTextOUT=#retText OUTPUT;
returned values are in #retIndex and #retText
Declare #variable int
Exec #variable = proc_name
DECLARE #ValueTable TABLE
(
Value VARCHAR (100)
)
SELECT #sql = N'SELECT SRS_SizeSetDetails.'+#COLUMN_NAME+' FROM SRS_SizeSetDetails WHERE FSizeID = '''+#FSizeID+''' AND SRS_SizeSetID = '''+#SRS_SizeSetID+'''';
INSERT INTO #ValueTable
EXEC sp_executesql #sql;
SET #Value='';
SET #Value = (SELECT TOP 1 Value FROM #ValueTable)
DELETE FROM #ValueTable
This worked for me:
DECLARE #SQL NVARCHAR(4000)
DECLARE #tbl Table (
Id int,
Account varchar(50),
Amount int
)
-- Lots of code to Create my dynamic sql statement
insert into #tbl EXEC sp_executesql #SQL
select * from #tbl
Here's something you can try
DECLARE #SqlStatement NVARCHAR(MAX) = ''
,#result XML
,#DatabaseName VARCHAR(100)
,#SchemaName VARCHAR(10)
,#ObjectName VARCHAR(200);
SELECT #DatabaseName = 'some database'
,#SchemaName = 'some schema'
,#ObjectName = 'some object (Table/View)'
SET #SqlStatement = '
SELECT #result = CONVERT(XML,
STUFF( ( SELECT *
FROM
(
SELECT TOP(100)
*
FROM ' + QUOTENAME(#DatabaseName) +'.'+ QUOTENAME(#SchemaName) +'.' + QUOTENAME(#ObjectName) + '
) AS A1
FOR XML PATH(''row''), ELEMENTS, ROOT(''recordset'')
), 1, 0, '''')
)
';
EXEC sp_executesql #SqlStatement,N'#result XML OUTPUT', #result = #result OUTPUT;
SELECT DISTINCT
QUOTENAME(r.value('fn:local-name(.)', 'VARCHAR(200)')) AS ColumnName
FROM #result.nodes('//recordset/*/*') AS records(r)
ORDER BY ColumnName
This was a long time ago, so not sure if this is still needed, but you could use ##ROWCOUNT variable to see how many rows were affected with the previous sql statement.
This is helpful when for example you construct a dynamic Update statement and run it with exec. ##ROWCOUNT would show how many rows were updated.
Here is the definition

Convert column values into string

I'm trying to write e proc which will convert column values into a string separated with a character: ',' for example.
it stucks on this line exec #maxcount = sp_executesql #temp and returns the value of #maxxount any suggestions how could I set a value of dynamic query execution so that it continued processing all the function an executed the correct answer.
ALTER procedure [dbo].[usp_stringConvert](
#table_name varchar(101),
#column_name varchar(100),
#separator varchar(20)
)
as
declare #maxcount int, #temp nvarchar(1000)
declare #count int
declare #result varchar(1000)
set #result =''
set #count =1
set #temp= Concat('select count(', #column_Name ,') from ', #table_name)
exec #maxcount = sp_executesql #temp
while (#count<#maxcount)
begin
if #count!=1
set #result+=#separator
set #temp=Concat('select ' , #column_name ,' from ' , #table_name , 'where #count = row_number() over(order by (select (100)))')
exec #temp = sp_executesql #temp
set #result =CONCAT(#result, #temp)
set #count+=1;
end
select #result;
Using regular SQL in SQL Server, you can concatenate strings using:
select stuff( (select concat(separator, column_name)
from table_name
for xml path ('', type)
).value('.', nvarchar(max)
), 1, len(separator), ''
)
You should be able to turn this into dynamic SQL using:
declare #sql nvarchar(max);
declare #result nvarchar(max);
set #sql = N'
select #result = stuff( (select concat(#separator + [column_name]
from [table_name]
for xml path ('''', type)
).value(''.'', nvarchar(max)
), 1, len(#separator), ''
)
';
set #sql = replace(#sql, '[table_name]', quotename(#table_name));
set #sql = replace(#sql, '[column_name]', quotename(#column_name));
exec sp_executesql #sql,
N'#result nvarchar(max) output',
#result=#result output;
select #result;

Sql multiple file import

I want to insert multiple csv file to sqlserver table. I have a procedure for doing that. It works but my all files have same column name. So instead of importing all records it just imports column name which is the first row. If I manually delete first row then it imports the other records, I have thousands of files so I cant work manually. I am posting store procedure here. Please tell me if I can change something to make this work.
ALTER procedure [dbo].[usp_ImportMultipleFiles] #filepath varchar(500),
#pattern varchar(100), #TableName varchar(128)
as
set quoted_identifier off
declare #query varchar(1000)
declare #max1 int
declare #count1 int
Declare #filename varchar(100)
set #count1 =0
create table #x (name varchar(200))
set #query ='master.dbo.xp_cmdshell "dir '+#filepath+#pattern +' /b"'
insert #x exec (#query)
delete from #x where name is NULL
select identity(int,1,1) as ID, name into #y from #x
drop table #x
set #max1 = (select max(ID) from #y)
--print #max1
--print #count1
While #count1 <= #max1
begin
set #count1=#count1+1
set #filename = (select name from #y where [id] = #count1)
set #Query ='BULK INSERT '+ #Tablename + ' FROM '''+ #Filepath+#Filename+'''
WITH ( FIELDTERMINATOR = '','',ROWTERMINATOR = ''\n'')'
--print #query
exec (#query)
insert into logtable (query) select #query
end
drop table #y
You can use the First Row option in your bulk insert statement something like...
BULK INSERT Table_Name
FROM 'C:\FilePath'
WITH
(
FIELDTERMINATOR = ','
,ROWTERMINATOR = '\n'
,FIRSTROW = 2 --<-- This option here
)
Edit to your proc
DECLARE #Query NVARCHAR(MAX);
SET #Query = N'BULK INSERT '+ #Tablename +
N' FROM '''+ #Filepath+#Filename +
N''' WITH ( FIELDTERMINATOR = '',''
,ROWTERMINATOR = ''\n''
,FIRSTROW = 2
)'

How to use Pass comma separated string in dynamic query in SQL

I have a function which will return integer values from comma delimited string , It takes two parameters (#string nvarchar(4000), #delimiter char(1)). So the problem is if I am using this function inside a dynamic query I am getting error , here is query
declare #ProductIDs varchar(11)
declare #SQL varchar(max)
set #ProductIDs='1,2,3,4'
declare #query varchar(max)
--set #query= #ProductIDs +','+#Delimiter
SELECT #SQL = 'SELECT val FROM dbo.[fnDelimitedStringToTable]('+ #ProductIDs +' , '','')'
Exec(#SQL)
I am getting error Procedure or function dbo.fnDelimitedStringToTable has too many arguments specified.
When you build a dynamic SQL like that, you need to wrap your parameter in double quote ''
declare #ProductIDs varchar(11)
declare #SQL varchar(max)
set #ProductIDs='1,2,3,4'
declare #query varchar(max)
--set #query= #ProductIDs +','+#Delimiter
SELECT #SQL = 'SELECT val FROM dbo.[fnDelimitedStringToTable]('''+ #ProductIDs +''' , '','')'
Exec(#SQL)
This way the SQL statement will be:
SELECT val FROM dbo.[fnDelimitedStringToTable]('1,2,3,4' , '','')
and not:
SELECT val FROM dbo.[fnDelimitedStringToTable](1,2,3,4 , '','')
Use sp_executesql instead. In this case you can pass arguments as parameters.
DECLARE #SQL nvarchar(max)
DECLARE #ParmDef nvarchar(1000)
DECLARE #ArgProductIDs nvarchar(100)
DECLARE #Arg2 nvarchar(100)
DECLARE #Arg3 nvarchar(100)
SET #SQL = N'SELECT val
FROM dbo.[fnDelimitedStringToTable](#ProductIDs, #Param2, #Param3)';
SET #ParmDef = N'#ProductIDs nvarchar(100),
#Param2 nvarchar(100),
#Param3 nvarchar(100)';
SET #Arg1 = N'1,2,3,4';
SET #Arg2 = N'';
SET #Arg3 = N'';
EXEC sp_executesql #SQL, #ParmDef,
#ProductIDs = #ArgProductIDs, #Param2 = #Arg2, , #Param3 = #Arg3

How to store results of dynamic SQL into a variable

is there a way to store the results of an exec statement in a varchar?
DECLARE #TableName varchar(100)
DECLARE #ExecStatement varchar(max)
DECLARE #PromotionXML varchar(max)
SET #TableName = 'Feeds'
Set #ExecStatement = (
'
SET #PromotionXML = (
SELECT
*
FROM
' + #TableName + ' for xml auto, elements
)'
)
exec #ExecStatement
select #PromotionXML
You need to use sp_executesql, not EXEC, since you need to treat the inner variable as an output parameter (which you can't do with EXEC). Also all of these parameters should be NVARCHAR, not VARCHAR (though I'm curious why you aren't returning the xml as XML).
DECLARE
#TableName NVARCHAR(512),
#sql NVARCHAR(MAX),
#xml NVARCHAR(MAX);
SET #TableName = N'dbo.Feeds';
SET #sql = N'SELECT #xml = CONVERT(NVARCHAR(MAX), (
SELECT * FROM ' + #TableName + ' FOR XML AUTO, ELEMENTS));';
EXEC sp_executesql #sql, N'#xml NVARCHAR(MAX) OUTPUT', #xml OUTPUT;
SELECT #xml;