Are these SQL statements equivalent - case when vs. NVL? - sql

My colleague has the following SQL statement executed in Redshift:
SELECT
CASE
WHEN P.PRED_VAL IS NULL THEN R.SCORE_VAL
ELSE P.PRED_VAL
END AS FINAL_SCORE
FROM RESULT R
INNER JOIN PREDICTION P
ON R.ID = P.ID;
Is there any context in which the result of that statement wouldn't be the same as NVL(P.PRED_VAL, R.SCORE_VAL)?

nvl is simply a non-standard name for the SQL standard coalesce function.
There is no functional difference between your case and your nvl, except that nvl is non-standard. Use coalesce.

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 with NULL value

I'm struggling to understand how to check for a null value in a progress case expression. I want to see if a column exists and use that, if not use the fallback column. For example, William in first name would be over written by Bill in fn.special-char.
I've got the following query:
SELECT
"PUB"."NAME"."LAST-NAME" as LastName,
CASE fn."SPECIAL-CHAR"
WHEN is null THEN "PUB"."NAME"."FIRST-NAME"
ELSE fn."SPECIAL-CHAR"
END as FirstName
FROM "PUB"."NAME"
LEFT OUTER JOIN "PUB"."DAT-DATA" fn on "PUB"."NAME"."NAME-ID" = fn."DAT-SRC-ID" and 11 = fn."FLD-FIELD-ID"
When I run the query I get:
ORBC Progress OpenEdge Wire Protocol driver][OPENEDGE]Syntax error SQL statement at or about "is null then "PUB"."NAME"."FIRST-" (10713)
If I do a select * I see everything. It just doesn't like the null part. I can also change the when is null to when 'bob' and it works.
Is there something different I need to do to use a null value in a progress db query?
The shorthand variation of the case statement (case expression when value then result ...) is a shorthand for a series of equality conditions between the expression and the given values. null, however, is not a value - it's the lack thereof, and must be evaluated explicitly with the is operator, as you tried to do. In order to do this properly, however, you need to use a slightly longer variation of the case syntax - case when condition then result ...:
SELECT
"PUB"."NAME"."LAST-NAME" as LastName,
CASE WHEN fn."SPECIAL-CHAR" IS NULL THEN "PUB"."NAME"."FIRST-NAME"
ELSE fn."SPECIAL-CHAR"
END as FirstName
FROM "PUB"."NAME"
LEFT OUTER JOIN "PUB"."DAT-DATA" fn on "PUB"."NAME"."NAME-ID" = fn."DAT-SRC-ID" and 11 = fn."FLD-FIELD-ID"
Instead of CASE you can use IFNULL function in Progress 4GL.
SELECT
"PUB"."NAME"."LAST-NAME" as LastName,
IFNULL(fn."SPECIAL-CHAR", "PUB"."NAME"."FIRST-NAME") as FirstName
FROM "PUB"."NAME"
LEFT OUTER JOIN "PUB"."DAT-DATA" fn on "PUB"."NAME"."NAME-ID" = fn."DAT-SRC-ID" and 11 = fn."FLD-FIELD-ID"

How join columns with null value?

Hi please help me. How join 3 columns with null values?.
SELECT [item],[Prox],[z], [item]+[Prox]+[z] as result FROM [FIELD$];
Result.
Try this:
SELECT [item],[Prox],[z], COALESCE([item],'')+COALESCE([Prox],'')+COALESCE([z],'') as result
FROM [FIELD$];
Explanation:
COALESCE evaluates the arguments in order and returns the current value of the first expression that initially does not evaluate to NULL.
i.e., If [item] is NULL, then COALESCE([item],'') will return an empty string.
Other alternatives:
Instead of COALESCE(ColName,''), you can use:
ISNULL(ColName,'') for SQL Server.
IFNULL(ColName,'') for MySQL.
NVL(ColName,'') for Oracle.
As concatenating multiple strings with at least one null value results in NULL you may use coalesce to solve this:
SELECT
[item],
[Prox],
[z],
coalesce([item], '') + coalesce([Prox], '') + coalesce([z], '') as result
FROM
[FIELD$];
coalesce is ANSI standard and available in almost all reasonable databases.
IN SQL Server 2012, you can use CONCAT function:
SELECT [item],[Prox],[z], concat([item],[Prox],[z]) as result FROM [FIELD$];

How to use a function call in a case statement without calling the function multiple times

I have a db view in which one of the columns is based on the result of a scalar function (I know, bad idea). The function return will convert nulls to an empty string, however, my view needs to show null when a value is not returned. The syntax documentation of the case statement doesn't appear to offer me an answer. My "wishful thinking" solution would be to give the function call an alias and then reference that alias in the case statement like so:
SELECT
p.Name,
CASE GetWinningTeam(p.id, 'WON') AS Winner
WHEN '' THEN NULL
ELSE Winner
END as WinningTeam
FROM
Projects p
instead of
SELECT
p.Name,
CASE GetWinningTeam(p.id, 'WON')
WHEN '' THEN NULL
ELSE GetWinningTeam(p.id, 'WON')
END as WinningTeam
FROM
Projects p
However, this is not valid syntax. Is there any way to make only one function call per record using a case statement, or any other solution?
You could use NULLIF and get rid of the case statement:
SELECT p.Name, NULLIF(GetWinningTeam(p.id, 'WON'),'') as WinningTeam
FROM Projects p
How about;
nullif(GetWinningTeam(p.id, 'WON') , '')
You could use a subquery:
select
name,
CASE WHEN Winner = '' THEN NULL
ELSE Winner
END as WinningTeam
FROM
(
SELECT
p.Name,
GetWinningTeam(p.id, 'WON') AS Winner
FROM
Projects p
) a

How to replace null into 0 in a complex query

I would like to replace the total value to 0 when it is null
Here is the query:
SELECT DISTINCT(location), (
SELECT Count(a.location) as total
FROM table_fo a
LEFT JOIN table_info b ON a.TRADEID = b.TRADEID AND a.asofdate = b.asofdate
WHERE (b.TERMSTATUS <> 'TRAN' OR b.TERMSTATUS is NULL) AND b.asofdate = '20110105' AND a.location = pfo.location
GROUP BY a.LOCATION
) AS total
FROM table_fo pfo
WHERE asofdate = '20110105';
You can use the ISNULL function.
Here is how you will use the function (for SQL Server).
ISNULL(columnName, 0)
I would like to replace the total
value to 0 when it is null
This is an impossible situation because:
The COUNT function always returns an integer. The result cannot be NULL!
As for coalescing an expression to a certain default in case it is NULL there are functions that do this in all major databases (ex.: COALESCE, NVL, ISNULL, IFNULL). The typical use is
FUNCTION_NAME(ExpressionThatMayBeNULL, DefaultWhenNull)
For specifics you should consult you database manufacturers documentation (you can find it online).
COALESCE will do this in PL/SQL (Oracle) and T-SQL (SQL Server)
Syntax is COALESCE(field1, field2[, fieldN]) - it will select the first column from the left to have a non-null value.
Modifying the query you had:
SELECT DISTINCT(location), COALESCE((
SELECT Count(a.location) as total
FROM table_fo a
LEFT JOIN table_info b ON a.TRADEID = b.TRADEID AND a.asofdate = b.asofdate
WHERE (b.TERMSTATUS <> 'TRAN' OR b.TERMSTATUS is NULL) AND b.asofdate = '20110105' AND a.location = pfo.location
GROUP BY a.LOCATION
),0) AS total
FROM table_fo pfo
WHERE asofdate = '20110105';
As dparker said, ISNULL(...) will work for some types of sql, though the name of the function can vary among database providers.
The function in IBM DB2 is called COALESCE(...), and in Oracle SQL it is NVL(...) for example.
This may be usefull
http://www.w3schools.com/sql/sql_isnull.asp
If you are using SQL server, the following are the 3 ways that can be used to replace a null with any user defined substitute value.
1. ISNULL
2. COALESCE
3. CASE
This question is also asked in one of the interviews I attended. Here is the link for an article with examples. By the way, there's also a video on the same in this article.
Different ways to replace NULLS in SQL Server
What DB system are you using?
SQL-Server, MySQL: IFNULL(value, 0)
Oracle: NVL(value, 0)
PostgreSQL: COALESCE(value, 0)