I have a database table I am trying to do an UPDATE/INSERT to with a stored procedure. Let's define the table like so:
CREATE TABLE Foo
(
Id INT IDENTITY(1, 1),
Name VARCHAR(256) NOT NULL,
ShortName VARCHAR(32),
Sort INT
);
I have written a stored procedure similar to the following:
CREATE PROCEDURE Put_Foo
(
#Id INT = NULL OUTPUT,
#Name VARCHAR(256),
#ShortName VARCHAR(32) = NULL,
#Sort INT = NULL
)
AS
BEGIN
SET NOCOUNT ON;
SELECT
#Id = F.Id
FROM
Foo AS F
WHERE
F.Name = #Name;
IF (#Id IS NOT NULL)
BEGIN
UPDATE
Foo
SET
ShortName = #ShortName,
Sort = #Sort
WHERE
Id = #Id;
END
ELSE
BEGIN
INSERT
INTO Foo
(
Name,
ShortName,
Sort
)
VALUES
(
#Name,
#ShortName
#Sort
);
SET #Id = SCOPE_IDENTITY();
END
RETURN;
END;
I've greatly simplified the data structures I am dealing with but I hope this serves my point. My question is in regards to how the parameters are processed. Is there a way to determine within the procedure if #Sort was passed in as NULL or set NULL by the default declaration in the parameter list?
EDIT:
The purpose of this is that I don't want NULL parameters to override any columns in the UPDATE statement unless they are explicitly passed in that way.
No, you can't detect how #Sort became NULL. If your goal is to capture when it is explicitly set versus it being set by the default, I would suggest using a different default value (maybe one that wouldn't normally be used, like -1). Then you can assume that if #Sort is NULL, it was explicitly passed in, but if it is -1, you know it was set by default.
I think this is what your looking for. If one of the parameters is null, it will updatedit with the value in the database. The other option is update one column at a time.
UPDATE Foo
SET
ShortName = ISNULL(#ShortName, ShortName)
, Sort = ISNULL(#Sort, Sort)
WHERE Id = #Id;
Take out the default value and and then the code calling the proc must provide a value (either a real value or NULL)
Related
I am making a stored procedure that would accept ID as a parameter and will bring one record related to the ID provided and if no ID were provided bring the whole result set back.
I have managed to make some workaround with COALESCE function but I really would like to have that input parameter as INTEGER data type.
Here's my code:
CREATE PROCEDURE GetThis
#ID VARCHAR(25) = NULL
AS
BEGIN
SET #ID= COALESCE( #ID, '%' )
...
SELECT * FROM #TABLE
WHERE CONVERT(VARCHAR(25),ID) LIKE #ID
END
What is the best way to achieve this?
Use an OR statement:
SELECT * FROM #TABLE
WHERE #ID IS NULL
OR CONVERT(VARCHAR(25),ID) LIKE #ID
Not sure if this is the best approach, but I have a stored procedure with an OUTPUT parameter as follows;
create procedure [dbo].[sp_get_site_idx]
#site_name varchar(100),
#result uniqueidentifier output
as
begin
select #result = [primary_idx_col] from [site] where upper([site].[site_name]) = upper(#site_name);
if (#result is null)
begin
< insert a new row>
< run the above select statement again>
end;
end;
When a #site_name that I know does not exist is supplied, the condition (#result is null) is never true, in fact #result appears to be undefined (similar to when there's an exception in a programming language).
Table [site] was created as:
create table [site] (
[primary_idx_col] UNIQUEIDENTIFIER DEFAULT NEWID() constraint pk_site_pk primary key,
...
);
Strangely, if I slightly modify the select statement to:
select #result = [primary_idx_col] from [site] where upper([site].[site_name]) = upper(#site_name) group by [primary_idx_col];
then (#result is null) will evaluate to true.
Please could you explain this behaviour? What is worng with the first select statement?
Thanks in advance.
UNIQUEIDENTIFIER can be checked against NULL.
I tried putting your code into a test database, and the logic seems to be working for me.
If I call your Stored Procedure with:
DECLARE #RESULT2 UNIQUEIDENTIFIER;
EXEC dbo.SP_GET_SITE_IDX #SITE_NAME = '<INSERT VALUE HERE>', -- varchar(100)
#RESULT = #RESULT2 OUTPUT;-- uniqueidentifier
SELECT #RESULT2
then I get the proper result depending on whether the site name is in the table or not.
Does it not insert the row in your IF, in the procedure?
Are you sure the site in question is not in your table?
It is possible that the site is in your table, but with a NULL key/value?
Using entity Framework, vb and sql server.
I have a stored procedure (shown below) to insert a new record and return the new identity of the record concerned (the id column is a properly defined identity column). The stored procedure is imported into my entity data model and called as a function, with the expected result being the identity of the new record. However I always get 0 returned instead.
If I execute the stored procedure in ssms I get the result I'm expecting in the results window and also a separate result with the value of 0 (which is clearly what is being returned to my mapped stored procedure).
Either I have an error in my stored procedure, or I'm doing something wrong with the way that I call the function (also shown below). I'd be really grateful for any suggestions that you might have to offer.
The stored procedure:
ALTER PROCEDURE [Finances].[CreatePurchaseInvoicePayment]
-- Add the parameters for the stored procedure here
#PurchaseInvoiceId int = NULL,
#SupplierId int = NULL,
#PurchaseInvoicePaymentDate date = NULL,
#Amount money = NULL,
#PaymentType int = NULL,
#ChequeNumber nchar(10) = NULL,
#BankAccountId int = NULL,
#purchaseInvoiceCreditNoteId int = NULL,
#ConversionFactor numeric(4,2) = NULL,
#ModifiedDate date = NULL,
#id int = NULL OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
INSERT INTO Finances.PurchaseInvoicePayments
VALUES
(
#PurchaseInvoiceId,
#SupplierId,
#PurchaseInvoicePaymentDate,
#Amount,
#PaymentType,
#ChequeNumber,
#BankAccountId,
#purchaseInvoiceCreditNoteId,
#ConversionFactor,
#ModifiedDate
)
SET #id = SCOPE_IDENTITY()
END
which is being called like this:
Try
pipId = CInt(te.CreatePurchaseInvoicePayment(pip.PurchaseInvoiceId, pip.SupplierId, pip.PurchaseInvoicePaymentDate, pip.Amount, pip.PaymentType, pip.ChequeNumber, pip.BankAccountId, pip.PurchaseInvoiceCreditNoteId, pip.ConversionFactor, pip.ModifiedDate,nothing).FirstOrDefault)
Catch ex As Exception
As I say if anyone could point me in the right direction I'd be most grateful.
I believe function expects an actual resultset from the SP. In this case you don't need an output parameter, just add at the end of SP:
SELECT SCOPE_IDENTITY()
and the function should read it correctly.
I have a stored procedure that updates two tables. The first table is always the same table, but the second table changes depending on a parameter that is passed in. Is it more efficient to write it all into one big procudure, as such
CREATE PROCEDURE MyBigProc
#id int
#param int,
#value1 int,
#value2 int
AS
BEGIN
SET NOCOUNT ON;
-- First table to update
UPDATE MyTable SET field1 = #value1 WHERE id = #id
-- Then choose which table to update based on #param
IF #param = 1
UPDATE MySecondTable SET field2 = #value2 WHERE id = #id
IF #param = 2
UPDATE MyThirdTable SET field2 = #value2 WHERE id = #id
END
Or should I write a separate procedure for each table and then call EXEC the procedure from the main procedure.
I suppose the latter is more flexible, say if I wanted to update a subtable but no the main table?
I suppose the latter is more flexible, say if I wanted to update a
subtable but no the main table?
Exactly, you have a good reason to split the work on 2 separate procs. If it makes sense for you for everything else, I don't see why not follow that approach.
One possible reason not to do it, would be if you need both updates to succeed or fail at the same time. Under a scenario like this, I would leave everything in one proc and enclose everything in one transaction.
CREATE PROCEDURE MyBigProc
#id int,
#param int,
#value1 int,
#value2 int
AS
BEGIN
SET NOCOUNT ON;
-- First table to update
UPDATE MyTable SET field1 = #value1 WHERE id = #id;
-- Then choose which table to update based on #param
IF #param = 1
exec SP_MySecondTable #id,#value2;
IF #param = 2
exec SP_MyThirdTable #id,#value2;
END
CREATE PROCEDURE SP_MySecondTable
#id int,
#value2 int
AS
BEGIN
UPDATE MySecondTable SET field2 = #value2 WHERE id = #id;
END
CREATE PROCEDURE SP_MyThirdTable
#id int,
#value2 int
AS
BEGIN
UPDATE MyThirdTable SET field2 = #value2 WHERE id = #id;
END
Its better to have different stored procedures and then call them all at a single place. It'll help you a lot while performing maintenance activities.
Best option is to use a CASE statement to update your tables
I need to write a generic procedure that set value for one column or no of a columns in a table depending on parameters. Any idea how to do it.
I would guess you want something like:
CREATE PROC UpdateProc
#RowID UNIQUEIDENTIFIER,
#Parameter1 NVARCHAR(50) NULL,
#Parameter2 INT NULL
AS
SET NOCOUNT ON
GO
IF #Parameter1 IS NOT NULL
BEGIN
UPDATE MyTable
SET Column1 = #Parameter1
WHERE ID = #RowID
END
IF #Parameter2 IS NOT NULL
BEGIN
UPDATE MyTable
SET Column2 = #Parameter2
WHERE ID = #RowID
END
It doesn't feel particularly elegant but if you don't know/can't guarantee which parameters will be passed I don't know of a better way than to test them in turn for NULL.