MySQL Query not selecting correct date range - mysql

Im currently trying to run a SQL query to export data between a certain date, but it runs the query fine, just not the date selection and i can't figure out what's wrong.
SELECT
title AS Order_No,
FROM_UNIXTIME(entry_date, '%d-%m-%Y') AS Date,
status AS Status,
field_id_59 AS Transaction_ID,
field_id_32 AS Customer_Name,
field_id_26 AS Sub_Total,
field_id_28 AS VAT,
field_id_31 AS Discount,
field_id_27 AS Shipping_Cost,
(field_id_26+field_id_28+field_id_27-field_id_31) AS Total
FROM
exp_channel_data AS d NATURAL JOIN
exp_channel_titles AS t
WHERE
t.channel_id = 5 AND FROM_UNIXTIME(entry_date, '%d-%m-%Y') BETWEEN '01-05-2012' AND '31-05-2012' AND status = 'Shipped'
ORDER BY
entry_date DESC

As explained in the manual, date literals should be in YYYY-MM-DD format. Also, bearing in mind the point made by #ypercube in his answer, you want:
WHERE t.channel_id = 5
AND entry_date >= UNIX_TIMESTAMP('2012-05-01')
AND entry_date < UNIX_TIMESTAMP('2012-06-01')
AND status = 'Shipped'

Besides the date format there is another issue. To effectively use any index on entry_date, you should not apply functions to that column when you use it conditions in WHERE, GROUP BY or HAVING clauses (you can use the formatting in SELECT list, if you need a different than the default format to be shown). An effective way to write that part of the query would be:
( entry_date >= '2012-05-01'
AND entry_date < '2012-06-01'
)
It works with DATE, DATETIME and TIMESTAMP columns.

Related

Avg function not returning proper value

I expect this query to give me the avg value from daily active users up to date and grouped by month (from Oct to December). But the result is 164K aprox when it should be 128K. Why avg is not working? Avg should be SUM of values / number of current month days up to today.
SELECT sq.month_year AS 'month_year', AVG(number)
FROM
(
SELECT CONCAT(MONTHNAME(date), "-", YEAR(DATE)) AS 'month_year', count(distinct id_user) AS number
FROM table1
WHERE date between '2020-10-01' and '2020-12-31 23:59:59'
GROUP BY EXTRACT(year_month FROM date)
) sq
GROUP BY 1
Ok guys thanks for your help. The problem was that on the subquery I was pulling the info by month and not by day. So I should pull the info by day there and group by month in the outer query. This finally worked:
SELECT sq.day_month, AVG(number)
FROM (SELECT date(date) AS day_month,
count(distinct id_user) AS number
FROM table_1
WHERE date >= '2020-10-01' AND
date < '2021-01-01'
GROUP BY 1
) sq
GROUP BY EXTRACT(year_month FROM day_month)
Do not use single quotes for column aliases!
SELECT sq.month_year, AVG(number)
FROM (SELECT CONCAT(MONTHNAME(date), '-', YEAR(DATE)) AS month_year,
count(distinct id_user) AS number
FROM table1
WHERE date >= '2020-10-01' AND
date < '2021-01-01'
GROUP BY month_year
) sq
GROUP BY 1;
Note the fixes to the query:
The GROUP BY uses the same columns as the SELECT. Your query should return an error (although it works in older versions of MySQL).
The date comparisons have been simplified.
No single quotes on column aliases.
Note that the outer query is not needed. I assume it is there just to illustrate the issue you are having.

Mysql. Change date format output on GROUP BY DAY query

I execute this query
SELECT * FROM graph WHERE ean IN ('00000000166330') group by DAY(created_at);
Getting those results:
# id, ean, avg_price, created_at
'58', '00000000166330', '2799.0000', '2020-06-11 16:43:27'
I want to change the date format returned of the created_at field.
I would like to get only the date, not the hour, and with the format: Day, month, Year.
My guess is that DATE_FORMAT should be used, but how to use it, grouping also by day?
Example here
You are not doing any aggregation, so remove group by
You can replace the operator IN with = because you are comparing against 1 value only
Use the function DATE() to get only the date part from created_at
You need a correlated subquery in the WHERE clause to get the row with the minimum id (since it does not matter whic row will be returned) of each day:
SELECT g.id, g.ean, g.avg_price, DATE_FORMAT(g.created_at, '%d-%m-%Y') created_at
FROM graph g
WHERE g.ean = '00000000166330'
AND g.id = (SELECT MIN(id) FROM graph WHERE ean = g.ean AND DATE(created_at) = DATE(g.created_at))
See the demo.
If you want distinct values without aggregation function you should use DISTINCT and for date you can use the date_format() function
SELECT DISTINCT DAY(created_at)
, date_format(date(created_at),'%d, %m, %Y') , id, avg_price
FROM graph WHERE ean = '00000000166330';
and when you have only a value you should use = and not IN operator.

Count Values with same Month Timestamp

I am struggling to count all the values that have the same Timestamp. This is how my database looks like:
Let's say I would like to get the amount of orders in May 2013. What is the right Syntax to get this done?
To get a count for a timestamp range, we can compare the timestamp column to a lower and upper bounds, for example:
SELECT COUNT(*)
FROM mytable t
WHERE t.orderdate >= '2013-05-01 00:00:00'
AND t.orderdate < '2013-06-01 00:00:00'
(All orders on or after the first second of May 1st AND before the first second of June.)
We can also do a similar comparison in an expression in the SELECT list, a conditional aggregation pattern:
SELECT SUM(IF(t.orderdate >= '2013-05-01' AND t.orderdate < '2013-06-01',1,0)) AS cnt_may
FROM mytable t
equivalently
SELECT SUM(CASE WHEN DATE_FORMAT(t.orderdate,'%Y-%m') = '2013-05' THEN 1 ELSE 0 END) AS cnt_may
FROM mytable t
Note that the first query (with conditions in the WHERE clause on the bare orderdate column) can take advantage of an index that has orderdate as the leading column, to perform an efficient range scan operation.

Combine Time in and Time out in one row mysql

Currently, I have this table: date_time_records where all of the time in and out of employees are being saved.
As you can see all of the data of time in and out are being stored for each row.
and these data can be identified if it is time in or out using state field
Time in = C/In
Time Out = C/Out
Expected Output
Now I'm trying to do a query something like this
Where you can see the same employee record but different day
and you can notice that the time in and out is being arranged.
Here's my code
SELECT
a.id,
a.ACNo,
a.name,
a.email,
(SELECT MAX(datetime) FROM date_time_records WHERE id = a.id AND state = "C/In") as time_in,
(SELECT MIN(datetime) FROM date_time_records WHERE id = a.id AND state = "C/Out") as time_out,
FROM `date_time_records` as a GROUP BY datetime ORDER BY `created_at` ASC
Please disregard the created_at
I'm using datetime since the system is capable to do a bulk upload of time in and out. of past data.
You could do something like this:
SELECT ACNo, Name,
SUBSTRING_INDEX(GROUP_CONCAT(CASE WHEN state='C/In' THEN DATETIME END ORDER BY DATETIME ASC),',',1) AS time_in,
SUBSTRING_INDEX(GROUP_CONCAT(CASE WHEN state='C/Out' THEN DATETIME END ORDER BY DATETIME ASC),',',-1) AS time_out,
DATE(DATETIME) AS recDate
FROM date_time_records
GROUP BY ACNo, Name,recDate
ORDER BY ACNo;
Using GROUP_CONCAT then SUBSTRING_INDEX to get the first & last value.
Fiddle here: https://www.db-fiddle.com/f/bfkoKK13kcE8NYVzo71Zi3/3
Use conditional aggregation:
SELECT dtr.id, dtr.ACNo, dtr.name, dtr.email,
MAX(CASE WHEN dtr.stat = 'C/IN' THEN dtr.datetime END) as time_in,
MIN(CASE WHEN dtr.stat = 'C/OUT' THEN dtr.datetime END) as time_out
FROM date_time_records dtr
GROUP BY dtr.id, dtr.ACNo, dtr.name, dtr.email
ORDER BY MIN(created_at) ASC
Could you just log a user's time in/time out separately from the date? That'd make the min/max query for time in/time out on a daily basis a lot simpler.

How to Group a table and get results for a row based on the previous rows' data

I have a lookup table that relates dates and people associated with those dates:
id, user_id,date
1,1,2014-11-01
2,2,2014-11-01
3,1,2014-11-02
4,3,2014-11-02
5,1,2014-11-03
I can group these by date(day):
SELECT DATE_FORMAT(
MIN(date),
'%Y/%m/%d 00:00:00 GMT-0'
) AS date,
COUNT(*) as count
FROM user_x_date
GROUP BY ROUND(UNIX_TIMESTAMP(created_at) / 43200)
But, how can get the number of unique users, that have now shown up previously? For instance this would be a valid result:
unique, non-unique, date
2,0,2014-11-01
1,1,2014-11-02
0,1,2014-11-03
Is this possibly without having to rely on a scripting language to keep track of this data?
I think this query will do what you want, at least it seems to work for your limited sample data.
The idea is to use a correlated sub-query to check if the user_id has occurred on a date before the date of the current row and then do some basic arithmetic to determine number of unique/non-unique users for each date.
Please give it a try.
select
sum(u) - sum(n) as "unique",
sum(n) as "non-unique",
date
from (
select
date,
count(user_id) u,
case when exists (
select 1
from Table1 i
where i.user_id = o.user_id
and i.date < o.date
) then 1 else 0
end n
from Table1 o
group by date, user_id
) q
group by date
order by date;
Sample SQL Fiddle
I didn't include the id column in the sample fiddle as it's not needed (or used) to produce the result and won't change anything.
This is the relevant question: "But, how can get the number of unique users, that have now shown up previously?"
Calculate the first time a person shows up, and then use that for the aggregation:
SELECT date, count(*) as FirstVisit
FROM (SELECT user_id, MIN(date) as date
FROM user_x_date
GROUP BY user_id
) x
GROUP BY date;
I would then use this as a subquery for another aggregation:
SELECT v.date, v.NumVisits, COALESCE(fv.FirstVisit, 0) as NumFirstVisit
FROM (SELECT date, count(*) as NumVisits
FROM user_x_date
GROUP BY date
) v LEFT JOIN
(SELECT date, count(*) as FirstVisit
FROM (SELECT user_id, MIN(date) as date
FROM user_x_date
GROUP BY user_id
) x
GROUP BY date
) fv
ON v.date = fv.date;