How to declare a variable in MySQL - 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/

Related

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;

Couple of useful MySQL SUM questions

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.

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

MySQL SELECT INTO <variable> returns null but query returns a value

For some reason I cannot get this query to return a value when I do a select into.
Given a table t10company, I have a column called CompanyID which is of CHAR(8), it has a value in it of: MYCO0001
If I issue the following query:
SELECT
MAX(CONVERT(RIGHT(CompanyID, 4), UNSIGNED INTEGER))
FROM t10company
WHERE LEFT(CompanyID, 4) = 'MYCO'
GROUP BY LEFT(CompanyID, 4)
ORDER BY RIGHT(CompanyID, 4) LIMIT 1;
I get a return value of 1 which is what I would expect.
If I issue the exact same query except with INTO #myvar and then do a SELECT #myvar it always returns NULL. It does this in the stored proc I'm writing and also does it in a query window in MySQL Workbench. I dont know why?
I use this form to assign a value to a user variable in MySQL
SELECT #myvar := MAX(CONVERT(RIGHT(CompanyID, 4), UNSIGNED INTEGER)) FROM ...
According to the 5.1 documentation, this should also work:
SELECT MAX(CONVERT(RIGHT(CompanyID, 4), UNSIGNED INTEGER)) INTO #myvar FROM ...
I ran a quick test (MySQL 5.1), and the final SELECT is showing #myvar is being set to 1.
CREATE TABLE t10company (CompanyID CHAR(8));
INSERT INTO t10company VALUES ('MYCO0001');
SET #myvar := NULL;
SELECT #myvar;
SELECT
MAX(CONVERT(RIGHT(CompanyID, 4), UNSIGNED INTEGER)) INTO #myvar
FROM t10company
WHERE LEFT(CompanyID, 4) = 'MYCO'
GROUP BY LEFT(CompanyID, 4)
ORDER BY RIGHT(CompanyID, 4) LIMIT 1;
SELECT #myvar;
The expression in the ORDER BY clause is a bit odd.
Why would you be ordering by that? The aggregate is only going to return one row. It's not clear if MySQL is disregarding that though, since MySQL may not be identifying that all rows that satisfy the WHERE clause are going to be grouped together into a single.
For this particular statement, the LIMIT 1 is redundant.
I'd suggest you try it without the ORDER BY, just to see if that makes any difference.
Otherwise, I'm inclined to agree that perhaps the aggregate function and the GROUP BY might be the problem. If it is, them a possible workaround is to wrap your statement in a set of parenthesis as an inline view (give it an alias), and then selecting from the inline view.
You don't need the "group by", "order by", or "limit" in your query for a simple max(). Eliminate those, and if that doesn't work, try wrapping another query around it.
select
value into #myvar
from (
SELECT
MAX(CONVERT(RIGHT(CompanyID, 4), UNSIGNED INTEGER)) as value
FROM
t10company
WHERE
LEFT(CompanyID, 4) = 'MYCO'
)
You need to add LEFT(CompanyID, 4) to your SELECT statement (before FROM) if your are going to GROUP BY LEFT(CompanyID, 4)
This is pretty weird.
If you enclose the query into another, it seems to work.
SELECT value FROM (
SELECT MAX(CONVERT(RIGHT(CompanyID, 4), UNSIGNED INTEGER))
AS value FROM t10company
WHERE LEFT(CompanyID, 4) = 'MYCO'
GROUP BY LEFT(CompanyID, 4)
ORDER BY RIGHT(CompanyID, 4) LIMIT 1
) AS weird INTO #myval;
Judging by the EXPLAIN, the query extra cost should be negligible.