SQL CASE wrong output - sql

I have this weird encounter using CASE in sql 2014.
This is my query:
SELECT (CASE WHEN dbo.GetFunctionAge(C.Birthdate) = 0
THEN '' ELSE dbo.GetFunctionAge(C.Birthdate)
END) AS Age
,dbo.GetFunctionAge(C.Birthdate)
,c.Birthdate
FROM Client C
WHERE ClientID = '34d0d845-e3a6-4078-8936-953ff3378eac'
this is the output:
Here is the GetFunctionAge function if you might ask.
IF EXISTS (
SELECT *
FROM dbo.sysobjects
WHERE ID = OBJECT_ID(N'[dbo].[GetFunctionAge]') AND
xtype in (N'FN', N'IF', N'TF'))
DROP FUNCTION [dbo].[GetFunctionAge]
GO
CREATE FUNCTION [dbo].[GetFunctionAge](#BirthDate DATETIME)
RETURNS INT
AS
BEGIN
DECLARE #Age INT
IF(#BirthDate = '1753-01-01 00:00:00.000')
BEGIN
SET #Age = 0
END
ELSE
BEGIN
SET #Age = DATEDIFF(hour,#BirthDate,GETDATE())/8766
END
RETURN #Age
END
GO
Question:
Why is Column Age in my output is 0which should be ''?
I added (No column name) to show that its output is 0 so my expected output base from my case condition is '' not 0
I didn't receive any error regarding inconsistency of data so why is case behaving like that?
Thanks for those who could clarify this to me.

SELECT
(CASE
WHEN a.ageint = 0 THEN ''
ELSE cast(a.ageint as varchar(3))
END) AS Age
, a.ageint
, c.Birthdate
FROM Client as C
CROSS APPLY (
SELECT
ISNULL(dbo.GetFunctionAge(C.Birthdate), 0) AS ageint
) AS a
WHERE ClientID = '34d0d845-e3a6-4078-8936-953ff3378eac'
;

You can cast it into varchar so you can return ' '.
SELECT (CASE WHEN dbo.GetFunctionAge(C.Birthdate) = 0
THEN '' ELSE Cast(dbo.GetFunctionAge(C.Birthdate) as varchar(5))
END) AS Age
,dbo.GetFunctionAge(C.Birthdate)
,c.Birthdate
FROM Client C
WHERE ClientID = '34d0d845-e3a6-4078-8936-953ff3378eac'
But If you wish to remain your Age column in data type int.
You could just use NULL instead of ' '

Related

Add column name to a variable and use it in later calculation in WHERE clause

I have a problem. I need to determine the name of the column under which the calculations will continue. So I wrote a select:
DECLARE #column VARCHAR(MAX)
DECLARE #ColumnA VARCHAR(MAX)
DECLARE #ColumnB VARCHAR(MAX)
SET #ColumnA = 'RegistrationDate'
SET #ColumnB = 'EntryDate'
SET #column = CASE
WHEN CONVERT(DATE,GETDATE()) NOT IN (
'2021-08-04','2021-08-05','2021-08-06','2021-08-07','2021-08-08','2021-08-09','2021-08-10','2021-09-07','2021-09-08','2021-09-09','2021-09-10','2021-09-11',
'2021-09-12','2021-09-13','2021-10-05','2021-10-06','2021-10-07','2021-10-08','2021-10-09','2021-10-10','2021-10-11','2021-11-09','2021-11-10','2021-11-11','2021-11-12','2021-11-13','2021-11-14','2021-11-15','2021-12-07',
'2021-12-08','2021-12-09','2021-12-10','2021-12-11','2021-12-12','2021-12-13'
) THEN
QUOTENAME(#Column)
ELSE
QUOTENAME(#ColumnB)
END
SELECT #column
which returns me [RegistrationDate] or [EntryDate] and stores this in variable #column. Now, when I know under which column should I calculate, I want to insert this variable #column in to my main select one of the WHERE clause:
DECLARE #column VARCHAR(MAX)
DECLARE #ColumnA VARCHAR(MAX)
DECLARE #ColumnB VARCHAR(MAX)
SET #ColumnA = 'RegistrationDate'
SET #ColumnB = 'EntryDate'
SET #column = CASE
WHEN CONVERT(DATE,GETDATE()) NOT IN (
'2021-08-04','2021-08-05','2021-08-06','2021-08-07','2021-08-08','2021-08-09','2021-08-10','2021-09-07','2021-09-08','2021-09-09','2021-09-10','2021-09-11',
'2021-09-12','2021-09-13','2021-10-05','2021-10-06','2021-10-07','2021-10-08','2021-10-09','2021-10-10','2021-10-11','2021-11-09','2021-11-10','2021-11-11','2021-11-12','2021-11-13','2021-11-14','2021-11-15','2021-12-07',
'2021-12-08','2021-12-09','2021-12-10','2021-12-11','2021-12-12','2021-12-13'
) THEN
QUOTENAME(#Column)
ELSE
QUOTENAME(#ColumnB)
END
SELECT
CASE WHEN final.Branch IS NULL THEN 'Total'
ELSE final.Branch
END AS 'Branch',
final.TR
FROM
(
SELECT
CASE
WHEN main.BRANCHNO = 1 THEN 'One'
WHEN main.BRANCHNO = 2 THEN 'Two'
WHEN main.BRANCHNO = 3 THEN 'Three'
WHEN main.BRANCHNO = 4 THEN 'Four'
WHEN main.BRANCHNO = 5 THEN 'Five'
WHEN main.BRANCHNO = 6 THEN 'Six'
END AS 'Branch',
COUNT(*) AS 'TR'
FROM
(
SELECT
*
FROM
[TABLE]
WHERE
Status = 100
AND
BRANCHNO IN (1,2,3,4,5,6)
AND
Type = 'TR'
AND
**#column** = CONVERT(DATE, CASE WHEN DATENAME(dw, getdate()) = 'Monday' THEN getdate()-3 ELSE getdate()-1 END
)
) AS main
GROUP BY
main.BRANCHNO WITH ROLLUP
) AS final
But when I execute query it returns me an error:
Msg 241, Level 16, State 1, Line 11 Conversion failed when converting
date and/or time from character string.
I imagined everything very simple: I put a column name into a variable, and then, that name placed at the beginning of the WHERE clause will be recognized as the column name and then *= CONVERT(DATE, CASE WHEN DATENAME(dw, getdate()) etc will do all work.
But that did not happen. Maybe someone knows why and maybe they know how to solve this task?
You can't use a variable to reference a column name. #column is just a piece of data, which just so happens to contain a column name as a string, but it's still just a string, not actually a reference to a column in a table.
Some options you have seem to be...
AND CASE #column WHEN 'RegistrationDate' THEN RegistrationDate
WHEN 'EntryDate' THEN EntryDate
END
=
CONVERT(DATE, CASE WHEN DATENAME(dw, getdate()) = 'Monday' THEN getdate()-3 ELSE getdate()-1 END)
Or, have two queries which only differ in the column being referenced...
IF (#column = 'RegistrationDate')
<query1>
ELSE IF (#column = 'EntryDate')
<query2>
Or "Dynamic SQL" where you build up a new string with your SQL code and execute that by call sp_executesql (assuming this is SQL Server, which it appears to be).
I recommend reading this : https://www.sommarskog.se/dyn-search.html
EDIT: A pure SQL alternative, assuming SQL Server
DECLARE #mode INT = CASE
WHEN CONVERT(DATE,GETDATE()) NOT IN (
'2021-08-04','2021-08-05','2021-08-06','2021-08-07','2021-08-08','2021-08-09','2021-08-10','2021-09-07','2021-09-08','2021-09-09','2021-09-10','2021-09-11',
'2021-09-12','2021-09-13','2021-10-05','2021-10-06','2021-10-07','2021-10-08','2021-10-09','2021-10-10','2021-10-11','2021-11-09','2021-11-10','2021-11-11','2021-11-12','2021-11-13','2021-11-14','2021-11-15','2021-12-07',
'2021-12-08','2021-12-09','2021-12-10','2021-12-11','2021-12-12','2021-12-13'
) THEN
0
ELSE
1
END;
DECLARE #filter_date DATE = CONVERT(DATE, CASE WHEN DATENAME(dw, getdate()) = 'Monday' THEN getdate()-3 ELSE getdate()-1 END;
WITH
source AS
(
SELECT
*
FROM
[TABLE]
WHERE
Status = 100
AND BRANCHNO IN (1,2,3,4,5,6)
AND Type = 'TR'
),
filtered_source AS
(
SELECT 0 AS mode, * FROM source WHERE RegistrationDate = #filter_date
UNION ALL
SELECT 1 AS mode, * FROM source WHERE EntryDate = #filter_date
)
SELECT
COALESCE(
CASE
WHEN BRANCHNO = 1 THEN 'One'
WHEN BRANCHNO = 2 THEN 'Two'
WHEN BRANCHNO = 3 THEN 'Three'
WHEN BRANCHNO = 4 THEN 'Four'
WHEN BRANCHNO = 5 THEN 'Five'
WHEN BRANCHNO = 6 THEN 'Six'
END,
'Total'
)
AS 'Branch',
COUNT(*) AS 'TR'
FROM
filtered_source
WHERE
mode = #mode
GROUP BY
GROUPING SETS (
(mode),
(mode, BRANCHNO)
);
By always including mode in the GROUPING SETS, the optimiser might be able to yield a better execution plan for the two scenarios.
Still read the link given above though, at the very least to understand why this is necessary, or perhaps why it doesn't quite manage to yield the best execution plan.

Conversion failed when converting the varchar value to data type bit in sql server

Here i try to convert a bit value to varchar , i try this query in MS sql server
CASE WHEN cast(ISNULL(O.isTerminated,0)as varchar) = 1 THEN 'Yes' ELSE '' END AS isTerminated.
Is giving error "Conversion failed when converting the varchar value 'Yes' to data type bit."
what will be the solution for this.
The error is not caused by the statement you are showing but by what you do with your isTerminated alias afterwards.
Your statement as is doesn't throw any errors.
DECLARE #isTerminated BIT = 1
SELECT CASE WHEN CAST(ISNULL(#isTerminated, 0) AS VARCHAR) = 1
THEN 'yes'
ELSE ''
END AS isTerminated
But treating the aliased isTerminated as a bit does.
DECLARE #isTerminated BIT = 1
SELECT *
FROM (SELECT CASE WHEN CAST(ISNULL(#isTerminated, 0) AS VARCHAR) = 1
THEN 'yes'
ELSE ''
END AS isTerminated) t
WHERE isTerminated = 1 -- isTerminated is a VARCHAR at this point
Why are you casting the bit to a varchar. Can you just do this:
CASE WHEN ISNULL(O.isTerminated,0) = 1 THEN 'Yes' ELSE '' END AS isTerminated
EDIT
When trying this example.
DECLARE #T TABLE(isTerminated BIT)
INSERT INTO #T
VALUES(1),(NULL),(0)
SELECT
CASE WHEN ISNULL(O.isTerminated,0) = 1 THEN 'Yes' ELSE '' END AS isTerminated
FROM
#T AS O
With your case statement. I don't revise a error. Are you missing out any details?

Assign to a T-SQL variable from a CASE statement

I'd like to assign some variables inside a query that uses CASE statements for it's columns. Not quite sure how to do this, having trouble finding the right syntax.
This is what I have so far, but it's got syntax errors.
-- set #theID and #theName with their appropriate values
select top (1)
#theID = (Case when B.ID IS NULL then A.ID else B.ID END) ,
#theName = (Case when B.Name IS NULL then A.Name else B.Name END)
from B left join A on A.ID = B.ID where ...
What's the correct place/way to stick those variables in there?
The example you've given should work. You can assign to variables from a case statement. Just pretend that the entire CASE..WHEN..THEN..ELSE..END block is a field. Here is a generic example:
declare #string1 nvarchar(100) = null
declare #string2 nvarchar(100) = null
select
#string1 = case when 1=1 then 'yes' else 'no' end
,#string2 = case when 1=0 then 'yes' else 'no' end
print 'string1 = ' + #string1
print 'string2 = ' + #string2
Gives:
string1 = yes
string2 = no
Can you tell us what specific error(s) you are getting?
You could probably do this more easily using ISNULL or COALESCE:
select top (1)
#theID = ISNULL(B.ID, A.ID),
#theName = ISNULL(B.Name, A.Name),
from B left join A on A.ID = B.ID where ...
DECLARE #SmallBlindSeatId INT
DECLARE #BigBlindSeatId INT
DECLARE #DealerSeatId INT
DECLARE #NextTurn INT
SELECT #DealerSeatId=( CASE WHEN BlindsInfo=1 THEN SeatId ELSE #DealerSeatId END ),
#SmallBlindSeatId=( CASE WHEN BlindsInfo=2 THEN SeatId ELSE #SmallBlindSeatId END),
#BigBlindSeatId=( CASE WHEN BlindsInfo=3 THEN SeatId ELSE #BigBlindSeatId END),
#NextTurn=( CASE WHEN NEXTTURN=1 THEN SeatId ELSE #NextTurn END)
FROM ABC WHERE TESTCASEID=1
PRINT(#DealerSeatId)
PRINT(#SmallBlindSeatId)
PRINT(#BigBlindSeatId)
PRINT (#NextTurn)

checking if condition in stored procedure( sql server 2005)

i have an SP where i need to check for if condition
ALTER PROCEDURE [dbo].[spCheck]
#strEmpname VARCHAR(50),
#intReturn INT OUTPUT,
#intWorkdID INT,
#intEmpID INT
AS
BEGIN
IF(#intWorkdID is not null and #intWorkdID != '')
BEGIN
IF EXISTS ( SELECT *
FROM Employee
WHERE [Empname] = #strEmpname
AND WorkID = #intWorkdID
)
SELECT #intReturn = '1'
END
ELSE
IF(#intEmpID is not null and #intEmpID != '')
BEGIN
IF EXISTS ( SELECT *
FROM Employee
WHERE [Empname] = #strEmpname
AND PeopleID = #intEmpID
)
SELECT #intReturn = '1'
END
ELSE IF(#intEmpID is not null and #intEmpID != '')
and(#intWorkdID is not null and #intWorkdID != '')
BEGIN
SELECT #intReturn = '0'
END
END
here based on WorkID,EmpID
1 condition and 2 condition should execute
if both condition fail i need to excute the third condition
can any one tell the syntax for it
thanks
prince
Best way is that you can use
Try something as below:
SELECT #intReturn =
CASE
WHEN #intWorkdID IS NULL THEN 1
WHEN #intWorkdID<>'' THEN 1
WHEN #intEmpID IS NULL THEN 1
WHEN #intEmpID <>'' THEN 1
ELSE 0
END
Case... When
for this
An int can't equal ''.
I'm not sure what you're asking for in your logic, but when an if doesn't match then it runs the else part. You can then have anpther if -> else after that as per your script.

SQL Switch/Case in 'where' clause

I tried searching around, but I couldn't find anything that would help me out.
I'm trying to do this in SQL:
declare #locationType varchar(50);
declare #locationID int;
SELECT column1, column2
FROM viewWhatever
WHERE
CASE #locationType
WHEN 'location' THEN account_location = #locationID
WHEN 'area' THEN xxx_location_area = #locationID
WHEN 'division' THEN xxx_location_division = #locationID
I know that I shouldn't have to put '= #locationID' at the end of each one, but I can't get the syntax even close to being correct. SQL keeps complaining about my '=' on the first WHEN line...
How can I do this?
declare #locationType varchar(50);
declare #locationID int;
SELECT column1, column2
FROM viewWhatever
WHERE
#locationID =
CASE #locationType
WHEN 'location' THEN account_location
WHEN 'area' THEN xxx_location_area
WHEN 'division' THEN xxx_location_division
END
without a case statement...
SELECT column1, column2
FROM viewWhatever
WHERE
(#locationType = 'location' AND account_location = #locationID)
OR
(#locationType = 'area' AND xxx_location_area = #locationID)
OR
(#locationType = 'division' AND xxx_location_division = #locationID)
Here you go.
SELECT
column1,
column2
FROM
viewWhatever
WHERE
CASE
WHEN #locationType = 'location' AND account_location = #locationID THEN 1
WHEN #locationType = 'area' AND xxx_location_area = #locationID THEN 1
WHEN #locationType = 'division' AND xxx_location_division = #locationID THEN 1
ELSE 0
END = 1
I'd say this is an indicator of a flawed table structure. Perhaps the different location types should be separated in different tables, enabling you to do much richer querying and also avoid having superfluous columns around.
If you're unable to change the structure, something like the below might work:
SELECT
*
FROM
Test
WHERE
Account_Location = (
CASE LocationType
WHEN 'location' THEN #locationID
ELSE Account_Location
END
)
AND
Account_Location_Area = (
CASE LocationType
WHEN 'area' THEN #locationID
ELSE Account_Location_Area
END
)
And so forth... We can't change the structure of the query on the fly, but we can override it by making the predicates equal themselves out.
EDIT: The above suggestions are of course much better, just ignore mine.
The problem with this is that when the SQL engine goes to evaluate the expression, it checks the FROM portion to pull the proper tables, and then the WHERE portion to provide some base criteria, so it cannot properly evaluate a dynamic condition on which column to check against.
You can use a WHERE clause when you're checking the WHERE criteria in the predicate, such as
WHERE account_location = CASE #locationType
WHEN 'business' THEN 45
WHEN 'area' THEN 52
END
so in your particular case, you're going to need put the query into a stored procedure or create three separate queries.
OR operator can be alternative of case when in where condition
ALTER PROCEDURE [dbo].[RPT_340bClinicDrugInventorySummary]
-- Add the parameters for the stored procedure here
#ClinicId BIGINT = 0,
#selecttype int,
#selectedValue varchar (50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
SELECT
drugstock_drugname.n_cur_bal,drugname.cdrugname,clinic.cclinicname
FROM drugstock_drugname
INNER JOIN drugname ON drugstock_drugname.drugnameid_FK = drugname.drugnameid_PK
INNER JOIN drugstock_drugndc ON drugname.drugnameid_PK = drugstock_drugndc.drugnameid_FK
INNER JOIN drugndc ON drugstock_drugndc.drugndcid_FK = drugndc.drugid_PK
LEFT JOIN clinic ON drugstock_drugname.clinicid_FK = clinic.clinicid_PK
WHERE (#ClinicId = 0 AND 1 = 1)
OR (#ClinicId != 0 AND drugstock_drugname.clinicid_FK = #ClinicId)
-- Alternative Case When You can use OR
AND ((#selecttype = 1 AND 1 = 1)
OR (#selecttype = 2 AND drugname.drugnameid_PK = #selectedValue)
OR (#selecttype = 3 AND drugndc.drugid_PK = #selectedValue)
OR (#selecttype = 4 AND drugname.cdrugclass = 'C2')
OR (#selecttype = 5 AND LEFT(drugname.cdrugclass, 1) = 'C'))
ORDER BY clinic.cclinicname, drugname.cdrugname
END
Please try this query.
Answer To above post:
select #msgID, account_id
from viewMailAccountsHeirachy
where
CASE #smartLocationType
WHEN 'store' THEN account_location
WHEN 'area' THEN xxx_location_area
WHEN 'division' THEN xxx_location_division
WHEN 'company' THEN xxx_location_company
END = #smartLocation
Try this:
WHERE (
#smartLocationType IS NULL
OR account_location = (
CASE
WHEN #smartLocationType IS NOT NULL
THEN #smartLocationType
ELSE account_location
END
)
)
CREATE PROCEDURE [dbo].[Temp_Proc_Select_City]
#StateId INT
AS
BEGIN
SELECT * FROM tbl_City
WHERE
#StateID = CASE WHEN ISNULL(#StateId,0) = 0 THEN 0 ELSE StateId END ORDER BY CityName
END
Try this query, it's very easy and useful: Its ready to execute!
USE tempdb
GO
IF NOT OBJECT_ID('Tempdb..Contacts') IS NULL
DROP TABLE Contacts
CREATE TABLE Contacts(ID INT, FirstName VARCHAR(100), LastName VARCHAR(100))
INSERT INTO Contacts (ID, FirstName, LastName)
SELECT 1, 'Omid', 'Karami'
UNION ALL
SELECT 2, 'Alen', 'Fars'
UNION ALL
SELECT 3, 'Sharon', 'b'
UNION ALL
SELECT 4, 'Poja', 'Kar'
UNION ALL
SELECT 5, 'Ryan', 'Lasr'
GO
DECLARE #FirstName VARCHAR(100)
SET #FirstName = 'Omid'
DECLARE #LastName VARCHAR(100)
SET #LastName = ''
SELECT FirstName, LastName
FROM Contacts
WHERE
FirstName = CASE
WHEN LEN(#FirstName) > 0 THEN #FirstName
ELSE FirstName
END
AND
LastName = CASE
WHEN LEN(#LastName) > 0 THEN #LastName
ELSE LastName
END
GO
In general you can manage case of different where conditions in this way
SELECT *
FROM viewWhatever
WHERE 1=(CASE <case column or variable>
WHEN '<value1>' THEN IIF(<where condition 1>,1,0)
WHEN '<value2>' THEN IIF(<where condition 2>,1,0)
ELSE IIF(<else condition>,1,0)
END)
Case Statement in SQL Server Example
Syntax
CASE [ expression ]
WHEN condition_1 THEN result_1
WHEN condition_2 THEN result_2
...
WHEN condition_n THEN result_n
ELSE result
END
Example
SELECT contact_id,
CASE website_id
WHEN 1 THEN 'TechOnTheNet.com'
WHEN 2 THEN 'CheckYourMath.com'
ELSE 'BigActivities.com'
END
FROM contacts;
OR
SELECT contact_id,
CASE
WHEN website_id = 1 THEN 'TechOnTheNet.com'
WHEN website_id = 2 THEN 'CheckYourMath.com'
ELSE 'BigActivities.com'
END
FROM contacts;
This worked for me.
CREATE TABLE PER_CAL ( CAL_YEAR INT, CAL_PER INT )
INSERT INTO PER_CAL( CAL_YEAR, CAL_PER ) VALUES ( 20,1 ), ( 20,2 ), ( 20,3 ), ( 20,4 ), ( 20,5 ), ( 20,6 ), ( 20,7 ), ( 20,8 ), ( 20,9 ), ( 20,10 ), ( 20,11 ), ( 20,12 ),
( 99,1 ), ( 99,2 ), ( 99,3 ), ( 99,4 ), ( 99,5 ), ( 99,6 ), ( 99,7 ), ( 99,8 ), ( 99,9 ), ( 99,10 ), ( 99,11 ), ( 99,12 )
The 4 digit century is determined by the rule, if the year is 50 or more, the century is 1900, otherwise 2000.
Given two 6 digit periods that mark the start and end period, like a quarter, return the rows that fall in that range.
-- 1st quarter of 2020
SELECT * FROM PER_CAL WHERE (( CASE WHEN CAL_YEAR > 50 THEN 1900 ELSE 2000 END + CAL_YEAR ) * 100 + CAL_PER ) BETWEEN 202001 AND 202003
-- 4th quarter of 1999
SELECT * FROM PER_CAL WHERE (( CASE WHEN CAL_YEAR > 50 THEN 1900 ELSE 2000 END + CAL_YEAR ) * 100 + CAL_PER ) BETWEEN 199910 AND 199912
Try this query. Its very easy to understand:
CREATE TABLE PersonsDetail(FirstName nvarchar(20), LastName nvarchar(20), GenderID int);
GO
INSERT INTO PersonsDetail VALUES(N'Gourav', N'Bhatia', 2),
(N'Ramesh', N'Kumar', 1),
(N'Ram', N'Lal', 2),
(N'Sunil', N'Kumar', 3),
(N'Sunny', N'Sehgal', 1),
(N'Malkeet', N'Shaoul', 3),
(N'Jassy', N'Sohal', 2);
GO
SELECT FirstName, LastName, Gender =
CASE GenderID
WHEN 1 THEN 'Male'
WHEN 2 THEN 'Female'
ELSE 'Unknown'
END
FROM PersonsDetail