Stored Procedure Cross Table ID Input - sql

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.

Related

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

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

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.

Lock Stored Procedure in SQL

I have a stored procedure which inserts info into multiple tables and gets the IDs by SCOPE_IDENTITY(). I would like to prevent multiple users from executing it at the same time, so that my IDs don't get mixed up.
How do I lock it? I have read about sp_getapplock and sp_releaselock, but there is no clear explanation how to use it. Below I put my procedure.
create procedure AddPerson(
#Name nvarchar(255),
#LastName nvarchar(255),
#City nvarchar(255),
#Address nvarchar(255)
)
as
BEGIN TRY
BEGIN TRANSACTION
insert into Location(Address, City)
values(#Address, #City)
declare #LocationID int
set #LocationID = SCOPE_IDENTITY()
insert into PersonalInfo(Name, LastName)
values (#Name, #LastName)
declare #PersonInfoID int
set #PersonInfoID = SCOPE_IDENTITY()
insert into Teacher
values(#LocationID, #PersonInfoID)
COMMIT
END TRY
BEGIN CATCH
ROLLBACK
END CATCH
No locking of any kind needed - this behavior you're trying to accomplish is already in place implicitly.
SCOPE_IDENTITY() returns the new ID in the scope of each transaction - so if 10 users are running this simultaneously, each will get their own, separate ID back from SCOPE_IDENTITY

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.

stored procedure executes correctly from management studio, but not in production

I have a stored procedure that works correctly when I execute the stored procedure from SQL Server Management Studio. Unfortunately, it doesn't behave the the same way on the production server. On an insert statement, it is only inserting some of the values and the rest are NULL. The NULL values are coming from user defined scalar function calls (which also work correctly when executed from Management Studio). Has anyone run into anything similar? I was thinking it might be a permissions issue, but I connected to the database through Management Studio with the production connection credentials and saw the same behavior. I'm a C# developer that normally works with ORMs, so I'm definitely no SQL expert. Thanks in advance, guys.
Here is the code:
BEGIN
DECLARE #UserExists int
SET #UserExists = 0
SELECT #UserExists = COUNT(*) FROM UserPass WHERE UserId = #UserID AND PortalID = #PORTALID
--If the Action is add and a User Exists change the Action to EDT (Update)
IF #Action = 'ADD' AND #UserExists > 0
SET #Action = 'EDT'
--Get All Of the Properties for this User
DECLARE #EMAIL nvarchar(255)
DECLARE #FIRSTNAME nvarchar(50)
DECLARE #LASTNAME nvarchar(50)
DECLARE #GENDER char(1)
DECLARE #BIRTHDATE smalldatetime
DECLARE #ADDRESS nvarchar(50)
DECLARE #CITY nvarchar(50)
DECLARE #STATE nchar(2)
DECLARE #COUNTRY nvarchar(50)
DECLARE #POSTALCODE nvarchar(10)
DECLARE #TELEPHONE nvarchar(20)
DECLARE #CELL nvarchar(20)
DECLARE #EMAILPERMISSION bit
DECLARE #TEXTPERMISSION bit
DECLARE #UPDATEDIRECTION nvarchar(3)
BEGIN TRY
SELECT #BIRTHDATE = CAST(dbo.GetPropertyValue(#PORTALID,#USERID,'Birthdate') AS SmallDatetime)
END TRY
BEGIN CATCH
SELECT #BIRTHDATE = NULL
END CATCH
SELECT #EMAIL = Email,
#FIRSTNAME = dbo.Proper(Firstname),
#LASTNAME = dbo.Proper(Lastname),
#GENDER = dbo.GetPropertyValue(#PORTALID,#USERID,'Gender'),
#ADDRESS = dbo.GetPropertyValue(#PORTALID,#USERID,'Street'),
#CITY = dbo.Proper(dbo.GetPropertyValue(#PORTALID,#USERID,'City')),
#STATE = Upper(dbo.GetState(dbo.GetPropertyValue(#PORTALID,#USERID,'Region'))),
#COUNTRY = dbo.GetPropertyValue(#PORTALID,#USERID,'Country'),
#POSTALCODE = dbo.GetPropertyValue(#PORTALID,#USERID,'Postalcode'),
#TELEPHONE = dbo.STRFILTER(dbo.GetPropertyValue(#PORTALID,#USERID,'Telephone'),'0,1,2,3,4,5,6,7,8,9'),
#CELL = dbo.STRFILTER(dbo.GetPropertyValue(#PORTALID,#USERID,'Cell'),'0,1,2,3,4,5,6,7,8,9'),
#EMAILPERMISSION = dbo.GetPropertyValue(#PORTALID,#USERID,'eNewsLetter'),
#TEXTPERMISSION = dbo.GetPropertyValue(#PORTALID,#USERID,'TextPermission')
FROM Users
WHERE UserId = #USERID
-- Insert new user
IF #Action = 'ADD'
BEGIN
INSERT INTO UserPass
(UserID, Portalid, CreatedDate, Username, UserPass.Password, email, firstname, lastname, gender, birthdate, UserPass.address, city, UserPass.state, country, postalcode, telephone, cell, emailpermission, textpermission, UpdateDirection)
VALUES
(#UserID, #PORTALID, #CREATEDDATE, #Username, #Password, #EMAIL, #FIRSTNAME, #LASTNAME,#GENDER, #BIRTHDATE, #ADDRESS, #CITY, #STATE, #COUNTRY, #POSTALCODE, #TELEPHONE, #CELL, #EMAILPERMISSION, #TEXTPERMISSION, 'OUT')
END
#PORTALID and #USERID are passed to the stored procedure as parameters, and those values are actually saving in the insert. The columns that aren't updating are the ones that call the GetPropertyValue function for the value. This is only on one database server (I am not connecting to a dev database through Management studio, I am connecting directly to the production database). When I execute the stored procedure from Management Studio, it's perfect. When the trigger on the table calls the sproc, the GetPropertyValue function fails.
Get SQL Profiler on it and then copy & paste & execute the statements from that in query analyser.
It's likely that your production is producing subtlely different code or is injecting different param values than the ones you expect and this will catch exactly what is happening.
While it's impossible to see what is happening without table structures, sprocs and functions my thoughts would be to compare the table structures, defaults, identity columns, etc. in PROD and DEV.
That says to me something is funny in your application code. I would check your C# logic and make sure you are using the right function call on the command object. It might help to post your code.
As Nissan Fan says, you haven't provided nearly enough information. That said, one possibility is that you're on SQL Server 2000 and are encountering an old bug. If you want a useful answer, though, ask a useful question.