Couple of useful MySQL SUM questions - mysql

If I was to have some MySQL such as:
$stmt = $conn->prepare("SELECT SUM(`num1`) + SUM(`num2`) FROM database.table WHERE `id` = :id");
$stmt->bindParam(':id', $ident, PDO::PARAM_INT, 11);
$stmt->execute();
$sum2 = $stmt->fetchAll();
And lets assume that the respective values of num1 is 20 and num2 is null, should I expect to receive a $sum2[0][0] value of 20 or null?
Also when using SUM, should the prepared select be as is displayed or:
$stmt = $conn->prepare("SELECT SUM(`num1` + `num2`) FROM database.table WHERE `id` = :id");
Or does it not particularly matter?

Use MySQL if because SUM(any)+NULL =NULL
IF(num1 IS NULL,0,num1)
IF(num2 IS NULL,0,num2)
or use like that:-
SELECT IFNULL(SUM(num1), 0)
or use IFNULL
IFNULL(SUM(num1), 0)
or use COALESCE
COALESCE(SUM(num1), 0)

sum() ignores NULL values. So, it only returns NULL when all the values are NULL.
On the other hand, when you add two numbers, then the result is NULL if either is NLLL.
So, in the first query, if you only have one row, then the result is NULL, because sum(num2) is NULL and the addition has a NULL result.
In the second case -- with one row -- then the value would also be NULL. However, with multiple rows, it would end up ignoring rows where either column has a NULL value.

Related

How to declare a variable in MySQL

I should set VARIABLE in mysql query but not work: can you help me, where is the error?
SET #variabile = ( SELECT `submit_time` AS 'Submitted',
max(if(`field_name`='N_PROGRESSIVO', `field_value`, null )) AS 'N_PROGRESSIVO',
max(if(`field_name`='Submitted From', `field_value`, null )) AS 'Submitted From',
GROUP_CONCAT(if(`file` is null or length(`file`) = 0, null, `field_name`)) AS 'fields_with_file'
FROM `wpcust_cf7dbplugin_submits`
WHERE `form_name` = 'Modulo SDO 2022 BS'
GROUP BY `submit_time`
ORDER BY `submit_time` DESC
) as variabile);
SELECT col1 INTO #variable1 FROM ... LIMIT 1
SELECT col1, col2 INTO #variable1, #variable2 FROM ... LIMIT 1
The number of variables must be the same as the number of columns or
expressions in the select list. In addition, the query must returns
zero or one row.
If the query return no rows, MySQL issues a warning of no data and the
value of the variables remain unchanged.
In case the query returns multiple rows, MySQL issues an error. To
ensure that the query always returns maximum one row, you use the
LIMIT 1 clause to limit the result set to a single row.
Source
https://dev.mysql.com/doc/refman/5.7/en/select-into.html
https://www.mysqltutorial.org/mysql-select-into-variable/

MySQL How to find Null data in a table

Scenario: I have a table with duplicate data. One of the columns of this table is ddate, if it is empty/null I want to select that row (and remove it). But for some reason, I cannot find the null rows with a direct query.
Issue: When I run the following query (1):
select
`ddate`,
count(1) as `nb`
from instrument_nt
group by `ddate`;
I get the number of rows where ddate is NULL and where it has other values. But when I run query (2):
select count(*) from instrument_nt where `ddate` = Null;
or
select * from instrument_nt where `ddate` = NULL;
My query result is either 0 or empty.
Question: What is the difference between those two queries (1 and 2)? How can I properly delete the data that has null/missing dates?
NULL mean unknow it's a value.
If you want to get NULL row you need to use IS NULL instead of eqaul NULL
select count(*) from instrument_nt where `ddate` IS Null;
What is the difference between those two queries (1 and 2)? How can I properly delete the data that has null/missing dates?
(1)
select count(*) from instrument_nt where `ddate` IS Null;
you will get the amount ddate is NULL from instrument_nt table.
(2)
select * from instrument_nt where `ddate` IS NULL;
you will get a result set which ddate is NULL;
Every null is defined to be different from every other null. Thus, equality to null is always false. See, for example, here, which describes this so-called "three value problem".
For this third class of value, you want to use IS, as in IS NULL or IS NOT NULL.
use the keyword IS NULL to check the null values in tables
For example:
select * from instrument_nt where `ddate` IS NULL;
MySQL null checks use the IS operator instead of =.
Your query should look like this: select * from instrument_nt whereddateIS NULL;

Not equal <> query excludes NULL values

I'm having a problem with some SQL queries that I cant figure out.
SELECT * FROM MasterList WHERE Requested <> "Yes";
If I run the above query on my table I get 60 records returned. However There should be close to 300. I think the issue is, some of the records are just blank in the Requested field and others are NULL. But I would have thought NULL would still count as not equal to "Yes" wouldnt it? If not, is there a way around that without having to go back and 'blank' all the null fields?
Nulls are not counted in comparison, if you want null values to be returned then you need to execute the following query:
SELECT * FROM MasterList WHERE Requested <> "Yes" OR Requested IS NULL;
<=>
NULL-safe equal. This operator performs an equality comparison like the = operator, but returns 1 rather than NULL if both operands are NULL, and 0 rather than NULL if one operand is NULL.
mysql> SELECT 1 <=> 1, NULL <=> NULL, 1 <=> NULL;
-> 1, 1, 0
mysql> SELECT 1 = 1, NULL = NULL, 1 = NULL;
-> 1, NULL, NULL
in your case use:
SELECT * FROM MasterList WHERE not Requested <=> "Yes"
It happens because null <> 'Yes' expression evaluates to null, thus you should add a separate is null check to include records that meet this condition in your result set:
select * from MasterList where Requested <> "Yes" or Requested is null
P.S.: comparison of null with anything, even with null itself, always returns null.
I've struggled with the same issue and someone introduced me to the IS DISTINCT FROM construct. Very useful but not available for all DBMS!
SELECT * FROM MasterList WHERE Requested IS DISTINCT FROM "Yes";

Return a default value if single row is not found

I have the following select statement to grab the next scheduled item for a stream. If there is no matching row, I want it to return a default value.
Here's the SQL that I'm using:
SELECT `file`
FROM `show`, `schedule`
WHERE `channel` = 1
AND `start_time` <= UNIX_TIMESTAMP()
AND `start_time` > UNIX_TIMESTAMP()-1800
AND `show`.`id` = `schedule`.`file`
ORDER BY `start_time`
DESC LIMIT 1
That should grab the most recently scheduled item, but not if it's older than 30 minutes before the query.
However, if the user doesn't schedule anything, I want a default value, so that something actually plays on the stream. I've tried the following:
SELECT COALESCE(`file`, 'default.webm')
FROM `show`, `schedule`...
And
SELECT IFNULL(`file`, 'default.webm')
FROM `show`, `schedule`
However, it always returns an empty result if no rows are found. How can I return a default value instead?
One way to do it
SELECT IFNULL(MIN(`file`), 'default.webm') `file`
FROM `show`, `schedule`
WHERE `channel` = 1 AND `start_time` <= UNIX_TIMESTAMP()
AND `start_time` > UNIX_TIMESTAMP()-1800 AND `show`.`id` = `schedule`.`file`
ORDER BY `start_time` DESC LIMIT 1
Since you return only one row, you can use an aggregate function, in that case MIN(), that ensures that you'll get NULL if no records selected. Then IFNULL() or COALESCE() will do its job.
#peterm's answer and this answer are designed to accommodate SQL logic that will return a maximum of one row in the result set.
His answer is designed to return a single row with a single column.
My answer is designed to return a single row with one or more columns.
Essentially, you can just use UNION with hardcoded value(s) in a second SELECT clause that has the same number of columns as the first SELECT.
For the OP:
(
SELECT `file`
FROM `show`,
`schedule`
WHERE `channel` = 1
AND `start_time` BETWEEN UNIX_TIMESTAMP()-1799 AND UNIX_TIMESTAMP()
AND `show`.`id` = `schedule`.`file`
ORDER BY `start_time` DESC
LIMIT 1
) UNION (
SELECT 'default.webm'
)
ORDER BY file = 'default.webm'
LIMIT 1;
Barring any syntax errors, the result set will serve up one row with one column keyed as file.
As a more general example: (DB-Fiddle Demo)
(
SELECT Col1,Col2,Col3
FROM ExampleTable
WHERE ID='1234'
) UNION (
SELECT 'Def Val','none',''
)
ORDER BY Col1 = 'Def Val'
LIMIT 1;
Outcomes:
If there are no rows found in the first SELECT, the result set will be filled with the values from the second SELECT. The result set as an array would be:
[['Col1' => 'Def Val', 'Col2' => 'none', 'Col3' => '']]
If one row is found in the first SELECT, the first SELECT values are offered in the result set and the second SELECT values are omitted. The result set as an would be: (see my demo link)
[['Col1' => 'A', 'Col2' => 'B', 'Col3' => 'C']]
*The associative keys in the result set will be dictated by the column names / aliases in the first SELECT query.
*Subsequent SELECT queries do not need to bother nominating column aliases.
*UNION doesn't require the column names from the two united queries to be identical. In fact, the column names or data sources in subsequent SELECT queries may be anything (different columns, function calls, etc).
(
SELECT Col1,Col2,Col3
FROM ExampleTable
WHERE ID='1234'
) UNION (
SELECT 'Def Val' AS `Fallback1`,
'none' AS `Fallback2`,
'' AS `Fallback3`
)
ORDER BY Col1 = 'Def Val'
LIMIT 1;
My opinion is that this is very easy to read and doesn't seem like a taxing query.
Thanks to #LudovicKuty for catching a potential bug regarding the order of rows produced by the UNION. https://dev.mysql.com/doc/refman/8.0/en/union.html#union-order-by-limit To eliminate the possibility of the default row being ordered before the found row, write an ORDER BY clause with enough logic to ensure the default row is always ordered later in the result set. There will be different sql-dialect-specific syntaxes that can be used to identify the default row. In some ORDER BY columnName = 'default value' will be enough, others may demand IF or IIF or CASE, etc. So long as the you build the logic so that the default returns a truthy result, then true will be treated as 1 and false will be treated as 0 -- and of course 1 comes after 0 when sorting ascending.
To handle a wider variety of cases, you'll need some conditional logic. This is only available in stored procedures in MySQL so you'll need to wrap this code in a procedure and call it:
if exists (
SELECT `file` FROM `show`, `schedule`
WHERE `channel` = 1 AND `start_time` <= UNIX_TIMESTAMP()
AND `start_time` > UNIX_TIMESTAMP()-1800 AND `show`.`id` = `schedule`.`file`
) then
SELECT `file` FROM `show`, `schedule`
WHERE `channel` = 1 AND `start_time` <= UNIX_TIMESTAMP()
AND `start_time` > UNIX_TIMESTAMP()-1800 AND `show`.`id` = `schedule`.`file`
ORDER BY `start_time` DESC LIMIT 1
; else
select `DefaultValue` as `file`
; end if

Returning a value even if no result

I have this kind of simple query that returns a not null integer field for a given id:
SELECT field1 FROM table WHERE id = 123 LIMIT 1;
The thing is if the id is not found, the resultset is empty. I need the query to always return a value, even if there is no result.
I have this thing working but I don't like it because it runs 2 times the same subquery:
SELECT IF(EXISTS(SELECT 1 FROM table WHERE id = 123) = 1, (SELECT field1 FROM table WHERE id = 123 LIMIT 1), 0);
It returns either field1 if the row exists, otherwise 0. Any way to improve that?
Thanks!
Edit following some comments and answers: yes it has to be in a single query statement and I can not use the count trick because I need to return only 1 value (FYI I run the query with the Java/Spring method SimpleJdbcTemplate.queryForLong()).
MySQL has a function to return a value if the result is null. You can use it on a whole query:
SELECT IFNULL( (SELECT field1 FROM table WHERE id = 123 LIMIT 1) ,'not found');
As you are looking for 1 record, (LIMIT 1) then this will work.
(SELECT field1 FROM table WHERE id = 123)
UNION
(SELECT 'default_value_if_no_record')
LIMIT 1;
Can be a handy way to display default values, or indicate no results found. I use it for reports.
See also http://blogs.uoregon.edu/developments/2011/03/31/add-a-header-row-to-mysql-query-results/ for a way to use this to create headers in reports.
You could include count(id). That will always return.
select count(field1), field1 from table where id = 123 limit 1;
http://sqlfiddle.com/#!2/64c76/4
You can use COALESCE
SELECT COALESCE(SUM(column),0)
FROM table
If someone is looking to use this to insert the result INTO a variable and then using it in a Stored Procedure; you can do it like this:
DECLARE date_created INT DEFAULT 1;
SELECT IFNULL((SELECT date FROM monthly_comission WHERE date = date_new_month LIMIT 1), 0)
INTO date_created
WHERE IFNULL((SELECT date FROM monthly_comission WHERE date = date_new_month LIMIT 1), 0) = 0;
With this you're storing in the variable 'date_created' 1 or 0 (if returned nothing).
Do search with LEFT OUTER JOIN. I don't know if MySQL allows inline VALUES in join clauses but you can have predefined table for this purposes.
k-a-f's answer works for selecting one column, if selecting multiple column, we can.
DECLARE a BIGINT DEFAULT 1;
DECLARE b BIGINT DEFAULT "name";
SELECT id, name from table into a,b;
Then we just need to check a,b for values.
if you want both always a return value but never a null value you can combine count with coalesce :
select count(field1), coalesce(field1,'any_other_default_value') from table;
that because count, will force mysql to always return a value (0 if there is no values to count) and coalesce will force mysql to always put a value that is not null