Check if a column's value is null in SQL Server - sql

Can't believe I am stuck with this but how can I check that value I am returning is null in select statement
IF EXISTS(SELECT TU.Tagged FROM TopicUser TU
WHERE TU.TopicId = #TopicId and TU.UserId = #UserId)
BEGIN
--do stuff
END
The value of TU.Tagged is NULL but yet it does go into the condition. In mind it does not exist.

It looks like you need something like:
IF EXISTS(SELECT TU.Tagged
FROM TopicUser TU
WHERE TU.TopicId = #TopicId
AND TU.UserId = #UserId
AND TU.Tagged IS NOT NULL)
BEGIN
--do stuff
END
Otherwise, you're checking only if records meeting your criteria exist, but those records could have a NULL value in the TU.Tagged column.

Solution 1 :
Use IsNULL() Function, When below query return null value IsNULL function replace null value with 0 and if condition treated as False.
IF EXISTS (SELECT IsNULL(TU.Tagged,0) FROM TopicUser TU
WHERE TU.TopicId = #TopicId and TU.UserId = #UserId)
BEGIN
END
Solution 2 :
Use (IS NULL OR IS NOT NULL) Property.
IF EXISTS (SELECT TU.Tagged FROM TopicUser TU
WHERE TU.TopicId = #TopicId and TU.UserId = #UserId
AND TU.Tagged IS NOT NULL)
BEGIN
END

To check that something exists you can simply say:
IF EXISTS(SELECT TOP 1 1 FROM TABLE WHERE ID = '2')
This simply returns a 1 if the record exists. For you the record exists but the column is null. You will need to check on the ID of the user. By this I mean even if something is null then it still treats it as existing.
I hope this makes sense.

You can use ISNULL(). when the select query return null for a value and if you want to replace it with O you can use below query.
IF EXISTS(SELECT ISNULL(TU.Tagged,0) FROM TopicUser TU
WHERE TU.TopicId = #TopicId and TU.UserId = #UserId)
BEGIN
--do stuff
END
As Like this You can replace the null with any value you want.

Related

How can I generate a sequence number in a empty table

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

How to use IF within AND in T-SQL

I am trying to create a stored procedure which will use one of the optional parameters provided.
In the code below they are #nStudentId and #nStudentIds set to NULL initially. Only one of them will be sent when the proc is called. When #nStudentIds are sent they will come-in as comma separated values.
CREATE PROCEDURE [dbo].[usp_GetStudentReferrals]
(
#ProfessorId BIGINT,
#nStudentId BIGINT = NULL,
#nStudentIds NVARCHAR(999) = NULL
)
AS
BEGIN
SELECT DISTINCT SR.StudentReferralId
FROM StudentReferral SR WITH(NOLOCK)
INNER JOIN PotentialCandidate PC WITH(NOLOCK) ON PC.PotentialCandidateId = SR.StudentId
WHERE SR.ProfessorId = #nProfessorId
AND -- this is where I am not able to figure out the logic to use either #nStudentId or #nStudentIds, whichever is passed in.
END
So when #nStudentId is sent it should be this in the AND
SR.StudentId = #nStudentId
When #nStudentIds is available I can use 'IN' like so:
SR.StudentId IN (SELECT value FROM STRING_SPLIT #nStudentIds, ','))
The limitation of my knowledge of SQL shows in this IF, which obviously does not work:
AND (if(#nStudentId <> 0 AND #nStudentId <> -1 AND #nStudentId IS NULL)
SR.StudentId = #nStudentId;
else if(#nStudentIds IS NOT NULL)
SR.StudentId IN (SELECT value FROM STRING_SPLIT#nStudentIds,','))
)
Any suggestions are appreciated.
Thanks in advance.
Regards.
There's literally no need for 2 parameters here. Ideally, what you should be using is a table type parameter, as that maintains the strong typing. Then you can just JOIN to said table type parameter:
CREATE TYPE dbo.IDs AS table (ID bigint);
GO
CREATE PROC dbo.usp_GetStudentReferrals #ProfessorId bigint, #StudentIDs dbo.IDs READONLY AS
BEGIN
SELECT DISTINCT SR.StudentReferralId
FROM dbo.StudentReferral SR --WITH(NOLOCK) --Why are you using NOLOCK? You do know what it does, right?
INNER JOIN dbo.PotentialCandidate PC /*WITH(NOLOCK)*/ ON PC.PotentialCandidateId = SR.StudentId --Why are you using NOLOCK? You do know what it does, right?
INNER JOIN #StudentIDs S ON SR.StudentID = S.ID
WHERE SR.ProfessorId = #ProfessorId; --I assumed this should be #ProfessorId not #nProfessorId
END;
GO
Then you would call the procedure with something like:
DECLARE #ProfessorId bigint, #Students dbo.IDs;
SET #ProfessorId = 123456789;
INSERT INTO #Students (ID)
VALUES(987654321),(5643321987342);
EXEC dbo.usp_GetStudentReferrals #ProfessorId, #Students;
why don't you put IF before SELECT
BEGIN
if(#nStudentId <> 0 AND #nStudentId <> -1 AND #nStudentId IS NULL)
SELECT DISTINCT .....
else
SELECT DISTINCT .....
you can using split string from
link
and change this part
AND (if(#nStudentId <> 0 AND #nStudentId <> -1 AND #nStudentId IS NULL)
SR.StudentId = #nStudentId;
else if(#nStudentIds IS NOT NULL)
SR.StudentId IN (SELECT name FROM dbo.splitstring(#nStudentIds))
)

ELSE SELECT nothing/blank

I need to have an 'ELSE' statement for every conditional statement in my stored procedures, how do I return make a procedure return nothing?
IF EXISTS(SELECT 1 FROM Account WHERE Account.username=#Username)
BEGIN
SELECT Status
FROM Account
WHERE Account.username=#Username
END
ELSE
BEGIN
SELECT --nothing/blank
END
Thanks!
You can assign a variable:
IF EXISTS(SELECT 1 FROM Account WHERE Account.username=#Username)
BEGIN
SELECT Status
FROM Account
WHERE Account.username = #Username;
END;
ELSE
BEGIN
DECLARE #X int;
SELECT #X = 0;
END;
Something like this:
IF EXISTS(SELECT 1 FROM Account WHERE Account.username=#Username)
BEGIN
SELECT Status
FROM Account
WHERE Account.username=#Username
END
ELSE
BEGIN
SELECT "No rows found" as Status
END
IF EXISTS(SELECT 1 FROM Account WHERE Account.username=#Username)
BEGIN
SELECT Status
FROM Account
WHERE Account.username=#Username
END
ELSE
BEGIN
SELECT NULL--nothing/blank
END
Try this query
IF EXISTS(SELECT 1 FROM Account WHERE Account.username=#Username)
BEGIN
SELECT Status
FROM Account
WHERE Account.username=#Username
END
ELSE
BEGIN
SELECT NULL as 'Status'--nothing/blank
END
If you want to retrieve the Status value or NULL if there is no matching row you can use a subquery:
select ( select Status from Account where username = #Username ) as Status;
The outer select will always return a result. If the subquery doesn't supply a value then the result will be NULL.
If you want different, i.e. non-NULL, default value you can use Coalesce and a subquery thusly:
select Coalesce(
( select Status from Account where username = #Username ), -- If found.
0 -- Default value if not found.
) as Status;
NB: It is assumed that there is either a single matching row or no matching row. The code will fail if the subquery returns more than one value.
Note that by querying the table only once either solution avoids the possibility of a race condition with another session updating or deleting the row for a user between the exists check and the select that returns the Status value.
if you want to return nothing then no need to write else part.
It will shorten your code and easy to understand.
IF EXISTS(SELECT 1 FROM Account WHERE Account.username=#Username)
BEGIN
SELECT Status
FROM Account
WHERE Account.username=#Username
END
Else part is required when you want to return something else above condition failed.

Return Value Column Name

The stored procedure below works correctly as expected. Returning True if "FleetBarcode" exists and False if it doesn't.
However, when it returns it it displays it as below
(no column name)
True
My problem is I need the "No Column Name" part to have a defined column name. Tried the method below so far which gives the 'True' field an alias.
Thank you for your time.
ALTER proc [dbo].[usp_getjobs]
#barcode as nvarchar(20)
as
SELECT CASE WHEN EXISTS(
SELECT
[FleetBarcode],
[Deleted]
FROM w_DeliveryItems
WHERE FleetBarcode = #barcode
AND Deleted != 1
)
THEN (SELECT 'True' 'Exist')
ELSE (SELECT 'False' 'Exist')
END
Use
ALTER PROC [dbo].[usp_getjobs] #barcode AS NVARCHAR(20)
AS
SELECT CASE
WHEN EXISTS(SELECT [FleetBarcode],
[Deleted]
FROM w_DeliveryItems
WHERE FleetBarcode = #barcode
AND Deleted != 1) THEN 'True'
ELSE 'False'
END AS [Exist]
The alias needs to go on the outer SELECT.
Also for column aliasing it is more common to use square brackets than single quotes.
Get rid if the SELECTs in the THEN/ELSE blocks and use AS to give the column a name:
SELECT CASE WHEN EXISTS(
...
THEN 'True')
ELSE 'False')
END AS [Exist] --<-- add name here
ALTER proc [dbo].[usp_getjobs]
#barcode as nvarchar(20)
as
SELECT CASE WHEN EXISTS(
SELECT
[FleetBarcode],
[Deleted]
FROM w_DeliveryItems
WHERE FleetBarcode = #barcode
AND Deleted != 1
)
THEN (SELECT 'True' 'Exist')
ELSE (SELECT 'False' 'Exist')
END AS [Your Column Name]

How to return sets of values based on condition in SQL Server 2005?

I am a beginner in SQL Server 2005 stored procedure. I can't seem to get it working as wanted.
I have a sp that takes in parameter #caseid from a table called annot. #caseid is assigned to value of column src_caseid and can have multiple references (ref_caseid) or none in table annot. I want to set a condition and set proper shepardsflag depending on the column court from table case which I did using INNER JOIN.
Basically this is the scenario:
Table annot - ref_caseid, src_caseid, annotation
Table case - caseid, court
Example of set of results from the INNER JOIN on ref_caseid = caseid like this:
ref_caseid src_caseid annotation court
17334 17338 Refd high court
17600 17338 Foll federal court
18271 17338 Foll federal court
43220 17338 Not Foll supreme court
Condition to be set:
From the recordset, if federal court exists, it should only take rows of federal court. If NO federal court is found, then it will take other cases with other court values.
To achieve this, I set a counter for federal court counts. But seems that SQL only reads the last row and set #courtFC value based on it. I've tried order by but doesn't seem working as well.
From sample above, the final shepardsflag value of case 17338 should be = 3 (Foll) as it should take rows with "federal court" only AND ignore the rest of the rows.
But the current result is shepardsflag = 2 ; which is wrong
I hope I explain well.
Can someone please help me on the right logic? Should I create a temp table? Thanks in advance.
Script:
ALTER PROCEDURE [dbo].[spUpdateShepardsFlags] #caseid int = null AS
begin
declare #Shep int
declare #ref_caseid int
declare #court int
declare #courtFC int
declare #annot int
if #caseid is not null
begin
select #court = b.court, #ref_caseid = a.ref_caseid, #annot = a.annotation
from cba_annot a inner join cbm_case b on a.ref_caseid = b.caseid
where a.src_caseid = #caseid
if #court is not null
begin
if #court = 'MYFC'
set #courtFC = #courtFC + 1
if #court <> 'MYFC'
SET #courtFC = #courtFC + 0
PRINT 'The #courtFC counter : ' + CAST(#courtFC AS CHAR)
end
if #court is not NULL
begin
if #courtfc > 0
begin
if exists(select a.ref_caseid, b.court, a.annotation, a.src_caseid from
cba_annot a inner join cbm_case b on a.ref_caseid = b.caseid)
begin
if exists(select src_caseid from cba_annot where (annotation like '%Refd%'
or annotation like '%Comp%')
and src_caseid = #caseid)
set #Shep = 4
if exists(select src_caseid from cba_annot where (annotation like '%Foll%'
or annotation like '%Aff%')
and src_caseid = #caseid)
set #ShepFC = 3
update cbm_case
set shepardsflag = #shep
where caseid=#caseid
end
end
else -- if #courtFC = 0
begin --new
if exists(select a.ref_caseid, b.court, a.annotation, a.src_caseid from
cba_annot a inner join cbm_case b on a.ref_caseid = b.caseid)
begin
if exists(select src_caseid from cba_annot where (annotation like '%Refd%'
or annotation like '%Comp%')
and src_caseid = #caseid)
set #Shep = 4
if exists(select src_caseid from cba_annot where (annotation like '%Foll%'
or annotation like '%Aff%')
and src_caseid = #caseid)
set #Shep = 3
if exists(select src_caseid from cba_annot where (annotation like '%Not Foll%'
or annotation like '%Dist%')
and src_caseid = #caseid)
set #Shep = 2
update cbm_case
set shepardsflag = #shep
where caseid=#caseid
end
end -- new
end
else --- if court is NULL -- case not referred by any other case
update cbm_case
set shepardsflag = 5
where caseid=#caseid
end
else -- if caseid is null
-- other condition
You've got some real problems with your understanding of SQL and I seriously doubt that temp tables are relevant.
1) Variables are initialized as null, but that doesn't appear to have significantly messed you up. (#courtFC + 0 doesn't evaluate you way you probably were thinking.)
2) The way you were doing assignments is dependent on order and the last one wins exactly as you noticed. Instead of saying:
select #court = b.court, ...
You could have use this:
select #courtFC = count(b.court) ... where b.court = 'federal court'
It also appears you're trying to write a loop and I think that's another part of your confusion. SQL is about sets, operating on multiple rows at once.
3) All of your EXISTS subqueries in the inner blocks are missing filters on the relevant caseid.
Your approach actually might work with those changes alone.
My version here isn't intended to complicate things but I fear you'll have trouble with it. Here's a set-based solution that really a more natural way.
if #caseid is not null /* short-circuit the update, but probably not necessary */
update cbm_case
set shepardsflag = coalesce(
(
select
case
max( /* highest precendence wins */
case /* map annotations by precedence i.e. */
/* if there are multiple annotations, */
/* which one takes priority */
when a.annotation in ('Refd', 'Comp') then 'P1'
when a.annotation in ('Foll', 'Aff') then 'P2'
when a.annotation in ('Not Foll', 'Dist') then 'P3'
else cast(0/0 as char(2)) /* error, I think */
end
)
when 'P1' then 4 /* translate back to shepardsflag */
when 'P2' then 3
when 'P3' then 2
end
from
cba_annot as a inner join cbm_case as refcase
on refcase.caseid = a.ref_caseid
where
a.src_caseid = cbm_case.caseid
and (
cbm_case.court <> 'federal court' /* all if src case not federal */
or refcase.court = 'federal court' /* always get federal */
)
),
5
)
where caseid = #caseid;
Edit 2
Ignore my comment in 3). Looking again I think I had misread OP's code because of the parenthesis and line break.
Edit 3
Fixed error caused by missing # character in first line.