T-SQL Error Message 207 When passing values Dynamically - sql-server

I am attempting to create a stored procedure that allows values to be passed to it, however, when I try to use Dynamic T-SQL I raise an error MSG 207
I know that the error message is supposed to indicate that the column name was misspelled in my statement thanks to the following site:
https://www.tsql.info/error/msg-207-level-16-invalid-column-name.php
This, however, does not make sense as the following hard coded statement works just fine.
INSERT INTO [dbo].[tDriversLicense] (DriversLicensePrefix, DriversLicenseSuffix, DateAdded, DriversLicenseNumber)
VALUES ('shockc', '11653798', GETDATE(), 'GAD4859');
ALTER PROCEDURE [dbo].[spAddDriversLicense]
-- Add the parameters for the stored procedure here
#DriversLicensePrefix NCHAR(8),
#DriversLicenseSuffix NCHAR(10)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #sqlInsertDriversLicense NVARCHAR(MAX)
SET #sqlInsertDriversLicense = 'INSERT INTO [dbo].[tDriversLicense] (DriversLicensePrefix, DriversLicenseSuffix, DateAdded, DriversLicenseNumber)
VALUES (' + #DriversLicensePrefix + ', ' + #DriversLicenseSuffix + ', GETDATE(), GPC4859);'
EXECUTE sp_executesql #sqlInsertDriversLicense
END
I've been spilling over this code for hours and I'm thoroughly confused as to why there is any difference between the two INSERT statements. The values being passed are the same but an error is raised when I attempt to pass them dynamically. How is this raising an error??
I've used some code from this video to attempt to learn how pass Scalar Values dynamically and have had luck in other stored procedures.
https://www.youtube.com/watch?v=RHHKG65WEoU

When working with dynamic strings, select them first, so you can check that the resulting syntax is workable.
You need single quotes in the result, so you need more than single, single quotes, in the code:
declare #DriversLicensePrefix nchar(8) = 'A2345678'
declare #DriversLicenseSuffix nchar(10) = 'abcdefghij'
DECLARE #sqlInsertDriversLicense nvarchar(max)
SET #sqlInsertDriversLicense = 'INSERT INTO [dbo].[tDriversLicense] (DriversLicensePrefix, DriversLicenseSuffix, DateAdded, DriversLicenseNumber)
VALUES (N''' + #DriversLicensePrefix + ''', N''' + #DriversLicenseSuffix + ''', ''' + convert(char(8),GETDATE(),112) + ''', ''GPC4859'');'
select #sqlInsertDriversLicense
+-------------------------------------------------------------------------------------------------------------------+
| result: |
+-------------------------------------------------------------------------------------------------------------------+
| INSERT INTO [dbo].[tDriversLicense] (DriversLicensePrefix, DriversLicenseSuffix, DateAdded, DriversLicenseNumber) |
| VALUES (N'A2345678', N'abcdefghij', '20181109', 'GPC4859'); |
+-------------------------------------------------------------------------------------------------------------------+
NB You should use convert(char(8),getdate(),112) SQL Server will recognize the YYYYMMDD format as a date value regardless of server default settings.
The result see above demonstrates what the insert statement MUST be, note that it it contains several single quotes.
When you are concatenating the SQL statement, you are also dealing with strings, and every part of that has to be contained within single quotes.
So there are multiple needs for single quotes.
And; So you need multiple single quotes throughout out the concatenation, some to help form the SQL statement, and others to be INSIDE that statement.
/* get this into #sql */
select 'Y' as col1;
declare #SQL as nvarchar(max)
set #SQL = N'select ''Y'' as col1;'
select #SQL;
+---------------------+
| #SQL |
+---------------------+
| select 'Y' as col1; |
+---------------------+
In the larger query 2 variables are defined a NCHAR(8) or (10) as you have defined them a Nchar then when inserting data into those you should prefix that input by N

As posted in a comment already there is no need for this dynamic approach at all.
The following code will show a straight and a dynamic approach. Try it out:
USE master;
GO
CREATE DATABASE testDB;
GO
USE testDB;
GO
CREATE TABLE TestTable(SomeContent VARCHAR(100),SomeDate DATETIME,SomeFixString VARCHAR(100));
GO
--This procedure will use the parameters directly. No need for any dynamic SQL:
CREATE PROCEDURE TestStraight(#content VARCHAR(100))
AS
BEGIN
INSERT INTO TestTable(SomeContent,SomeDate,SomeFixString)
VALUES(#content,GETDATE(),'Proc Straight');
END
GO
--this procedure will use real parameters. You should never use parameters in string concatenation. One day you might meet bobby tables...
CREATE PROCEDURE TestDynamic(#content VARCHAR(100))
AS
BEGIN
DECLARE #cmd NVARCHAR(MAX)=
N'INSERT INTO TestTable(SomeContent,SomeDate,SomeFixString)
VALUES(#DynamicContent,GETDATE(),''Proc Dynamic'');'
EXEC sp_executesql #cmd,N'#DynamicContent VARCHAR(100)',#DynamicContent=#content;
END
GO
--Test it
EXEC TestStraight 'yeah!';
EXEC TestDynamic 'oh yeah!';
SELECT * FROM TestTable;
GO
--Clean up
USE master;
GO
--careful with real data!
--DROP DATABASE testDB;

Related

Calling an insert values using statement with in another stored procedure dynamically

I am creating a stored procedure within a stored procedure and am looking to insert dynamically generated values within a stored procedure to another stored procedure, I tried going to many places but still not find out my answer or they are not near to my given scenario please check below
Below 6 lines are part of above stored procedure and based on these six lines I would like to create another stored procedure where I am calling them for insert statement these six lines are doing the job I wanted but how to print those or call them within a stored procedure so that it shows the insert statement.
I tried output and table variable still not able to populate the insert statement. Please help me achieve this thanks
declare #DD varchar(max)
set #DD='select '+isnull(#allcol,'')+ ' from '+#Table1+' a '+'inner join '+#Table2+' b on a.'+#KeyColumn1+'=b.'+#KeyColumn2+isnull(' inner join '+#Table3+' c on a.'+#KeyColumn1+'=c.'+#KeyColumn3,'')
--print #DD
--exec (#DD)
-- Declare your stored procedure name here
DECLARE #create_stored_procedure nvarchar(max)
DECLARE #TableName nvarchar(max)
-- Please provide name to your stored procedure
set #TableName = 'staging_ABC'
SET #create_stored_procedure = N'
CREATE PROCEDURE [dbo].[sproc_' + #TableName + ']
AS
BEGIN
-- If stage table exist drop it and then insert into [staging_ABC]
IF EXISTS (SELECT * FROM sys.objects WHERE NAME = ''' + #TableName + ''')
BEGIN
DROP TABLE [dbo].[Staging_ABC]
END
-- We need to populate insert statement here from #dd
--print #DD
END '

Stored Procedure in sql for selecting columns based on input values

I am trying to code a stored procedure in SQL that does the following
Takes 2 inputs (BatchType and "Column Name").
Searches database and gives the batchdate and the data in the column = "Column name"
Code is as give below
ALTER PROCEDURE [dbo].[chartmilldata]
-- Add the parameters for the stored procedure here
(#BatchType nvarchar (50),
#Data nvarchar(50))
AS
BEGIN
-- Insert statements for procedure here
SELECT BatchDate,#Data FROM --Database-- WHERE BatchType = #BatchType
END
I am trying to select column from the database based on operator input. But I am not getting the output. It would be great if someone can give me a direction.
You may want to build out your SELECT statement as a string then execute it using sp_executesql.
See this page for more info:
https://msdn.microsoft.com/en-us/library/ms188001.aspx
This will allow you to set your query to substitute in your column name via your variable and then execute the statement. Be sure to sanitize your inputs though!
You'd need to use dynamic SQL, HOWEVER I would not recommend this solution, I don't think there is anything I can add as to why I wouldn't recommend it that isn't explained better in Erland Sommarskog in The Curse and Blessings of Dynamic SQL.
Nonetheless, if you had to do it in a stored procedure you could use something like:
ALTER PROCEDURE [dbo].[chartmilldata]
-- Add the parameters for the stored procedure here
(#BatchType nvarchar (50),
#Data nvarchar(50))
AS
BEGIN
-- DECLARE AND SET SQL TO EXECUTE
DECLARE #SQL NVARCHAR(MAX) = N'SELECT BatchDate = NULL, ' +
QUOTENAME(#Data) + N' = NULL;';
-- CHECK COLUMN IS VALID IN THE TABLE
IF EXISTS
( SELECT 1
FROM sys.columns
WHERE name = #Data
AND object_id = OBJECT_ID('dbo.YourTable', 'U')
)
BEGIN
SET #SQL = 'SELECT BatchDate, ' + QUOTENAME(#Data) +
' FROM dbo.YourTable WHERE BatchType = #BatchType;';
END
EXECUTE sp_executesql #SQL, N'#BatchType NVARCHAR(50)', #BatchType;
END
It would probably be advisable to change your input parameter #Data to be NVARCHAR(128) (or the alias SYSNAME) though, since this is the maximum for column names.

Passing concat query parameters to SQL OPENQUERY

Due to the constraints within the workplace I have to use a local stored procedure to call another remote stored proc on a linked sql server, however the problem lies in passing a necessary parameter to the remote stored proc.
This is the query I constructed:
select *
from OPENQUERY([REMOTE_SRVR],'exec db.dbo.dwStoredProc_sp ''#id''')
In order to pass #id to the remote stored proc I understand I could concatenate the above as a string and then use exec
Something along the lines of:
set #query = 'select * from OPENQUERY([REMOTE_SRVR], ''EXEC db.dbo.dwStoredProc_sp '' #id '''''
exec(#query)
I cannot get the local stored proc to successfully call the other. The single quote mess doesn't help!
I get the error: Could not find stored procedure 's'
To help with the quote mess I like to do this in steps. It is more code but easier to understand. I am not sure from your example if #id is an integer. In that case you can lose the double quotes around __ID__.
set #query = 'EXEC db.dbo.dwStoredProc_sp ''__ID__'''
set #query = REPLACE(#query,'__ID__',#id)
set #query = REPLACE(#query,'''','''''')
set #query = REPLACE('SELECT * FROM OPENQUERY([REMOTE_SRVR], ''__REMOTEQUERY__'')','__REMOTEQUERY__',#query)
You could avoid dynamic queries by simply by using EXEC (..., ParamValue) AT LinkedServer (see product's documentation, example [L. Using a parameter with EXECUTE and AT linked_server_name]):
1) On target server:
CREATE PROCEDURE dbo.Proc1( #id NVARCHAR(50) )
AS
SELECT #id AS [id];
GO
2) On the source server you create the linked server and then you can call the stored procedure using EXEC ... AT ... syntax:
DECLARE #p1 NVARCHAR(50);
SET #p1 = N'DROP TABLE dbo.CocoJambo'
EXECUTE (N'dbo.Proc1 ? ' , #p1 ) AT LOCALINKEDSEREV
Output:
id
------------------------
DROP TABLE dbo.CocoJambo

dynamic sql statement insertion issue

I have created a Temp table(#TempTable). I am trying to insert the date to get but I am getting an error. It's a dynamic query.
I am trying to get the date from another table and inserting the date to temp table
Just to make sure you understand the problem I have given an example
DECLARE #OfferEndDateTime datetime
SELECT #OfferEndDateTime = getdate()-1
print #VOfferEndDateTime
DECLARE #SQL VarChar(1000)
SELECT #SQL ='INSERT INTO #TempTable '+
'SELECT D,Points,#OfferEndDateTime '
exec(#sql)
Please Let me know where I am going wrong
You need to use sp_executesql when passing a parameter to dynamic sql
exec sp_executesql #sql, N'#OfferEndDateTime datetime', #OfferEndDateTime=#OfferEndDateTime
You have, at least, three problems:
The variable needs to be outside:
SELECT #SQL ='INSERT INTO #TempTable '+
'SELECT D,Points,' + #OfferEndDateTime
The variable needs to be varchar type or similar
What is D,Points? They are not defined anywhere. If they are varchar values you nead to quote them (use " or '') for that purpose.
If you need to use the parameter like datetime you should use sp_executesql instead. Check HERE for some info on it!

Using sp_executesql with params complains of the need to declare a variable

I am attempting to make a stored procedure that uses sp_executesql. I have looked long and hard here, but I cannot see what I am doing incorrectly in my code. I'm new to stored procedures/sql server functions in general so I'm guessing I'm missing something simple. The stored procedure alter happens fine, but when I try run it I'm getting an error.
The error says.
Msg 1087, Level 15, State 2, Line 3
Must declare the table variable "#atableName"
The procedure looks like this.
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
go
ALTER PROCEDURE [dbo].[sp_TEST]
#tableName varchar(50),
#tableIDField varchar(50),
#tableValueField varchar(50)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQLString nvarchar(500);
SET #SQLString = N'SELECT DISTINCT #aTableIDField FROM #atableName';
EXEC sp_executesql #SQLString,
N'#atableName varchar(50),
#atableIDField varchar(50),
#atableValueField varchar(50)',
#atableName = #tableName,
#atableIDField = #tableIDField,
#atableValueField = #tableValueField;
END
And I'm trying to call it with something like this.
EXECUTE sp_TEST 'PERSON', 'PERSON.ID', 'PERSON.VALUE'
This example isn't adding anything special, but I have a large number of views that have similar code. If I could get this stored procedure working I could get a lot of repeated code shrunk down considerably.
Thanks for your help.
Edit: I am attempting to do this for easier maintainability purposes. I have multiple views that basically have the same exact sql except the table name is different. Data is brought to the SQL server instance for reporting purposes. When I have a table containing multiple rows per person id, each containing a value, I often need them in a single cell for the users.
You can not parameterise a table name, so it will fail with #atableName
You need to concatenate the first bit with atableName, which kind defeats the purpose fo using sp_executesql
This would work but is not advisable unless you are just trying to learn and experiment.
ALTER PROCEDURE [dbo].[sp_TEST]
#tableName varchar(50),
#tableIDField varchar(50),
#tableValueField varchar(50)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQLString nvarchar(500);
SET #SQLString = N'SELECT DISTINCT ' + quotename(#TableIDField) + ' FROM ' + quotename(#tableName);
EXEC sp_executesql #SQLString;
END
Read The Curse and Blessings of Dynamic SQL
You cannot use variables to pass table names and column names to a dynamic query as parameters. Had that been possible, we wouldn't actually have used dynamic queries for that!
Instead you should use the variables to construct the dynamic query. Like this:
SET #SQLString = N'SELECT DISTINCT ' + QUOTENAME(#TableIDField) +
' FROM ' + QUOTENAME(#TableName);
Parameters are used to pass values, typically for use in filter conditions.

Resources