Assume this script:
DECLARE #result TABLE(Id BIGINT);
DELETE FROM [Products].[Product]
OUTPUT DELETED.[Id] INTO #result
WHERE [Products].[Product].[Id] = 1589;
So in continues I try :
1
SELECT CAST(ISNULL([Id], -1) AS BIGINT) AS N'RetValId' FROM #result;
When [Id] is null returned null (nothing), but this one returned -1:
2
DECLARE #mi BIGINT;
SET #mi = (SELECT [Id] FROM #result)
SELECT CAST(ISNULL(#mi, -1) AS BIGINT) AS N'RetValId'
Why? where is the problem with first script?
Update
So is there any way to check if the Deleted Id is null returned -1 And if not Returned Id without declare another variable? what is the simplest way?
If you have no entry for the ID 1589, then in the DELETED table there will be no record, if you have it then it should return 1589.
So if you don't have I think it simple returns nothing, because this statement has no input row:
SELECT CAST(ISNULL([Id], -1) AS BIGINT) AS N'RetValId' FROM #result;
(If you SELECT * from #result it should be no rows there)
The second one return the -1 because you set first to the variable which is getting the NULL value after the select.
DECLARE #mi BIGINT;
SET #mi = (SELECT [Id] FROM #result)
(If you select only #mi after this, then it should be NULL)
I think that is the explanation
UPDATED:
May you can try a small trick to achive it without an other varriable:
SELECT CAST(ISNULL(MAX([ID]),-1) AS BIGINT) AS N'RetValId' FROM #result;
Because of MAX the insie statement will be NULL, so here is the trick. If something was deleted, then the ID will be there.
I hope it helped.
You can use a derived table that will return one row with -1 and then do an outer apply on #result.
select isnull(R.Id, T.Id) RetValId
from (values(-1)) as T(Id)
outer apply #result as R
An easy way to return null if no rows where deleted is the ##rowcount variable. It contains the number of rows affected by the previous operation:
DELETE FROM [Products].[Product]
WHERE [Products].[Product].[Id] = 1589;
IF ##ROWCOUNT = 0
return null
return 1589
Related
I am trying to make a query that can generate the latest sequence number +1 to the new record in sql server.
let ignore the insert part first, I write a query like this:
SELECT 'asdf' AS col1, CASE WHEN EXISTS (SELECT pk_sales_inv_no FROM salesInvoice WHERE pk_sales_inv_no LIKE 'Q-ARF2206-%') THEN 1 ELSE 0 END AS EXPR1
It looks fine, when the record with same prefix exists, It return 1, else 0.
Because I have to process the current latest sequence number in the true value part, so I change my query with this to get the pk_sales_inv_no for the true part processing.
SELECT TOP (1) 'asdf' AS col1, CASE WHEN EXISTS (SELECT pk_sales_inv_no FROM salesInvoice WHERE pk_sales_inv_no LIKE 'Q-ARF2206-%') THEN 1 ELSE 0 END AS EXPR1 FROM salesInvoice WHERE (pk_sales_inv_no LIKE 'Q-ARF2206-%') ORDER BY pk_sales_inv_no DESC
Then problem happens, because the select result is totally empty, so It doesn't return the 1 or 0.
How can I improve it to work out with a empty select result.
You can write a simple scalar udf, if you need it in JOIN adapt it as a table value function.
I doubt that this is what you need, I think you want to get the number after the 2nd dash
IF OBJECT_ID (N'dbo.udf_lastSequence') IS NOT NULL
DROP FUNCTION dbo.udf_lastSequence
GO
CREATE FUNCTION dbo.udf_lastSequence (#invNo varchar(100))
RETURNS int
AS
BEGIN
DECLARE #lastInvNo VARCHAR(100)
DECLARE #search VARCHAR(100)
DECLARE #result int
SET #result = 0
SET #search = CONCAT(#invNo, '%');
SELECT TOP 1 #lastInvNo = pk_sales_inv_no
FROM salesInvoice
WHERE (pk_sales_inv_no LIKE #search)
ORDER BY pk_sales_inv_no DESC
IF #lastInvNo IS NOT NULL
SET #result = CAST(REPLACE(#lastInvNo, #invNo, '') AS INT);
return #result
END
GO
Try it with SELECT dbo.udf_lastSequence('Q-ARF2206-') WITHOUT the final % charter
I'm passing a delimited string to a stored procedure that enters the values into the declared table when it runs into the delimiter,
Here is my Stored Procedure.
Alter PROCEDURE s_BulkDeleteTest
(
#IDString VarChar(200)
)
AS
-- Creating Variables
DECLARE #numberLength int
DECLARE #numberCount int
DECLARE #TheIDs VarChar(200)
DECLARE #sTemp VarChar(100) -- to hold single characters
-- Creating a temp table
DECLARE #T TABLE
(
TheIDs VarChar(500)
)
--Initializing Variables for counting
SET #numberLength = LEN (#IDString)
SET #numberCount = 1
SET #TheIDs = ''
--Start looping through the keyword ids
WHILE (#numberCount <= #numberLength)
BEGIN
SET #sTemp = SUBSTRING (#IDString, #numberCount, 1)
IF (#sTemp = ',')
BEGIN
INSERT #T(TheIDs) VALUES (#TheIDs)
SET #TheIDs = ''
END
IF (#sTemp <> ',')
BEGIN
SET #TheIDs = #TheIDs + #sTemp
END
SET #numberCount = #numberCount + 1
END
This all works fine for adding the values to the #T table, but then I added this..
delete from [Subjects]
where (select TheIDs from #T) = SubjectID
that threw an error about there being more than one value in the declared table #T.
So I was wondering how can I use the values in #T and delete all those ID's from my Subjects table.
If TheIDs has any null values using IN operator will delete unexpect rows. I would suggest using EXISTS operator something like this...
DELETE FROM [Subjects]
WHERE EXISTS
(SELECT 1
FROM #T
WHERE [Subjects].SubjectId = TheIDs)
You need to use in:
delete from [Subjects]
where SubjectId in (select TheIDs from #T);
A result set with multiple rows cannot be equal to a single value.
EDIT:
The expression (select TheIds from #T) returns a set of values. The = operator works on scalar values, not sets. So, it doesn't normally work with this construct. The in operator compares a scalar to a set. so it does work.
There is one exception. When the subquery returns one row and one column, then it is converted to a scalar value. So, the expression would work if there were one row returned, or if you forced one row, as in:
where SubjectId = (select top 1 TheIDs from #T);
Of course, in would work in this situation as well.
I am trying to achieve something like the below in WHERE clause in sql.
if (#zipCode ==null)
begin
([Portal].[dbo].[Address].Position.Filter(#radiusBuff) = 1)
end
else if(#zipCode !=null)
begin
([Portal].[dbo].[Address].PostalCode=#zipCode )
end
I tried the following:
WHERE ((#zipCode IS NOT NULL AND ([Portal].[dbo].[Address].PostalCode=#zipCode)) OR (#zipCode IS NULL AND ([Portal].[dbo].[Address].Position.Filter(#radiusBuff) = 1)))
which is wrong. Can anyone help in framing the exact statement. Thanks!
is null is the syntax I use for such things, when COALESCE is of no help.
Try:
if (#zipCode is null)
begin
([Portal].[dbo].[Address].Position.Filter(#radiusBuff) = 1)
end
else
begin
([Portal].[dbo].[Address].PostalCode=#zipCode )
end
Isnull() syntax is built in for this kind of thing.
declare #Int int = null;
declare #Values table ( id int, def varchar(8) )
insert into #Values values (8, 'I am 8');
-- fails
select *
from #Values
where id = #Int
-- works fine
select *
from #Values
where id = isnull(#Int, 8);
For your example keep in mind you can change scope to be yet another where predicate off of a different variable for complex boolean logic. Only caveat is you need to cast it differently if you need to examine for a different data type. So if I add another row but wish to specify int of 8 AND also the reference of text similar to 'repeat' I can do that with a reference again back to the 'isnull' of the first variable yet return an entirely different result data type for a different reference to a different field.
declare #Int int = null;
declare #Values table ( id int, def varchar(16) )
insert into #Values values (8, 'I am 8'), (8, 'I am 8 repeat');
select *
from #Values
where id = isnull(#Int, 8)
and def like isnull(cast(#Int as varchar), '%repeat%')
is null can be used to check whether null data is coming from a query as in following example:
declare #Mem varchar(20),#flag int
select #mem=MemberClub from [dbo].[UserMaster] where UserID=#uid
if(#Mem is null)
begin
set #flag= 0;
end
else
begin
set #flag=1;
end
return #flag;
Try a case statement
WHERE
CASE WHEN #zipCode IS NULL THEN 1
ELSE #zipCode
END
Try the following:
if ((select VisitCount from PageImage where PID=#pid and PageNumber=5) is NULL)
begin
update PageImage
set VisitCount=1
where PID=#pid and PageNumber=#pageno
end
else
begin
update PageImage
set VisitCount=VisitCount+1
where PID=#pid and PageNumber=#pageno
end
I have a stored procedure that selects a row based on an id (simple enough), but only returns the actual result if the data satisfies a few conditions, otherwise it returns specific error codes. So when doing nested checks, the code would look similiar to this:
CREATE PROCEDURE GetStuffById
#StuffId int
AS
BEGIN
IF EXISTS (SELECT TOP 1 * FROM [Stuff] WHERE StuffId = #StuffId)
BEGIN
DECLARE #IsValid bit
SET #IsValid = (SELECT IsValid FROM [Stuff] WHERE StuffId = #StuffId)
IF #IsValid = 1
BEGIN
--More nested checks may occur here
SELECT * FROM [Stuff] WHERE StuffId = #StuffId
END
ELSE
BEGIN
RETURN -2
END
END
ELSE
BEGIN
RETURN -1
END
END
In this approach I already have 3 selects on the same table, which seems redundant and inefficient and another check would mean another select etc. Is there a better pattern to do this (e.g. temp tables)?
UPDATE: edited first check
You can assign to multiple variables in a single select and use ##ROWCOUNT to detect whether a row was found.
DECLARE #IsValid BIT,
#Foo INT
SELECT #IsValid = IsValid,
#Foo = Foo
FROM [Stuff]
WHERE StuffId = #StuffId
/*This must be tested immediately after the assignment statement*/
IF ##ROWCOUNT = 0
RETURN -1
IF ISNULL(#IsValid, 0) = 0
RETURN -2
SELECT #IsValid AS IsValid,
#Foo AS Foo
I want to define a scaler function which in that I'm going to return the result into a variable but I do not know how to do this.
CREATE FUNCTION dbo.Funname ( #param int )
RETURNS INT
AS
declare #returnvar int
select #returnvar = select colname from tablename where someconditions = something
return(#returnvar)
I want to make a function something like the top. I mean the result of the select statement which is:
select colname from tablename where someconditions = something
Is only a single cell and we are sure about it. I want to store it into a variable and return it from the function. How can I implement this thing?
I should probably mention that scalar UDFs do come with a considerable health warning and can cause performance issues depending upon how you use them.
Here's an example though.
CREATE FUNCTION dbo.Funname ( #param INT )
RETURNS INT
WITH RETURNS NULL ON NULL INPUT
AS
BEGIN
RETURN (SELECT number FROM master.dbo.spt_values WHERE number < #param)
END
In the above example I didn't use a variable as it is redundant. The version with variable is
BEGIN
DECLARE #Result int
SET #Result = (SELECT number FROM master.dbo.spt_values WHERE number < #param)
RETURN #Result
END
For both of the above you would need to be sure the Query returned at most one row to avoid an error at runtime. For example
select dbo.Funname(-1) Returns -32768
select dbo.Funname(0) Returns error "Subquery returned more than 1 value."
An alternative syntax would be
BEGIN
DECLARE #Result int
SELECT #Result = number FROM master.dbo.spt_values WHERE number < #param
RETURN #Result
END
This would no longer raise the error if the subquery returned more than one value but you would just end up with an arbitrary result with no warning - which is worse.
Following Comments I think this is what you need
CREATE FUNCTION dbo.getcustgrade(#custid CHAR(200))
RETURNS INT
WITH RETURNS NULL ON NULL INPUT
AS
BEGIN
RETURN
( SELECT [cust grade]
FROM ( SELECT customerid,
DENSE_RANK() OVER (ORDER BY COUNT(*) DESC) AS [cust grade]
FROM Orders
GROUP BY CustomerID
)
d
WHERE customerid = #custid
)
END