Categorize select with multiple DATE BETWEEN - mysql

My question in title, so
If i had:
SELECT * FROM tbl WHERE date BETWEEN "date[0][start]"
AND "date[0][end]" OR date BETWEEN "date[1][start]" AND "date[1][end]"
Can i somehow separate results in appliance with where clause

Each condition evaluates to either FALSE (0) or TRUE (1). It is possible to select the results of the expressions as values and even sort the result by these values:
SELECT
col1, col2, ..., coln,
date BETWEEN "date[0][start]" AND "date[0][end]" AS first,
date BETWEEN "date[1][start]" AND "date[1][end]" AS second
FROM tbl
WHERE date BETWEEN "date[0][start]" AND "date[0][end]"
OR date BETWEEN "date[1][start]" AND "date[1][end]"
ORDER BY first

Related

MySQL return summed values and a virtual column as (count - sum)

I have a table as follows:
log (log_id, log_success (bool), log_created)
I would like to SELECT and return 3 columns date success and no_success, where the former does not exist in table and finally aggregate them by day.
I have created this query:
SELECT
log_created as 'date'
COUNT(*) AS 'count',
SUM(log_success) AS 'success'
SUM('count' - 'success') AS 'no_success'
FROM send_log
GROUP BY DATE_FORMAT(log_created, '%Y-%m-%d');
Would I be able to achieve it with this query? Is my syntax correct?
Thanks.
You can't reuse an alias defined in the select within the same select clause. The reason for this is that it might not even have been defined when you go to access it. But, you easily enough can repeat the logic:
SELECT
log_created AS date,
SUM(log_success) AS success,
COUNT(*) - SUM(log_success) AS no_success,
FROM send_log
GROUP BY
log_created;
I don't know why you are calling DATE_FORMAT in the group by clause of your query. DATE_FORMAT is usually a presentation layer function, which you call because you want to view a date formatted a certain way. Since it appears that log_created is already a date, there is no need to call DATE_FORMAT on it when aggregating. You also should not even need in the select clause, because the default format for a MySQL date is already Y-m-d.
You must select DATE_FORMAT(log_created, '%Y-%m-%d') if you want to group by this.
Also you can get the no_success counter with SUM(abs(log_success - 1))
SELECT
DATE_FORMAT(log_created, '%Y-%m-%d') date,
SUM(log_success) log_success,
SUM(abs(log_success - 1)) no_success
FROM send_log
GROUP BY date;
See the demo

Query with GROUP BY and ORDER BY not working when multiple columns in SELECT are chosen

I'm updating an old website and one of the queries isn't working anymore:
SELECT * FROM tbl WHERE col1 IS NULL GROUP BY col2 ORDER BY col2
I noticed if I dropped the GROUP BY it works, but the result set doesn't match the original:
SELECT * FROM tbl WHERE col1 IS NULL ORDER BY col2
So I tried reading up on GROUP BY in the docs to see what might be the issue, and it seemed to suggest not using * to select all the fields, but explicitly using the column name so I tried it with just the column that was being ordered and grouped:
SELECT col2 FROM tbl WHERE col1 IS NULL GROUP BY col2 ORDER BY col2
Which works but after looking through the code the query requires 2 columns in the query so whoever added * was overdoing it, but if I add that column produces an error, similarly adding a third column produces the same error:
SELECT col2, col3 FROM tbl WHERE col1 IS NULL GROUP BY col2 ORDER BY col2
SELECT col1, col2, col3 FROM tbl WHERE col1 IS NULL GROUP BY col2 ORDER BY col2
Can anyone tell me why this last query doesn't work? I can't decipher why from the docs, but this is the minimum query required to get the result set I need.
Running the query in Adminer I get this error
Error in query (1055): Expression #2 of SELECT list is not in GROUP BY
clause and contains nonaggregated column 'name.table.column'
which is not functionally dependent on columns in GROUP BY clause; this is
incompatible with sql_mode=only_full_group_by
You need to be careful when you use GROUP BY. Once you understand what GROUP BY does, you will know the issue yourself. It does an aggregation on your data or in other words, it reduces your data by doing some operation on the raw entries and creating new reduced number of entries on which some aggregation function has been applied(SUM, COUNT, AVG, etc.)
The fields you provide in the GROUP BY clause represents the level of aggregation/roll-up you are going for.
SELECT col2, col3 FROM tbl WHERE col1 IS NULL GROUP BY col1 ORDER BY col1
Here you are trying to do the aggregation at col1 level, meaning that for every distinct value present in column col1, there will be some operation done on some other columns you provide in SELECT clause(here col2,col3) so that in the output you have non-repeating values in col1 and some rolled-up values of col2 and col3 against each distinct col1 value based on what function you apply(SUM, COUNT, AVG, etc.).
How do you apply this function? That is what is missing in your above query. To solve it, you need to apply some aggregation function on the fields that are present in the SELECT clause but not in GROUP BY clause. Taking an example of SUM, try this:
SELECT SUM(col2), SUM(col3) FROM tbl WHERE col1 IS NULL GROUP BY col1 ORDER BY col1
OR for a better idea, removing WHERE filter and checking the output by running:
SELECT col1, SUM(col2), SUM(col3) FROM tbl GROUP BY col1 ORDER BY col1
Additionally, the reason why your other query
SELECT col2 FROM tbl WHERE col1 IS NULL GROUP BY col2 ORDER BY col2
worked is because you need not apply aggregation to the field(here col2) which is present in the GROUP BY clause.
First of all, when query() returns false, you should find out what the error was. You seem to be using PDO, so I will direct you to this page: http://php.net/manual/en/pdo.error-handling.php
TL;DR - you should enable PDO exceptions, or else you need to write code to check the result of every call to query(), prepare(), and execute() to see if an error occurred. And if so, use errorInfo() to find out the actual error. Doing anything else is flying blind!
Error in query (1055): Expression #2 of SELECT list is not in GROUP BY
clause and contains nonaggregated column 'webvictoria.cats_oct.matchLink'
which is not functionally dependent on columns in GROUP BY clause; this is
incompatible with sql_mode=only_full_group_by
This is a common issue. See dozens of questions tagged mysql-error-1055.
I guess you just upgraded to MySQL 5.7. MySQL 5.7 enabled strict mode by default, so I guess you just upgraded. Prior to MySQL 5.6, strict mode was optional and not enabled by default.
See: https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
You can't write ambiguous queries. If you GROUP BY col2, which value in the group of rows of each group should be used for col1 and col3? It's ambiguous.
Without strict mode, MySQL chooses an arbitrary row from the group. With strict mode, it reverts to standard SQL behavior, and disallows the ambiguous query. This is how most other brands of SQL database behave, by the way.
To fix it, you must follow this rule: Every column in your select list must be one of:
A column in your GROUP BY clause
A column functionally dependent on the columns in your GROUP BY clause (so there can only be one value)
Used in an aggregate function like MIN(), MAX(), COUNT(), SUM(), AVG(), or GROUP_CONCAT()
Some people choose to disable strict mode in MySQL 5.7 for the sake of "getting the code working again." But it isn't working—it's just giving ambiguous results like it did before MySQL 5.7.
It's better to fix the logic of your queries.
This query:
SELECT *
FROM tbl
WHERE col1 IS NULL
GROUP BY col1
ORDER BY col1;
never really worked. It may have seemed to work, but you were just lucky. You have unaggregated columns in the SELECT. These come from an arbitrary row.
You can do something like this to get values from other columns:
SELECT col1, min(col2), min(col3)
FROM tbl t
WHERE col1 IS NULL AND
GROUP BY col1
ORDER BY col1;
The reason it didn't work is because you need to use one of the selection criteria in the GROUP BY and the ORDER BY. So if you wanted to group by col1, you would need to do this:
SELECT col1, col2, col3
FROM tbl
WHERE
col1 IS NULL
GROUP BY col1
ORDER BY col1
;
Without selecting that field, you are basically saying "Hey go get me every phone number in California" Then after you get that you say "Now order them by first name and group them by last name" and DBMS says "but... I don't have any of that"
try this
SELECT col2, col3 FROM tbl WHERE col1 IS NULL GROUP BY col2, col3 ORDER BY col2, col3

Access: Use scalar correlated subquery result for sorting

In Access, is it possible to use the result of a scalar correlated subquery to sort the resultant rows? This didn't work (returned a sql error):
SELECT (SELECT MIN(DateTime) FROM Appt WHERE (PatientID = XXX.ID)) AS minDT, XXX.FullName,
FROM Patient AS XXX
ORDER BY minDT;
Replacing the "minDT" in the ORDER BY clause with the entire expression didn't work either.
Access won't allow you to use a field expression alias in the ORDER BY, but you can use a column's ordinal number ...
SELECT *
FROM
(
SELECT
(
SELECT MIN([DateTime])
FROM Appt
WHERE (PatientID = XXX.ID)
) AS minDT,
XXX.FullName
FROM Patient AS XXX
) AS sub
ORDER BY 1;
Note I bracketed the DateTime field name because I suspect it's a reserved word.
And don't include a comma after the last item in the SELECT field expression list.

Error message "Operand should contain 1 column(s)"

Am trying to select the day and month part for a range of date of a date field in mysql and its given me this error"Operand should contain 1 column(s)".
tablename is personal
date field name is dob
"SELECT *
FROM personal
WHERE (EXTRACT(MONTH
FROM dob),
EXTRACT(DAY
FROM dob)) BETWEEN '$fromdate' AND '$todate'"
dob is date field and the $fromdate and $todate holds a date input from the screen like "2014-04-30" and "2014-06-30
Using WHERE clause you can compare multiple values but one each at a time.
In your statement WHERE is trying to use both MONTH and DAY as separate values comma separated but comparing with $fromdate and $tdate, which is not correct.
And hence is the error:
Operand should contain 1 column(s)
You may be looking for a solution like this:
If $fromdate and $todate are in the format of mmdd, then
SELECT * FROM personal
WHERE date_format( dob, '%m%d' )
BETWEEN '$fromdate' AND '$todate'
You need to use CONCAT in order to merge day and month from your dob column and then compare using between clause
SELECT
*
FROM
personal
WHERE
CONCAT(EXTRACT(MONTH FROM dob),'-',EXTRACT(DAY FROM dob))
BETWEEN '$fromdate' AND '$todate'
Or better to use DATE_FORMAT to get the month and day only but make sure you have standard date object stored in column, and the format you provide in DATE_FROMAT must match with the format of your provided parameters
SELECT
*
FROM
personal
WHERE
DATE_FROMAT(dob,'%m-%d')
BETWEEN '$fromdate' AND '$todate'
Just in case anyone else runs across this error (I fought with it for hours before realizing my mistake)
You will also get this error if you accidentally put the cols for a SELECT in parenthesis
So if you are in a hurry and cut and paste your field list and type...
INSERT INTO mytablename(col1, col2, col3)
SELECT (col1, col2, col3) FROM anothertable WHERE col4 = 1;
instead of
INSERT INTO mytablename(col1, col2, col3)
SELECT col1, col2, col3 FROM anothertable WHERE col4 = 1;
it throws the Operand should contain 1 column(s) error.

Is it possible to sum a expression column in access?

I have a column in access I need to get the total of. When I try the below method in my query I get the error "You tried to execute a query that does not include the specified expression 'ID' as part of an aggregate function."
Expr1: Sum([Column1])
Edit my query:
SELECT tblTest.ID,Field1,Sum([Field1]) AS Expr1 From tblTest;
Your question needs more details but I think you want this:
SELECT Sum(yourColumn)
FROM yourTable
Then if you need to you will have to add a GROUP BY
SELECT Sum(yourColumn)
FROM yourTable
GROUP BY yourTable.Id
Based on your comment your query would be:
SELECT ID
,Field1
,Sum([Field1]) AS Expr1
From tblTest
GROUP BY ID, Field1;