SQL query, treat NULL as zero [duplicate] - mysql

This question already has an answer here:
MySQL: Typecasting NULL to 0
(1 answer)
Closed 7 years ago.
I'm learning SQL (using MySQL) and have a very simple question. I have a table with salary and bonus information on employees, and I'd like to sum the two, but have MySQL return the value zero when at least one of the summands is NULL, instead of returning NULL. What's the easiest way to do this?
mysql> SELECT SALARY, BONUS FROM EMPLOYEE_PAY_TBL;
+----------+---------+
| SALARY | BONUS |
+----------+---------+
| 30000.00 | 2000.00 |
| NULL | NULL |
| 40000.00 | NULL |
| 20000.00 | 1000.00 |
| NULL | NULL |
| NULL | NULL |
+----------+---------+
mysql> SELECT SALARY + BONUS FROM EMPLOYEE_PAY_TBL;
+----------------+
| SALARY + BONUS |
+----------------+
| 32000.00 |
| NULL |
| NULL |
| 21000.00 |
| NULL |
| NULL |
+----------------+

You can use COALESCE. It accepts a number of arguments and returns the first one that is not null.
You can use IFNULL too (not to be confused with ISNULL). It behaves the same in this scenario, but COALESCE is more portable; it allows multiple arguments and returns the first not-null one. Also, other databases support it too, so that makes it slightly easier to migrate to another database if you would like to in the future.
SELECT COALESCE(SALARY, 0) + COALESCE(BONUS, 0)
FROM EMPLOYEE_PAY_TBL;
or
SELECT IFNULL(SALARY, 0) + IFNULL(BONUS, 0)
FROM EMPLOYEE_PAY_TBL;
Both of them are just a very convenient way to write:
SELECT
CASE WHEN SALARY IS NULL THEN 0 ELSE SALARY END +
CASE WHEN BONUS IS NULL THEN 0 ELSE BONUS END
FROM EMPLOYEE_PAY_TBL;

SELECT IFNULL(SALARY, 0), IFNULL(BONUS, 0) FROM EMPLOYEE_PAY_TBL;
You should use IFNULL function for that.
CORRECTED

Related

How to inner join result of stored function?

I am searching for all day with no success so I decided to ask.
I will very simplify structure as much as possible to ask for essence.
I have function:
mysql> SELECT set_of_ids_to_names('1:2:3:4:5', ':') AS `res`;
+-------------------------------+
| res |
+-------------------------------+
| NameA:NameB:NameC:NameD:NameE |
+-------------------------------+
I have table:
mysql> SELECT * FROM `tbl_tool`;
+----+-----------------+---------+
| ID | Tool | ID_name |
+----+-----------------+---------+
| 1 | Tool_1 | 1:2:3:4 |
| 2 | Tool_2 | 2:4:5 |
| 3 | Tool_3 | 4:5 |
| 4 | Tool_4 | 3 |
+----+-----------------+---------+
The result I would like to achieve is to have view called 'v_tool' so once I selet it I get:
mysql> SELECT * FROM `v_tool`;
+----+-----------------+-------------------------+
| ID | Tool | Name |
+----+-----------------+-------------------------+
| 1 | Tool_1 | NameA:NameB:NameC:NameD |
| 2 | Tool_2 | NameB:NameD:NameE |
| 3 | Tool_3 | NameD:NameE |
| 4 | Tool_4 | NameC |
+----+-----------------+-------------------------+
This what I tried is:
SELECT `tbl_tool`.`ID`, `tbl_tool`.`Tool`, `Name` FROM `tbl_tool`
INNER JOIN (SELECT set_of_ids_to_names((SELECT `ID` FROM `tbl_tool` WHERE `ID` = `tbl_tool`.`ID`), ':') AS `Name`) AS `aaa`
I know that it is wrong, but I just could not find idea how to pass proper value to function 'set_of_ids_to_names'.
Big thank you in advance.
Looking at the original function call you made:
SELECT set_of_ids_to_names('1:2:3:4:5', ':') AS `res`
It is important to note the function call appears in the SELECT clause, not in the FROM clause.
This suggests set_of_ids_to_names is a scalar function, not a table-valued function.
When querying table tbl_tool, you can do the exact same thing: call set_of_ids_to_names in the SELECT clause.
SELECT Tool, set_of_ids_to_names(ID_name, ':') AS Name
FROM tbl_tool
For table-valued functions, the situation is different of course. SQL Server has CROSS APPLY for that, in MySQL you'd probably have to join the table with a subquery encapsulating the function call.

Unexpected NOT EQUAL TO NULL comparison in MySQL [duplicate]

This question already has answers here:
What's the difference between " = null" and " IS NULL"?
(4 answers)
Closed 5 years ago.
I have below table in MySQL.
city_data
+------+-----------+-------------+
| id | city_code | city_name |
+------+-----------+-------------+
| 4830 | BHR | Bharatpur |
| 4831 | KEP | Nepalgunj |
| 4833 | OHS | Sohar |
| 4834 | NULL | Shirdi |
+------+-----------+-------------+
and below query.
select id,city_code,city_name from city_data where city_code != 'BHR';
I was expecting 3 rows.
| 4831 | KEP | Nepalgunj |
| 4833 | OHS | Sohar |
| 4834 | NULL | Shirdi |
+------+-----------+-------------+
But getting only 2 rows.
| 4831 | KEP | Nepalgunj |
| 4833 | OHS | Sohar |
+------+-----------+-------------+
I am not able to understand why the row
| 4834 | NULL | Shirdi |
Not includes in the result of my query. The where condition(NULL != 'BHR') should have been passed.
Please, someone, help to clear the doubt.
According to MySQL Reference Manual, section 3.3.4.6: Working with NULL values the following is why:
Because the result of any arithmetic comparison with NULL is also
NULL, you cannot obtain any meaningful results from such comparisons.
In MySQL, 0 or NULL means false and anything else means true. The
default truth value from a boolean operation is 1.
This means that NULL != 'BHR' will evaluate to NULL, which in turn will mean false to MySQL. In order for the query to work as you want, you have to append OR city_code IS NULL to your query.
You cannot compare null values with !=, because it is null, use IS NULL predicate instead:
select id,city_code,city_name
from city_data
where city_code != 'BHR' OR city_code IS NULL;
It is not possible to test for NULL values with comparison operators, such as =, <, or <>. Therefore query is confusing and NULL record is being ignored. for more info go to https://www.w3schools.com/sql/sql_null_values.asp

How do I use COALESCE and JOIN at the same time and including NULL values in MySQL?

I'm having trouble using COALESCE and JOIN at the same time. My plan is:
to match the venture column from my current table against the vid column from venture list table and return the corresponding venture name.
if the venture column on the current table is zero (0) or null, the other column next to it will be selected ("venture_other" column)
Although my query returns its proper values, it seems like NULL values are ignored in this case.
venture_list table:
-------------------
| vid | name |
-------------------
| 1 | Malaysia |
-------------------
| 2 | Singapore |
-------------------
request_forms:
---------------------------------------------
| fid | username | venture | venture_other |
---------------------------------------------
| 1 | jake.long | 2 | |
---------------------------------------------
| 2 | xander.f | 0 | Japan |
---------------------------------------------
Expected Result
---------------
| venturename |
---------------
| Singapore |
---------------
| Japan |
---------------
Actual Result
---------------
| venturename |
---------------
| Singapore |
---------------
Here's my query:
SELECT COALESCE(NULLIF(ventures.name, null), venture_other) AS venturename
FROM request_forms forms
JOIN venture_list ventures ON ventures.vid = forms.venture
I tried rearranging the column names, but didn't work.
The problem is that MySQL default behaviour on a JOIN is an INNER JOIN.
Obviously since there is no matching result for the second row in venture_list you only get 1 row back.
Try using LEFT JOIN THAT way the column ventures.name will result in NULL and thus venture_other will be used.
Your original use of NULLIF() here is peculiar. From the documentation:
Returns NULL if expr1 = expr2 is true, otherwise returns expr1.
So your statement said, "In the event that ventures.name is NULL then return NULL else return ventures.name". Which is superfluous since a NULL will already return a NULL because it's NULL.
Instead of the case, and properly using the NULLIF() you could have the NULLIF() return a NULL in the event that ventures.name is 0:
SELECT COALESCE(NULLIF(ventures.name, 0), venture_other) AS venturename
FROM request_forms forms
JOIN venture_list ventures ON ventures.vid = forms.venture
You were pretty close but need to change the nullif a bit:
select coalesce(nullif(ventures.name,0), venture_other) as venturename
from request_forms forms
join venture_list ventures
on ventures.vid = forms.venture;
Basically, you want to use nullif to null out ventures.name if it is 0..then the coalesce does the rest.

Can I SELECT this in a single stament?

I am a total SQL noob; sorry.
I have a table
mysql> describe activity;
+--------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+---------+------+-----+---------+-------+
| user | text | NO | | NULL | |
| time_stamp | int(11) | NO | | NULL | |
| activity | text | NO | | NULL | |
| item | int | NO | | NULL | |
+--------------+---------+------+-----+---------+-------+
Normally activity is a two-step process; 1) "check out" and 2 "use"
An item cnnot be checked out a second time, unless used.
Now I want to find any cases where an item was checked out but not used.
Being dumb, I would use two selects, one for check out &one for use, on the same item, then compare the timestamps.
Is there a SELECT statemnt that will help me selct the items which were checked out but not used?
Tricky with the possibility of multipel checkouts. Or should I just code
loop over activity, form oldest until newset
if find a checkout and there is no newer used time then i have a hit
You could get the last date of each checkout or use and then compare them per item:
SELECT MAX(IF(activity='check out', time_stamp, NULL)) AS last_co,
MAX(IF(activity='use', time_stamp, NULL)) AS last_use
FROM activity
GROUP BY item
HAVING NOT(last_use >= last_co);
The NOT(last_use >= last_co) is written that way because of how NULL compare behaviour works: last_use < last_co will not work if last_use is null.
Without proper indexing, this query will not perform very well though. Plus you might want to bound the query using a WHERE condition.

Average Time MYSQL from a row

Hi all i have a table with the time in each row
how do i get the average time for each row with a select
eg 22:56:39 should be the result
+---------------------+---------------------+
| Day_16 | Day_12 |
+---------------------+---------------------+
| NULL | NULL |
| NULL | NULL |
| NULL | NULL |
| 2011-01-16 23:52:34 | 2011-02-15 22:00:45 |
Ps there is a ID for each row also
SELECT SEC_TO_TIME(AVG(TIME_TO_SEC(day_16),TIME_TO_SEC(day_12))) FROM Table1;
SELECT FROM_UNIXTIME(UNIX_TIMESTAMP(Day_12) + ((UNIX_TIMESTAMP(Day_16) - UNIX_TIMESTAMP(Day_12)) / 2)) FROM tablename
Edit: Ulvund's solution is much cleaner