Use stored proc parameters in Select dynamic SQL - dynamic-sql

This question may sound stupid... but hey ! I can't find the answer ! lol!!
I have this query that I need to convert to dynamic query:
INSERT INTO [SurveyInterface].[tblCEProcessingWorkingLCPSUF](
ParentId,
OperatingEntityNumber,
SurveyGroupCodeId,
ReferencePeriod,
SurveyCodeId,
StructureLevel )
SELECT ParentId,
RealOperatingEntityNumber AS OperatingEntityNumber,
'71' AS SurveyGroupCodeId,
'201906' AS ReferencePeriod,
'ZM' AS SurveyCodeId,
StructureLevel
FROM dbo.tblSUFGeneric201906
WHERE ParentId <> RealOperatingEntityNumber;
It looks so simple !
DECLARE #InputSurveyGroupCodeId INT = 71
,#InputReferencePeriod VARCHAR(6) = '201906'
,#InputSurveyCodeId VARCHAR(2) = 'ZM'
EXEC ('INSERT INTO [SurveyInterface].[tblCEProcessingWorkingLCPSUF](
ParentId,
OperatingEntityNumber,
SurveyGroupCodeId,
ReferencePeriod,
SurveyCodeId,
StructureLevel )
SELECT ParentId,
RealOperatingEntityNumber AS OperatingEntityNumber,
' + #InputSurveyGroupCodeId + ' AS SurveyGroupCodeId,
' + #InputReferencePeriod + ' AS ReferencePeriod,
' + #InputSurveyCodeId + ' AS SurveyCodeId,
StructureLevel
FROM ' + #InputSUFFrameTable + '
WHERE ParentId <> RealOperatingEntityNumber')
But when I execute it, I get the folowing error message :
Msg 50000, Level 16, State 2, Procedure uspCEProcessingMainScriptAllProcesses, Line 634 [Batch Start Line 2]
Invalid column name 'ZM'.
Why is it working when the values are numbers, but not string ? The only issue that I have is with the parameter "#InputSurveyCodeId". I did tried the following:
' + quotename(#InputSurveyCodeId, '''') + ' AS SurveyCodeId
But then I got the error message : Incorrect syntax near 'quotename'. Do you guys see something I don't ?
Thanks a lot in advance for your help :-)
Mylene

I found the solution
DECLARE #sqlstatement NVARCHAR(max)
SET #sqlstatement = 'INSERT INTO [SurveyInterface].tblCEProcessingWorkingLCPSUF](
ParentId,
OperatingEntityNumber,
SurveyGroupCodeId,
ReferencePeriod,
SurveyCodeId,
StructureLevel )
SELECT ParentId,
RealOperatingEntityNumber AS OperatingEntityNumber,
' + quotename(#InputSurveyGroupCodeId, '''') + ' AS SurveyGroupCodeId,
' + quotename(#InputReferencePeriod, '''') + ' AS ReferencePeriod,
' + quotename(#InputSurveyCodeId, '''') + ' AS SurveyCodeId,
StructureLevel
FROM ' + #InputSUFFrameTable + '
WHERE ParentId <> RealOperatingEntityNumber'
PRINT #sqlstatement
EXEC sys.sp_executesql #sqlstatement

Related

SQL Server EXEC #SQL command causing an error

IF (SELECT COUNT(*)
FROM
(SELECT [Domain], [Server], [Instance], [DatabaseName]
FROM [dbo].[OF_Databases_A]
INTERSECT
SELECT [Domain], [Server], [Instance], [DatabaseName]
FROM [dbo].[OF_Databases]) z) > 0
BEGIN
DECLARE #SQL Nvarchar(max)
SET #SQL=
(
select 'Delete from [dbo].[OF_Databases] where domain='''+[Domain]+'''' + ' and server= '''+[Server] +'''' + ' and instance= '''+[Instance] +'''' + ' and DatabaseName= '''+[DatabaseName] +'''' + ' GO' from [dbo].[OF_Databases_A]
INTERSECT
select 'Delete from [dbo].[OF_Databases] where domain='''+[Domain]+'''' + ' and server= '''+[Server] +'''' + ' and instance= '''+[Instance] +'''' + ' and DatabaseName= '''+[DatabaseName] +'''' + ' GO' from [dbo].[OF_Databases]
)
EXECUTE #SQL
END
If I execute this query, I get the following error:
Msg 512, Level 16, State 1, Line 81
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
Msg 2812, Level 16, State 62, Line 87
Could not find stored procedure ''.
How can I fix this?
Your variable could take only one value, you are giving it a resultSet, for it to work you need to do like this:
IF (SELECT COUNT(*)
FROM
(SELECT [Domain], [Server], [Instance], [DatabaseName]
FROM [dbo].[OF_Databases_A]
INTERSECT
SELECT [Domain], [Server], [Instance], [DatabaseName]
FROM [dbo].[OF_Databases]) z) > 0
BEGIN
DECLARE #SQL Nvarchar(max) = ''
SELECT #SQL = #SQL + ISNULL(QUERY, '') + ' '
FROM
(
select 'Delete from [dbo].[OF_Databases] where domain='''+[Domain]+'''' + ' and server= '''+[Server] +'''' + ' and instance= '''+[Instance] +'''' + ' and DatabaseName= '''+[DatabaseName] +'''' + ' GO' AS QUERY from [dbo].[OF_Databases_A]
INTERSECT
select 'Delete from [dbo].[OF_Databases] where domain='''+[Domain]+'''' + ' and server= '''+[Server] +'''' + ' and instance= '''+[Instance] +'''' + ' and DatabaseName= '''+[DatabaseName] +'''' + ' GO' from [dbo].[OF_Databases]
) a
EXECUTE (#SQL)
END

When building a dynamic query, an error is shown converting data type varchar to float - how to solve it?

I work on SQL Server 2012; when building a dynamic query, I get this error
Msg 8114, Level 16, State 5, Line 16
Error converting data type varchar to float
How to solve this error?
I build a dynamic query based on #Header and #column and #Body.
#Header represents the header must display as headers.
#column represent pivot columns.
#Body represent select query for data.
CREATE TABLE #FinalTable
(
PART_ID nvarchar(50) ,
CompanyName nvarchar(50),
PartNumber nvarchar(50),
DKFeatureName nvarchar(100),
value float,
StatusId int,
DisplayOrder int,
splitFlag bit
)
INSERT INTO #FinalTable
VALUES
('1222', 'Honda', 'silicon', 'package', '15.50Am', 2, 5, 0),
('1900', 'MERCEIS', 'GLASS', 'family', '90.00Am', 2, 2, 1),--have column per Unit on #Header because FlagAllow=1
('5000', 'TOYOTA', 'alominia', 'source', '70.20kg', 2, 1, 0),
('8000', 'MACDA', 'motor', 'parametric', '50.40kg', 2, 3, 1),--have column per Unit on #Header because FlagAllow=1
('8900', 'JEB', 'mirror', 'noparametric', '75.35kg', 2, 4, 0)
DECLARE #Header NVARCHAR(MAX)
SELECT
#Header = STUFF((SELECT ', ' + CASE WHEN A.splitFlag = 1 AND a.value <> '-' AND (a.Value IS NOT NULL) THEN '''' + A.DKFeatureName + ''' AS '' '+ A.DKFeatureName + ''', ''' + A.DKFeatureName + 'Units' + ''' AS ''' + A.DKFeatureName +'Units' +'''' else ''''+A.DKFeatureName +''' as ''' + A.DKFeatureName +'''' END
FROM #FinalTable A
WHERE StatusId = 2
ORDER BY DisplayOrder
FOR XML PATH ('')), 1, 2, '')
DECLARE #Columns NVARCHAR(MAX)
SELECT
#Columns = STUFF(
(
SELECT ', ' + case when A.splitFlag = 1 and a.value<> '-' and (a.Value is not null) then '['+A.DKFeatureName+'],['+A.DKFeatureName+'Unit]' else quotename(A.DKFeatureName) end
FROM #FinalTable A where StatusId=2
ORDER BY DisplayOrder
FOR XML PATH ('')
),1,2,''
)
DECLARE #Body NVARCHAR(MAX)
SELECT
#Body = STUFF(
(
SELECT ', ' + case when A.splitFlag = 1 and a.value<> '-' and (a.Value is not null) then 'LEFT(' + QUOTENAME (A.DKFeatureName) + ',PATINDEX(''%[^0-9.]%'',' + QUOTENAME (A.DKFeatureName) + '+ ' + ''' ''' + ')-1) as ['+A.DKFeatureName+'],RIGHT('+ QUOTENAME (A.DKFeatureName) +',LEN('+ QUOTENAME (A.DKFeatureName) +') - PATINDEX(''%[^0-9.]%'','+ QUOTENAME (A.DKFeatureName) +')+1) as ['+A.DKFeatureName +'Units'+']' else quotename(A.DKFeatureName) end
FROM #FinalTable A
where StatusId=2
ORDER BY A.DisplayOrder
FOR XML PATH ('')
),1,2,''
)
DECLARE #SQL NVARCHAR(MAX)
select #SQL =CONCAT('
SELECT * Into #NewTable
FROM #FinalTable
PIVOT(max(Value) FOR DKFeatureName IN ('+#Columns+')) AS PVTTable
',
N' Select ''PART_ID'' as ''PART_ID'' ,''CompanyName'' as ''CompanyName'',''PartNumber'' as ''PartNumber'' , ' +#Header + '
union all
select PART_ID,CompanyName,PartNumber, ' +#Body + ' from #NewTable
')
EXEC (#SQL)
The column value you are using is float which is a number not varchar. But you input varchar = "15.50Am".
You can create new columns for units (am, kg, etc.)
or you can change value like value numeric (5,2)

How to insert Error_Message using EXECUTE sp_executesql

Using MS SQL Server I have the below code - it is being executed via a EXECUTE sp_executesql command:
Declare #Cmd nvarchar(max)
;with DistinctTables as
(
select distinct [DestTable], [SourceFile] from [tbl_IN_Ctrl_Dtl]
),
InsertCommands as
(
-- columns from Destination table
select *,
'BEGIN TRY insert into ' + [DestTable] + '(' +
STUFF((
SELECT ',' + [DestCol]
FROM [tbl_IN_Ctrl_Dtl] t1
where t1.DestTable = drt.DestTable
GROUP BY DestCol,ORDINAL_POSITION
ORDER BY ORDINAL_POSITION
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'),1,1,'')
+ ')' +
' select ' +
-- columns from source table
STUFF((
SELECT ',' + [SourceCol]
FROM [tbl_IN_Ctrl_Dtl] t1
where t1.DestTable = drt.DestTable
GROUP BY SourceCol,ORDINAL_POSITION
ORDER BY ORDINAL_POSITION
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'),1,1,'')
+ ' from ' + [SourceFile]
+ ';
update tbl_IN_Ctrl_Header set ErrMsg = ##ERROR where SourceFile_INSERT = 0 and SourceFile = ''' + [SourceFile]+ ''''
+';
update tbl_IN_Ctrl_Header set SourceFile_INSERT = 1 where SourceFile_INSERT = 0 and SourceFile = ''' + [SourceFile]+ ''''
+'; END TRY BEGIN CATCH'
as InsertCommand
from DistinctTables drt
)
select #cmd =
STUFF((
SELECT ';' + char(10) + [InsertCommand]
FROM InsertCommands
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'),1,1,'')
+';' from InsertCommands ic
--print #cmd
EXECUTE sp_executesql #cmd
I can retrieve the error number using line:
update tbl_IN_Ctrl_Header set ErrMsg = ##ERROR where SourceFile_INSERT = 0 and SourceFile = ''' + [SourceFile]+ ''''
However, how do I retrieve the actual text error message? If I use ERROR_MESSAGE I just get Null. How do I modify the above to update 'ErrMsg' to the actual text error message? I've put a BEGIN TRY at the beginning of the Insert and END TRY at the end of the UPDATE but I now receive the error Incorrect syntax near ';'.

Using Union all to SQL Queries to create Dynamic Column Names

Please se my code below
set #query = 'SELECT tenantcode, locationd, name, MONTH,' +
'Year1 as' + '[' + #Year1 + ']' +
',Year2 as' + '[' + #Year2 + ']' +
',Year3 as' + '[' + #Year3 + ']' +
',Year4 as' + '[' + #Year4 + ']' +
',Year5 as' + '[' + #Year5 + ']' +
'from #SalesPerYear' +
'UNION ALL' +
'SELECT tenantcode, locationd, name, total , t1, t2,t3,t4,t5 FROM #TotalSales '
EXECUTE (#query)
That is part of my codes in the desire in achieving a final output in SQL WHERE COLUMN NAMES should be dynamic (in this case, the changing YEAR NAME such as 2011, 2012,2013 etc)
When execute my stored procedure, there is an error like this
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near 'tenantcode'.
When I remove the Union all, both queries worked individually. What could be the problem here.
You're missing a space between from #SalesPerYear and UNION ALL and also the following SELECT.
....
'from #SalesPerYear '
^---here
'UNION ALL' +
' SELECT tenantcode, locationd, name, total , t1, t2,t3,t4,t5 FROM #TotalSales '
^--- and here
Thats the easiest way to demonstrate it, you can of course just put a space either side of UNION ALL
' UNION ALL ' +

Generating Scripts for Specific Records in SQL Server

This is probably a bit of a limited, but valuable scenario. I have a SQL Server 2008 database with a table that has millions of records. There appears to be an intermittent problem with several of the records. I'm trying to repro the problem. In an effort to do this, I finally got the ID of an offending record. I would like to generate an INSERT statement associated with this single record in my PROD database. Then I can easily migrate it into my TESTING database in an effort to repro and resolve the problem.
Basically, I need to generate a single INSERT statement for a single record from a single table where I know the primary key value of the record.
Does anyone have any ideas of how I can accomplish this? Essentially, I want to generate insert statements on a conditional basis.
Thank you!
First try to recreate what you want to insert with a SELECT statement.
After that you can insert into the table with a INSERT INTO like this:
INSERT INTO tablename
SELECT ....
If they are on different servers, you can use INSERT like this:
INSERT INTO tablename VALUES (...)
using the values given by the SELECT in the other server fill the values in the insert.
In your specific case I think you can do this:
CREATE PROCEDURE dbo.GenerateSingleInsert
#table NVARCHAR(511), -- expects schema.table notation
#pk_column SYSNAME, -- column that is primary key
#pk_value INT -- change data type accordingly
AS
BEGIN
SET NOCOUNT ON;
DECLARE #cols NVARCHAR(MAX), #vals NVARCHAR(MAX),
#valOut NVARCHAR(MAX), #valSQL NVARCHAR(MAX);
SELECT #cols = N'', #vals = N'';
SELECT #cols = #cols + ',' + QUOTENAME(name),
#vals = #vals + ' + ' + REPLICATE(CHAR(39),3) + ','
+ REPLICATE(CHAR(39),3) + ' + ' + REPLICATE(CHAR(39),2) + '+'
+ 'RTRIM(' + CASE WHEN system_type_id IN (40,41,42,43,58,61) THEN
'CONVERT(CHAR(8), ' + QUOTENAME(name) + ', 112) + '' ''
+ CONVERT(CHAR(14), ' + QUOTENAME(name) + ', 14)'
ELSE 'REPLACE(' + QUOTENAME(name) + ','''''''','''''''''''')' END + ')
+ ' + REPLICATE(CHAR(39),2)
FROM sys.columns WHERE [object_id] = OBJECT_ID(#table)
AND system_type_id <> 189 -- can't insert rowversion
AND is_computed = 0; -- can't insert computed columns
SELECT #cols = STUFF(#cols, 1, 1, ''),
#vals = REPLICATE(CHAR(39), 4) + ' + ' + STUFF(#vals, 1, 13, '')
+ REPLICATE(CHAR(39), 2);
SELECT #valSQL = N'SELECT #valOut = ' + #vals + ' FROM ' + #table + ' WHERE '
+ QUOTENAME(#pk_column) + ' = ''' + RTRIM(#pk_value) + ''';';
EXEC sp_executesql #valSQL, N'#valOut NVARCHAR(MAX) OUTPUT', #valOut OUTPUT;
SELECT SQL = 'INSERT ' + #table + '(' + #cols + ') SELECT ' + #valOut;
END
GO
So let's try it out:
CREATE TABLE dbo.splunge
(
ID INT, dt DATETIME, rv ROWVERSION, t NVARCHAR(MAX)
);
INSERT dbo.splunge(ID, dt, t)
SELECT 1, GETDATE(), 'foo'
UNION ALL SELECT 2, GETDATE(), 'bar'
UNION ALL SELECT 3, GETDATE(), 'O''Brien';
EXEC dbo.GenerateSingleInsert N'dbo.splunge', N'ID', 1;
SQL
-------------
INSERT dbo.splunge([ID],[dt],[t]) SELECT '1','20120517 10:07:07:330','foo'
EXEC dbo.GenerateSingleInsert N'dbo.splunge', N'ID', 2;
SQL
-------------
INSERT dbo.splunge([ID],[dt],[t]) SELECT '2','20120517 10:07:07:330','bar'
EXEC dbo.GenerateSingleInsert N'dbo.splunge', N'ID', 3;
SQL
-------------
INSERT dbo.splunge([ID],[dt],[t]) SELECT '3','20120517 10:07:07:330','O''Brien'
If there is an IDENTITY column you may need to set SET IDENTITY_INSERT ON for the TEST table, and verify that there is no collision. Probably about 500 caveats I should mention, I haven't tested all data types, etc.
However in the more general case there is a lot more to it than this. Vyas K has a pretty robust stored procedure that should demonstrate how complicated it can get:
http://vyaskn.tripod.com/code/generate_inserts_2005.txt
You are probably far better off using a tool like Red-Gate's SQL Data Compare to pick a specific row and generate an insert for you. As I've blogged about, paying for a tool is not just about the money, it's about the hours of troubleshooting and bug-fixing that someone else has already done for you.
Aaron,
I liked your code, it solved a problem for me. I ran into a few issues using it (like you said I would) with nulls and the text type so I made some changes to address those issues.
ALTER PROCEDURE dbo.GenerateSingleInsert
#table NVARCHAR(511), -- expects schema.table notation
#pk_column SYSNAME, -- column that is primary key
#pk_value INT -- change data type accordingly
AS
BEGIN
SET NOCOUNT ON;
DECLARE #cols NVARCHAR(MAX), #vals NVARCHAR(MAX),
#valOut NVARCHAR(MAX), #valSQL NVARCHAR(MAX);
SELECT #cols = N'', #vals = N'';
SELECT #cols = #cols + ',' + QUOTENAME(name),
#vals = #vals + ' + '','' + ' + 'ISNULL('+REPLICATE(CHAR(39),4)+'+RTRIM(' +
CASE WHEN system_type_id IN (40,41,42,43,58,61) -- datetime types
THEN
'CONVERT(CHAR(8), ' + QUOTENAME(name) + ', 112) + '' ''+ CONVERT(CHAR(14), ' + QUOTENAME(name) + ', 14)'
WHEN system_type_id IN (35) -- text type NOTE: can overflow
THEN
'REPLACE(CAST(' + QUOTENAME(name) + 'as nvarchar(MAX)),'+REPLICATE(CHAR(39),4)+','+REPLICATE(CHAR(39),6)+')'
ELSE
'REPLACE(' + QUOTENAME(name) + ','+REPLICATE(CHAR(39),4)+','+REPLICATE(CHAR(39),6)+')'
END
+ ')+' + REPLICATE(CHAR(39),4) + ',''null'') + '
FROM sys.columns WHERE [object_id] = OBJECT_ID(#table)
AND system_type_id <> 189 -- can't insert rowversion
AND is_computed = 0; -- can't insert computed columns
SELECT #cols = STUFF(#cols, 1, 1, ''),
#vals = REPLICATE(CHAR(39),2) + STUFF(#vals, 1, 6, '') + REPLICATE(CHAR(39),2) ;
SELECT #valSQL = N'SELECT #valOut = ' + #vals + ' FROM ' + #table + ' WHERE '
+ QUOTENAME(#pk_column) + ' = ''' + RTRIM(#pk_value) + ''';';
EXEC sp_executesql #valSQL, N'#valOut NVARCHAR(MAX) OUTPUT', #valOut OUTPUT;
SELECT SQL = 'INSERT ' + #table + '(' + #cols + ') SELECT ' + #valOut;
END