String that contains a SELECT with several pairs of variables and values. Using EXEC gives me an undeclared variable error - sql

The process is more complex than the previous one.
I have a stored procedure that retrieves the variable #parameters_list NVARCHAR(2000).
This #parameters_list variable contains a series of parameters that I retrieve from a transactional website. Usually, it contains a series of parameters with their respective values. The parameters vary depending on the type of transaction being executed.
Here is a more complete description of the process:
Suppose, that #parameters_list comes with the following data from the website
#parameters_list = 'id_client=1;id_dealer=1;id_country=1;id_region=5;id_city=2;sede=2;id_tower=8;main_code=CHI-01-01;id_location=2;city=Main City;data_name=Box 01;title=Major KPI;tittle2=Detecting relevant Data;detail=none'
Inside the stored procedure, I have in part the following declarations and creation of a temporary table:
DECLARE #id_client INT,
#id_dealer INT,
#id_country INT,
#id_region INT,
#id_city INT,
#id_tower INT,
#main_code VARCHAR(120),
#id_location INT,
#city VARCHAR(50),
#data_name VARCHAR(100),
#detail VARCHAR(100),
#title VARCHAR(200),
#title2 VARCHAR(300)
DECLARE #stringData NVARCHAR(2000),
#data_key VARCHAR(30)
DECLARE #ident INT
CREATE TABLE [dbo].[#TEMP_DATA](
[ident] [int] IDENTITY(1,1) NOT NULL,
[data_key] [varchar](100) NULL,
[data_value] [varchar](100) NULL
) ON [PRIMARY]
Later, I execute another stored procedure (PANKI_UTILS..SP_KEY_VALUE_PARAMETER) whose main task is to separate the variables with their respective values. Then, the result is stored in the temporary table #TEMP_DATA.
EXEC PANKI_UTILS..SP_KEY_VALUE_PARAMETER
#parameters_list,
';',
'=',
#ident output
INSERT INTO
#TEMP_DATA
SELECT
[key],
value
FROM PANKI_UTILS..KEY_VALUE
WHERE ind = #ident
ORDER BY [key]
The content of the #TEMP_DATA table is as follows:
What the image shows is a table where the column data_key is the name of the variable and "data value" the value of that variable.
Finally, I store all the content of the table in a #stringData variable
SET #stringData = (SELECT string_agg('#'+CAST(data_key AS VARCHAR(30)) +'='+ CAST(data_value AS VARCHAR(500)), ',') FROM #TEMP_DATA)
SELECT #stringData
#city=Main City,#data_name=Box 01,#detail=none,#id_city=2,#id_client=1,#id_country=1,#id_dealer=1,#id_location=2,#id_region=5,#id_sede=2,#id_tower=8,#main_code=CHI-01-01,#title=Major KPI,#tittle2=Detecting relevant Data
That's why I'm looking for a way to retrieve the variables in the form of; #city, #data_name and etc.
An alternative was to use the sp_executesql command, but I don't really know how to use it to retrieve those variables.
If you can help me, I would appreciate it. Thanks.

The TSQL you provide as a parameter to execute is run in a different scope than your parent script. It doesn't have access to local variables declared outside of it.
If you need to use execute, try something like this:
declare #string_data varchar(max);
SET #string_data = '
declare #City varchar(255), #Product varchar(255) , #Zip varchar(255);
SELECT #city=''Baltimore'', #product= ''car'', #zip=''630930'';
SELECT #city AS city, #product AS product, #zip AS zip;
';
EXEC(#string_data);
But you might be able to get away without using it:
declare #City varchar(255), #Product varchar(255) , #Zip varchar(255);
SELECT #city='Baltimore', #product= 'car', #zip='630930';
SELECT #city AS city, #product AS product, #zip AS zip;

When you use EXEC(#String), you're opening a new session and starting a new transaction. That new session that is opened is not aware of any variable from the calling session that executed the EXEC command.
Further, it doesn't really look like you need to use dynamic SQL and execute right here.
Without know what the rest of your query looks like, try this.
SELECT #city=Baltimore, #product= car, #zip=630930
SELECT #city AS city, #product AS product, #zip AS zip

Related

I want to write the code I created with the 'Stored procedure' as a function

CREATE PROC add_person
(
#id tinyint,
#name nvarchar(max),
#surname nvarchar(max),
#salary int,
#job nvarchar(max)
)
AS
BEGIN
INSERT INTO information
VALUES(#id,#name,#surname,#salary,#job)
END
I want to write this code as a function. But the concept of "return" confuses me. That's why I couldn't.
I tried to write the code above as a function. This code came out.
CREATE FUNCTION add_person
(
#id tinyint,
#name nvarchar(max),
#surname nvarchar(max),
#salary int,
#job nvarchar(max)
)
RETURNS TABLE
AS
BEGIN
RETURN INSERT INTO information -- not work
VALUES(#id,#name,#surname,#salary,#job)
END
If you want to return the newly created table, you can use the stored procedure to do that. If you're using SQL Server, the code would be:
BEGIN
INSERT INTO information -- not work
VALUES(#id,#name,#surname,#salary,#job);
SELECT * FROM information WHERE id = ##identity; -- this is the primary key just created.
END
Functions are much more limited in their functionality than are stored procedures.
Although insert is allowed, it is only allowed in local variables. As the documentation says:
INSERT, UPDATE, and DELETE statements modifying local table variables.
On the other hand, a stored procedure can return a value. Normally, this is a status code, where 0 means everything succeeded, and any other value means that the process failed.

List of foreign keys in an insert SQL Server

I am trying to set up a stored proc that will have three variables
FK_List
String_of_Info
CreateId
I need to insert into the table one entry per foreign key from the FK_List. I was curious what the best way to structure the stored procedure to do this efficiently.
EDIT: Code snippet added
CREATE PROCEDURE StackOverFlowExample_BulkAdd
#FKList VARCHAR(MAX),
#Notes NVARCHAR(1000),
#CreateId VARCHAR(50)
AS
BEGIN
INSERT INTO [dbo].[StackOverflowTable] WITH (ROWLOCK)
([FKID], [Notes], [CreateId], [UpdateId])
VALUES (#FKList, <---- this is the problem spot
#Notes, #CreateId, #CreateId)
END
GO
Based off your comments, you simply need a slight edit
CREATE PROCEDURE StackOverFlowExample_BulkAdd
#Notes nvarchar(1000),
#CreateId varchar(50)
AS
BEGIN
INSERT INTO [dbo].[StackOverflowTable] WITH (ROWLOCK)
([FKID]
,[Notes]
,[CreateId]
,[UpdateId])
select
someID
,#Notes
,#CreateId
,#CreateId
from FKListTable
END
GO
Here is a simple demo
This will insert a row into your table for each FK reference in the reference table with the parameters you pass in. That's all there is to it!
Here's another demo that may be more clear as I use a GUID for the primary key on the secondary table.
SECOND EDIT
Based off your comments, you will need a string splitter. I have added a common one which was created by Jeff Moden. See the example here
The final proc, after you create the function, will be like below. You need to change the comma in the function to what ever the delimiter is for your application. Also, you should start using table valued parameters.
CREATE PROCEDURE StackOverFlowExample_BulkAdd
#FKList VARCHAR(MAX),
#Notes nvarchar(1000),
#CreateId varchar(50)
AS
BEGIN
INSERT INTO [dbo].[StackOverflowTable] WITH (ROWLOCK)
([FKID]
,[Notes]
,[CreateId]
,[UpdateId])
select item
,#Notes
,#CreateId
,#CreateId
from dbo.DelimitedSplit8K(#FKList,',')
END
And you can call it like so:
declare #FKList varchar(1000) = '1,2,3,4,5,6'
declare #Notes varchar(1000) = 'here is my note'
declare #CreatedId int = 1
exec StackOverFlowExample_BulkAdd #FKList, #Notes, #CreatedId

Stored Procedure Cross Table ID Input

I'm trying to insert other table's IDs (Company and Bank) into the uBankID and uCompanyID of the EndUser table and the BankID of the Company table on INSERT.
Whatever way I do this, the required fields aren't being populated, what am I doing wrong? I had a look at an inline select statement at the ID to try and grab it but couldn't fathom it and it wouldn't compile.
The variables are all present and correct in the backend and are being parsed through, all but these IDs, as nothing is going wrong with the C# I'm thinking there's something amiss with my SQL, especially as I'm fairly new to stored procedures.
Any help would be greatly appreciated.
Code (slimmed down):
CREATE PROCEDURE [ProcedureInsert]
#Title nvarchar(10),
#FirstName nvarchar(50),
#LastName nvarchar(50),
#Organisation nvarchar(50),
#Address nvarchar(50),
#uBankID int,
#uCompanyID int,
#BankID int,
#SortCode int,
#AccountNumber nvarchar(50),
#AccNameHolder nvarchar(50),
#cId int output,
#bId int output,
#euId int output
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [Bank](SortCode, AccountNumber, AccNameHolder)
VALUES(#SortCode, #AccountNumber, #AccNameHolder)
SET #bId = SCOPE_IDENTITY();
INSERT INTO [Company](Organisation, Address, BankID)
VALUES(#Organisation, #Address, #bId)
SET #cId = SCOPE_IDENTITY();
INSERT INTO [EndUser](Title, FirstName, LastName, uBankID, uCompanyID)
VALUES(#Title, #FirstName, #LastName, #uBankID, #cId)
SET #euId = SCOPE_IDENTITY();
END
You need to declare the variables. And Tab Alleman is right, get rid of the unused parameters.
DECLARE #cId int;
DECLARE #bId int;
DECLARE #euId int;
INSERT INTO [BAD](SortCode,AccountNumber,AccNameHolder)
VALUES('1234','a234','Test Name')
SET #bId=SCOPE_IDENTITY();
INSERT INTO [Company](Organisation,Address1, Address2,City,County,PostCode,Telephone,BankID)
VALUES('AnOrganisation','addressesss','Address2','City','County','PostCode','0123one', #bId)
SET #cId=SCOPE_IDENTITY();
INSERT INTO [EndUser](Title,FirstName,LastName,Email,uBankID,uCompanyID)
VALUES('Sitle','Fiame','astName','vv#Email',#bId,#cId)
SET #euId=SCOPE_IDENTITY();
EDIT
Remove those parameters if they're not being used, but they weren't in the sample code, else leave them, obviously.
Also, I used single quotes to dump in the data into the table rather than variables, if it's not working then there's something wrong with the bank end code.

Must declare the scalar variable "#tempattend" in sql procedure?

I am getting an error stating that I Must declare the table variable "#tempattend".
Please help me. How can I pass #tempattend table to #tempTableSelect variable?
ALTER PROCEDURE [dbo].[Rl_LM_AHS]
#SupEmpID nvarchar(10),
#SectorName nvarchar(300),
#dateList nvarchar(300),
#Month nvarchar(5),
#Year nvarchar(5),
#SearchType nvarchar(10)
AS
BEGIN
SET NOCOUNT ON;
declare #tempTableSelect nvarchar(2000)
DECLARE #tempattend Table
(
[Emp.ID] nvarchar(10),
[Name] nvarchar(60),
[1] nvarchar(3) null,
[2] nvarchar(3) null,
[3] nvarchar(3) null
upto ..............
[31] nvarchar(3) null
)
IF (#SearchType = 1)
BEGIN
--INSERT TEAM LIST TO #tempattend TABLE
insert into #tempattend([Emp.ID],[Name]) (Select EMP.empID as [Emp.ID],CONCAT(EMP.emp_fname,' ',COALESCE(nullif(EMP.emp_Mname,'') +' ',''),COALESCE(nullif(EMP.emp_Lname,'') +' ','')) as [Name] from EShiftHistory)
set #tempTableSelect = 'select [Emp.ID],Name,' + #dateList +' from #tempattend'
EXEC (#tempTableSelect)
END
END
You should write
set #tempTableSelect = 'select [Emp.ID],Name,' + #dateList +' from #tempattend'
#tempattend is a temporary table variable. It holds a table, not some value like #datelist.
But why do you EXEC instead of just selecting directly from the table?
Come to think of it: It may not be possible to use memory temp tables in EXEC statements. Try turning this
DECLARE #tempattend Table
into
CREATE TABLE #tempattend
and change every occurance of #tempattend to #tempattend.
Following up on Thorsten Dittmar's answer, why not something like this?
select empID,
CONCAT(emp_fname,' ',
COALESCE(emp_Mname,''),
COALESCE(nullif(emp_Lname,''))) as [Name]
from EShiftHistory
I realize you're trying to do some dynamic selection with the #dateList variable, but that's a strong signal that you should either normalize your tables or just let your client code pick out which columns it wants. (Not everything needs to be done in raw SQL.)
Numbers as column names? Definitely problematic.

Returning a value in OUTPUT parameter in a sproc

I have a stored procedure that returns all fields of an object.
CREATE PROCEDURE getCustomer
(
#CustomerId int OUTPUT
)
AS
BEGIN
SELECT #CustomerId=CustomerId,FirstName,LastName FROM Customers
END
I want to be able to return the id of the object as an output parameter, so that another sproc can use it. I get this error in this example:
A SELECT statement that assigns a value to a variable must not be combined with
data-retrieval operations.
CREATE PROCEDURE getCustomer_and_more
AS
BEGIN
DECLARE #CustomerId int
EXEC getCustomer #CustomerId OUTPUT
-- call another sproc that requires this #CustomerId
END
When your SELECT statement assigns variable values, all fields in the SELECT must assign to a local variable.
Change your SPROC to
CREATE PROCEDURE getCustomer
(
#CustomerId int OUTPUT
)
AS
BEGIN
DECLARE #FirstName VARCHAR(50)
DECLARE #LastName VARCHAR(50)
SELECT #CustomerId=CustomerId, #FirstName = FirstName, #LastName =LastName
FROM Customers
You don't have to use them variables, but they must be assigned in this fashion.
Your BETTER option is to remove the fields. If they're not needed, don't bother selecting them.
[EDIT] to respond to your comment
So, you could do what you're looking to do by splitting out the assignment of the variable and selecting the other fields as follows:
CREATE PROCEDURE getCustomer
(
#CustomerId int OUTPUT
)
AS
BEGIN
SELECT #CustomerId=CustomerId FROM Customers
SELECT FirstName, LastName, {A_BUNCH_OF_OTHER_FIELDS}
FROM
Customers
This would allow you to get your output param and select all of the other data without having to define params for each field. You have to weigh ease of use (not having to define a lot of local vars) versus performance (having to run two statements as opposed to one). This seems a little strange to me however.
I wasn't quite clear if you needed the other values from the GetCustomer sproc available to you in getCustomer_and_more. If you do, then yes, you'd have to define OUTPUT params for each value you needed
There is an error in the query: FirstName and LastName are redundant.
SELECT #CustomerId = CustomerId
FROM Customers
Also I assume you have more than one customer in the Customers table. So this query will return the last CustomerId, which I assume is not what you want. So you need to add WHERE condition, or TOP 1.
Something like this:
CREATE PROCEDURE getCustomer (#CustomerId int OUTPUT)
AS
BEGIN
select #CustomerId = id
from Customer
where <SomeCondition>
END
[EDIT] As you state that there the error is not in the SELECT statement and it compiles and works fine, here is the proof. Please try this code will work without problems.
CREATE PROCEDURE getCustomer
(
#CustomerId int OUTPUT,
#CustomerName varchar(10) OUTPUT
)
AS
BEGIN
SELECT #CustomerId = 666, #CustomerName = 'Test'
END
GO
CREATE PROCEDURE getCustomer_and_more
AS
BEGIN
DECLARE #CustomerId int
DECLARE #CustomerName varchar(10)
EXEC getCustomer #CustomerId OUTPUT, #CustomerName OUTPUT
SELECT #CustomerId, #CustomerName
END
GO
EXEC getCustomer_and_more
This is the code that is causing your error:
DECLARE #CustomerId int
SELECT #CustomerId = CustomerId, FirstName, LastName
FROM Customers
This is not legit SELECT statement. Try this code and you will see exactly the same error as you showed in the question.