Set prefix in SQL CASE expression - sql

I have problem setting a prefix in a case statement.
Data set:
missionid:
5505
5506
select
CASE
WHEN m.EXTLOCATIONID is not null THEN '01' + convert(nvarchar(50),m.missionid)
ELSE tg.ID_ACTIVITY
END as Barcode2
from MISSION m
left join TASKGROUP tg with(nolock) on m.MMPICKLISTID = tg.ID
When I run this query my result is this:
Barcode2:
15505
15506
Desired result is this:
015505
015506
As one can see, the first zero is not shown in the result. How can I achieve this?

CASE expression would always return one type so, you need to do conversion:
CASE WHEN m.EXTLOCATIONID is not null
THEN '01' + convert(nvarchar(50), m.missionid)
ELSE CONVERT(VARCHAR(255), tg.ID_ACTIVITY)
END as Barcode2

A case expression returns a single type. And, if different paths return different types -- say a string and a number -- then the result is a number. Those are the rules of SQL.
You are also mixing national character sets with "regular" characters. That seems unnecessary. I would recommend:
(CASE WHEN m.EXTLOCATIONID is not null
THEN CONCAT('01', m.missionid)
ELSE CONVERT(VARCHAR(255), tg.ID_ACTIVITY)
END) as Barcode2

Related

How to perform Case statement inside a select statement?

I wanted to put 'No record' on the column instead of NULL if the datediff function returns a null value.
SELECT concat(e.firstname ,e.lastname) as Fullname,c.shiftcode as Shift, cast(c.datecheckinout as date) Date,datename(month, c.datecheckinout) as RecordMonth,c.timein , c.timeout,
CAST(
CASE
WHEN (datediff(HOUR,c.timein,c.timeout) IS NULL)
THEN 'No record'
END
), FROM tblCheckInOutDetail c RIGHT JOIN tblEmployee e on e.IdEmployee = c.IdEmployee WHERE e.IdEmployee = 55
So far this code only throws Incorrect syntax near 'CAST', expected 'AS'. but I don't know what data type should I put in the CAST parameter , since if there's a record it will show the datetime .
You need to convert the number value to a string. For this, you can use coalesce():
SELECT concat(e.firstname ,e.lastname) as Fullname,c.shiftcode as Shift, cast(c.datecheckinout as date) Date,datename(month, c.datecheckinout) as RecordMonth,c.timein , c.timeout,
COALESCE(CAST(datediff(HOUR, c.timein, c.timeout) AS VARCHAR(255)), 'No record')
FROM tblEmployee e LEFT JOIN
tblCheckInOutDetail c
ON e.IdEmployee = c.IdEmployee
WHERE e.IdEmployee = 55;
Note: I switched the RIGHT JOIN to a LEFT JOIN. They are equivalent logically. But most people find it much easier to follow the logic of the LEFT JOIN, because the table that defines the rows is the first table being read in the FROM clause.
Strictly answering question (though I don't understand why you need a CASE expression if you have working versions of the query), you can easily translate this to a CASE expression:
ISNULL(CAST(datediff(HOUR,c.timein,c.timeout) as varchar),'No Record')
ISNULL really is just nice, convenient shorthand for CASE WHEN a IS NOT NULL THEN a ELSE b END, so:
CASE WHEN DATEDIFF(HOUR, c.timein, c.timeout) IS NOT NULL
THEN CAST(datediff(HOUR,c.timein,c.timeout) as varchar(11))
ELSE 'No Record' END
As you can see, a downside is that if you really really really want a CASE expression, you have to repeat at least the DATEDIFF to cover both the case where the outer row doesn't exist and the case where the outer row exists but one of the values is NULL.
Also note that you should always specify a length for variable types like varchar, even in cases where you think you're safe with the default.
I don't know if this is the correct option or usage.
but this works for me :
ISNULL(CAST(datediff(HOUR,c.timein,c.timeout) as varchar),'No Record')
But can you guys show me how to do this using case expression?

CASE expression for NULL condition is not working

I have an SQL query where the case expression is not working because I am getting the NULL value.
Any idea how to fix this?
select
td.reportEndDate,
CASE td.originalLinearAirDate
WHEN NULL THEN '12345678'
END As originalLinearAirDate
from
FROM DBA.Telecast td
where id = 2
order by
td.reportEndDate,
originalLinearAirDate;
You can use isnull
select
td.reportEndDate,
CASE WHEN td.originalLinearAirDate IS NULL THEN '19000101'
ELSE td.originalLinearAirDate
END As originalLinearAirDate
from
FROM DBA.Telecast td
where id = 2
order by
td.reportEndDate,
originalLinearAirDate;
You can use COALESCE() :
SELECT td.reportEndDate,
COALESCE(td.originalLinearAirDate, '12345678') AS originalLinearAirDate -- Use default date instead of '12345678'
FROM DBA.Telecast td
WHERE id = 2
ORDER BY td.reportEndDate, originalLinearAirDate;
In your case expression you didn't specified ELSE part hence you got NULL.
However, case expression will only return one type. So, you should check code or do necessary conversation.
The problem is the NULL comparison. The comparison is never true, even when used from comparison in a CASE expression.
If you wanted to do this using CASE, then you need to use IS NULL:
(CASE WHEN td.originalLinearAirDate IS NULL
THEN '12345678'
END) As originalLinearAirDate
If you want to return the original value in this case, you need an ELSE:
(CASE WHEN td.originalLinearAirDate IS NULL
THEN '12345678'
ELSE td.originalLinearAirDate
END) As originalLinearAirDate
Note that this will return an error if the column is really a DATE, because '12345678' cannot be converted to a date.
This version is better expressed using COALESCE():
COALESCE(td.originalLinearAirDate, '12345678')

View causing Invalid length parameter passed to the LEFT or SUBSTRING function error when providing where clause

I'm having an odd thing occurring in one of my views. Initially, I have a view that does the following:
SELECT id, CAST((CASE WHEN
LEN(line) = 1
THEN ISNULL(LTRIM(RTRIM(line)), '-1')
ELSE
ISNULL(LTRIM(RTRIM(SUBSTRING(line, 1, (CHARINDEX(CHAR(9),
line) - 1)))), '-1')
END) AS varchar(MAX)) AS ObjMarker
FROM dbo.tblM2016_RAW_Current_Import_File
WHERE ((CASE WHEN
LEN(line) = 1
THEN ISNULL(LTRIM(RTRIM(line)), '')
ELSE
LTRIM(RTRIM(SUBSTRING([line], 1, CHARINDEX(CHAR(9), [line]))))
END) <> CHAR(9))
AND
((CASE WHEN
LEN(line) = 1
THEN ISNULL(LTRIM(RTRIM(line)), '')
ELSE
LTRIM(RTRIM(SUBSTRING([line], 1, CHARINDEX(CHAR(9), [line]))))
END) NOT LIKE '%*%')
AND
((CASE WHEN
LEN(line) = 1
THEN ISNULL(LTRIM(RTRIM(line)), '')
ELSE LTRIM(RTRIM(SUBSTRING([line], 1, CHARINDEX(CHAR(9),
[line])))) END) <> '')
And it works fine. However, I have another view which uses the results of the above view, shown below:
SELECT curr.id
,curr.ObjMarker
,Nxt.id AS NxtID
,Nxt.ObjMarker AS NxtObjMarker
,Nxt.id - curr.id - 2 AS OFFSET
,curr.id + 1 AS StrtRec
,Nxt.id - 1 AS EndRec
FROM dbo.vwM2016_RAW_Import_File_Object_Line_Markers AS curr
LEFT OUTER JOIN
dbo.vwM2016_RAW_Import_File_Object_Line_Markers AS Nxt ON
Nxt.id =
(SELECT MIN(id) AS Expr1
FROM dbo.vwM2016_RAW_Import_File_Object_Line_Markers AS source
WHERE (id > curr.id))
WHERE curr.ObjMarker <> '0'
And apparently, if I leave the WHERE curr.ObjMarker <> '0' in the second query, it gives the error
Msg 537, Level 16, State 3, Line 1
Invalid length parameter passed to the LEFT or SUBSTRING function.
But if I remove WHERE curr.ObjMarker <> '0' it returns the result set without error.
Could this be a problem with the query optimizer not doing operations in order? I've checked the rows where 0 occurs for any special characters in an editor and I couldn't find any hidden whitespace characters or anything.
There's no guarantee of the order the criteria in your select statements will be evaluated, and SQL Server does not short circuit. Predicate pushdown can also happen for any criteria SQL Server estimates to be useful -- so you can't assume that a certain criteria will always be evaluated before something else.
The problem is with this expression:
ISNULL(LTRIM(RTRIM(SUBSTRING(line, 1, (CHARINDEX(CHAR(9),
line) - 1)))), '-1')
If [line] does not contain a Char(9), the CharIndex field returns 0. This turns the substring expression into SUBSTRING(line,1,-1), which is invalid because the length cannot be a negative number.
When not used in the WHERE clause, the expression is not evaluated until after the other filters are applied and the result set is reduced. At least one of the filters in the view eliminate the rows without tabs, so the expression never operates on those rows.
However, when the expression is used in the WHERE clause, it is combined with the view filters and evaluated in the order that SQL Server determines is best for performance. Unfortunately, some of the rows without tabs are still part of the result set when this is evaluated, causing the result to fail.
A possible fix, add an explicit test in your case statement (in the first view where you define objMarker) to address rows that do not contain tabs.
WHEN CHARINDEX(CHAR(9), line) = 0 THEN '-1'

Not Equal logic trouble in SQL Server

I can't believe I'm having so much trouble with this.
Using this statement:
USE XXXX
SELECT
ID, DESCRIPTION, STATUS
FROM
PART
WHERE
PART.ID LIKE 'PCH%'
AND PART.DESCRIPTION NOT LIKE '%OBSOLETE%'
AND PART.STATUS = 'O'
I get a table with 34 entries, each of them containing O in PART.STATUS.
What I actually want to say is, only show me the values which do NOT have a status of O. I know there are other ways around this. values that are not O should be null, but I'm annoyed that I can't figure out how the 'not equal' statement works. When I switch the last line to:
AND PART.STATUS <> 'O'
OR
AND PART.STATUS != 'O'
I get an empty table returned.
If I use the line
AND PART.STATUS IS NULL
I get the table I'm looking for.
What am I misunderstanding about the use of 'not equal statements'?
The problem is 3 valued predicate logic. When at least one side of predicate is NULL the result of predicate is UNKNOWN(no matter you use = or <> or > or <, ...), but WHERE clause only returns rows where predicate evaluates to TRUE. So our job is to make predicate to evaluate to TRUE when PART.STATUS IS NULL. This is done by adding additional check on NULL like:
USE XXXX
SELECT ID, DESCRIPTION,STATUS
FROM PART
WHERE
PART.ID LIKE 'PCH%'
AND PART.DESCRIPTION NOT LIKE '%OBSOLETE%'
AND (PART.STATUS <> 'O' OR PART.STATUS IS NULL)
Here is a little example. Imagine this is your table and you are issuing your statement WHERE PART.STATUS <> 'O'
PART(STATUS)
'A'
'O'
NULL
It evaluates to:
WHERE 'A' <> 'O' --TRUE
WHERE 'O' <> 'O' --FALSE
WHERE NULL <> 'O'--UNKNOWN
Since WHERE clause returns only rows where result of predicate is TRUE, you will get only 'A' here.
the issue here is with the nullvalue since every logical comparation against it would return false for example
PART.STATUS = NULL-- Would be false
PART.STATUS <> NULL-- would also return false
so you should do your comparison like
AND (PART.STATUS <> 'O' OR PART.STATUS IS NULL)
The part you're missing is that NULL is not a value, but the absence of it. A NULL means that the value in that field is either inexistent or unknown. That's why you cant' directly compare a value to a NULL. As stated in other answers, you have to use PART.STATUS IS NULL. Another option would be to use the ISNULL function, wich will test a value for NULL and, if it is, will return whatever value you specify on the second parameter. E.g.
USE XXXX
SELECT ID, DESCRIPTION,STATUS
FROM PART
WHERE
PART.ID LIKE 'PCH%'
AND PART.DESCRIPTION NOT LIKE '%OBSOLETE%'
AND ISNULL(PART.STATUS, '') <> 'O'
Check the documentation for NULL in Sql Server and the ISNULL function. Also, this question could be of use.
USE XXXX
SELECT ID, DESCRIPTION,STATUS
FROM PART
WHERE
PART.ID LIKE 'PCH%'
AND PART.DESCRIPTION NOT LIKE '%OBSOLETE%'
OR PART.STATUS != 'O'
Maybe your misunderstanding is probably about the NULL concept. NULL is not an empty string neither different from 'O', it's just NULL.
That's why you have to use
AND PART.STATUS IS NULL
or
AND isnull(PART.STATUS, '') <> 'O'
It is important to remember how NULL is treated in a database. It isn't a value at all!
No operator (>,<,=.. etc) less (is) used will ever return rows with NULL.
writing in SQL "where column = NULL" is like saying "give me all rows where the value isn't a value
Null values can't be compared with equals(=) or not equals operators. Try the below:
USE XXXX
SELECT ID, DESCRIPTION,STATUS FROM PART WHERE
PART.ID LIKE 'PCH%'
AND PART.DESCRIPTION NOT LIKE '%OBSOLETE%'
AND ISNULL(PART.STATUS, '') <> 'O'

Return 'Yes' or No' from select statement?

tbl_LoanSummary has Sample_Number column. I have to check if Sample_Number column is not null the return 'Y' otherwise return return 'N' from below select statement.
select a.Br_Loan_No ,a.Br_LookupKey, //return IsNull(s.Sample_Number) ='N' or 'Y'
from dbo.tbl_Br a left outer join dbo.tbl_LoanSummary s
on s.Loan_no = a.Br_Loan_No order by a.Br_Loan_No
How to do this?
You can use the case expression for this...
select a.Br_Loan_No,
a.Br_LookupKey,
CASE WHEN s.Sample_Number IS NULL THEN 'N' ELSE 'Y' END AS [HasSample]
from dbo.tbl_Br a left outer join dbo.tbl_LoanSummary s
on s.Loan_no = a.Br_Loan_No order by a.Br_Loan_No
In Oracle, you could also use
select NVL(s.Sample_Number, 'N')
to return N in case of null value
(of course you still need something to have Y in case of not null.)
You'll want to use a CASE expression. It's like an embedded if-statement or switch-statement from traditional programming languages.
SELECT a.Br_Loan_No,
a.Br_LookupKey
CASE
WHEN s.Sample_Number IS NULL THEN 'N'
ELSE 'Y'
END AS sample_number_is_not_null
FROM dbo.tbl_Br a
LEFT JOIN dbo.tbl_LoanSummary s
ON s.Loan_no = a.Br_Loan_No
ORDER BY a.Br_Loan_no
Note that you are creating a computed column here, rather than selecting the raw value of an existing column. It's generally required that you give this column a name, thus the use of the AS sample_number_is_not_null.
There are two forms of the CASE expression. One lets you compare a column or value against several choices. It is like using an implicit equals:
CASE foo
WHEN 3 THEN 'foo is 3!'
WHEN 4 THEN 'foo is 4!'
ELSE 'foo is not 3 or 4'
END
The other form, in the example at the top, lets you use arbitrary expressions in each WHEN clause. It should be noted that each WHEN clause is evaluated in order and the first one to match is the one whose THEN is used as the result. If none of the WHENs match, then the result in the ELSE is used.