So I have a problem to select data from my database. I want to select data with recorded time between 4 PM and 10 PM for a whole month. If it's isn't possible should I query per day for a whole month?
Assuming mydt column is DATETIME or TIMESTAMP datatype,
we could do something like this:
FROM t
WHERE t.mydt >= '2019-09-01'
AND t.mydt < '2019-09-01' + INTERVAL 1 MONTH
AND DATE_FORMAT(t.mydt,'%H') >= '16'
AND DATE_FORMAT(t.mydt,'%H') < '22'
The first two conditions restrict values to the month of September 2019.
The last two conditions restrict the "hour" portion of the datetime, time values from 16:00:00 thru 21:59:99
If we also want to include 22:00:00, we can use '%T' as format model in DATE_FORMAT and do a less than or equal to comparison
AND DATE_FORMAT(t.mydt,'%T') >= '16:00:00'
AND DATE_FORMAT(t.mydt,'%T') <= '22:00:00'
I have a select statement that selects the time, and order by the time asc, but it seems to be ignoring the A.M and P.M part. How would I fix that?
SELECT DATE_FORMAT(max(time),'%h:%i:%s %p') AS mytimestr FROM currentChat WHERE date = '$date' ORDER BY mytimestr ASC
Result:
1:00 A.M
2:00 P.M
3.00 A.M
4.00 P.M
Need Result:
1:00 A.M
3.00 A.M
2:00 P.M
4.00 P.M
If your time column is a MySQL TIME datatype, as I suspect it is from the way you call DATE_FORMAT, then you don't need to ORDER BY your mytimestr expression. You can simply order by the time field itself to get the records in chronological order.
SELECT DATE_FORMAT(max(time),'%h:%i:%s %p') AS mytimestr
FROM currentChat
WHERE date = '$date'
ORDER BY max(time) ASC
I'm not sure whether you intended to have MAX(...) without a GROUP BY - this will only return one row making the ORDER BY a little bit redundant but perhaps you only gave a portion of your query.
I'm trying to pull all information inside a given date range from my database using something like this query:
SELECT transactionDate, SUM(transactionTotal)
FROM transaction
WHERE transactionDate BETWEEN '2014-06-01' AND '2014-08-11'
AND transactionType = 'end'
GROUP BY DAYOFMONTH(transactionDate)
ORDER BY transactionDate ASC
But somehow I only get the data for 1 month
2014-06-01 20:38:05 4811500.00
2014-06-02 20:42:59 5924950.00
2014-06-03 20:44:38 3811500.00
2014-06-04 11:45:13 4472000.00
2014-06-05 15:34:53 7922000.00
2014-06-06 17:45:28 5027000.00
2014-06-07 11:25:38 4378000.00
2014-06-08 07:59:04 4250000.00
2014-06-09 08:41:49 4766500.00
2014-06-10 01:23:35 4071000.00
2014-06-11 01:01:30 1459000.00
2014-06-12 15:05:08 2960000.00
2014-06-13 00:47:09 1160000.00
2014-06-14 16:52:20 4208000.00
2014-06-16 00:05:18 3947500.00
2014-06-17 00:18:39 4926000.00
2014-06-18 00:33:38 4244500.00
2014-06-19 00:43:39 4045000.00
2014-06-20 22:47:54 2649500.00
2014-06-21 23:06:04 4030000.00
2014-06-22 23:19:22 945500.00
2014-06-23 23:29:27 3015000.00
2014-06-24 23:35:56 2420000.00
2014-06-25 00:02:03 3920000.00
2014-06-26 00:50:33 4841000.00
2014-06-27 10:39:14 4095000.00
2014-06-28 07:43:06 5605500.00
2014-06-29 11:48:24 1939000.00
2014-06-30 10:49:50 3620000.00
As you can see, I get the results from 2014-06-01 to 2014-06-01 even when all other dates also have data to display.
Hope you can help me, thanks!
You're misusing GROUP BY and the pernicious MySQL GROUP BY extension is biting you. You're grouping your data into 31 buckets with your GROUP BY DAYOFMONTH() , so there's no way you'll get more than 31 rows in your result set. You're then (misusing the extension) displaying some arbitrarily selected transaction_date value from each of your 31 groupings. It happens to be a June date, and this has tricked you into thinking you've only selected June records. You've actually selected all the dates in your range, but mistakenly grouped July and August records with your June records. Ouch.
Second, using BETWEEN to select date ranges from a DATETIME column isn't quite right, because it gets the end of the range wrong. BETWEEN '2014-06-01' AND '2014-08-11' gets the items dated from the first of June up until the very first moment of August 11th. So something happening at noon on August 11th won't get selected.
Here is the query you need to do this job correctly.
SELECT DATE(transactionDate),
SUM(transactionTotal)
FROM transaction
WHERE transactionDate >= '2014-06-01'
AND transactionDate < '2014-08-11' + INTERVAL 1 DAY
AND transactionType = 'end'
GROUP BY DATE(transactionDate)
ORDER BY DATE(transactionDate) ASC
What's going on here? First, we're grouping by just the date of each transaction, using DATE(), and we're including that grouped value in our result set with SELECT DATE().
Second, the date range selection takes everything on or after midnight on June first, up until the moment right before midnight on August 12th. That's the point of transactionDate < '2014-08-11' + INTERVAL 1 DAY. It takes the whole day's worth of items for August 11.
There's a writeup of this corner of SQL tech here: http://www.plumislandmedia.net/mysql/sql-reporting-time-intervals/
Use the following sql query to get desired results
SELECT transactionDate, SUM(transactionTotal) FROM transaction WHERE transactionDate BETWEEN '2014-06-01' AND '2014-08-11' AND transactionType = 'end' GROUP BY CAST(transactionDate AS DATE) ORDER BY transactionDate ASC
I'm not sure this is even possible without using PHP, but I'd love to try.
I have a database that looks like this (a bunch of other stuff, but this is all that is relevant:
Date_Day (is a range from 1 to 31 with no trailing 0)
Date_Month (is a range from January to December, not numerical)
Date_Year (is the year in 4 digit format, ex: 2005)
Total (number with 2 decimal places)
I know the way the dates are stored is awful, but this is the database I was given. If there is a query that I could use these columns to create an actual DATETIME column, I would happily do it, I just don't know what that query looks like.
I have this query that returns the Total sales amount for this day for all previous years:
SELECT
Date_Year, Date_Month, SUM(Total)
FROM
tablename
WHERE
Date_Year < YEAR(CURDATE())
AND
Date_Month = MONTHNAME(CURDATE())
AND
Date_Day = DAY(CURDATE())
GROUP BY
Date_Year, Date_Month
So if I run this today, I get the daily totals for October 4th for all previous years. The issue is that in sales, this isn't very helpful for comparing growth. What I really need is the daily totals for the 1st Friday in October for all previous years.
Is this possible without having to rely on PHP? If so, I would be very grateful for your help.
Thank you.
You might be looking for DAYOFWEEK()
Returns the weekday index for date (1 = Sunday, 2 = Monday, …, 7 = Saturday). These index values correspond to the ODBC standard.
mysql> SELECT DAYOFWEEK('2007-02-03');
> 7
SELECT
Date_Year, Date_Month, SUM(Total)
FROM
tablename
WHERE
Date_Year < YEAR(CURDATE())
AND
Date_Month = MONTHNAME(CURDATE())
AND
Date_Day = DAY(LAST_DAY(CURDATE()) - ((28 + WEEKDAY(LAST_DAY(CURDATE())) - 4)))
GROUP BY
Date_Year, Date_Month
maybe this will help
Oracle's table server offers a built-in function, TRUNC(timestamp,'DY'). This function converts any timestamp to midnight on the previous Sunday. What's the best way to do this in MySQL?
Oracle also offers TRUNC(timestamp,'MM') to convert a timestamp to midnight on the first day of the month in which it occurs. In MySQL, this one is straightforward:
TIMESTAMP(DATE_FORMAT(timestamp, '%Y-%m-01'))
But this DATE_FORMAT trick won't work for weeks. I'm aware of the WEEK(timestamp) function, but I really don't want week number within the year; this stuff is for multiyear work.
You can use both YEAR(timestamp) and WEEK(timestamp), and use both of the these expressions in the SELECT and the GROUP BY clause.
Not overly elegant, but functional...
And of course you can combine these two date parts in a single expression as well, i.e. something like
SELECT CONCAT(YEAR(timestamp), '/', WEEK(timestamp)), etc...
FROM ...
WHERE ..
GROUP BY CONCAT(YEAR(timestamp), '/', WEEK(timestamp))
Edit: As Martin points out you can also use the YEARWEEK(mysqldatefield) function, although its output is not as eye friendly as the longer formula above.
Edit 2 [3 1/2 years later!]:
YEARWEEK(mysqldatefield) with the optional second argument (mode) set to either 0 or 2 is probably the best way to aggregate by complete weeks (i.e. including for weeks which straddle over January 1st), if that is what is desired. The YEAR() / WEEK() approach initially proposed in this answer has the effect of splitting the aggregated data for such "straddling" weeks in two: one with the former year, one with the new year.
A clean-cut every year, at the cost of having up to two partial weeks, one at either end, is often desired in accounting etc. and for that the YEAR() / WEEK() approach is better.
Figured it out... it's a little cumbersome, but here it is.
FROM_DAYS(TO_DAYS(TIMESTAMP) -MOD(TO_DAYS(TIMESTAMP) -1, 7))
And, if your business rules say your weeks start on Mondays, change the -1 to -2.
Edit
Years have gone by and I've finally gotten around to writing this up.
https://www.plumislandmedia.net/mysql/sql-reporting-time-intervals/
The accepted answer above did not work for me, because it ordered the weeks by alphabetical order, not chronological order:
2012/1
2012/10
2012/11
...
2012/19
2012/2
Here's my solution to count and group by week:
SELECT CONCAT(YEAR(date), '/', WEEK(date)) AS week_name,
YEAR(date), WEEK(date), COUNT(*)
FROM column_name
GROUP BY week_name
ORDER BY YEAR(DATE) ASC, WEEK(date) ASC
Generates:
YEAR/WEEK YEAR WEEK COUNT
2011/51 2011 51 15
2011/52 2011 52 14
2012/1 2012 1 20
2012/2 2012 2 14
2012/3 2012 3 19
2012/4 2012 4 19
You can get the concatenated year and week number (200945) using the YEARWEEK() function. If I understand your goal correctly, that should enable you to group your multi-year data.
If you need the actual timestamp for the start of the week, it's less nice:
DATE_SUB( field, INTERVAL DAYOFWEEK( field ) - 1 DAY )
For monthly ordering, you might consider the LAST_DAY() function - sort would be by last day of the month, but that should be equivalent to sorting by first day of the month ... shouldn't it?
Just ad this in the select :
DATE_FORMAT($yourDate, \'%X %V\') as week
And
group_by(week);
If you need the "week ending" date this will work as well. This will count the number of records for each week. Example: If three work orders were created between (inclusive) 1/2/2010 and 1/8/2010 and 5 were created between (inclusive) 1/9/2010 and 1/16/2010 this would return:
3 1/8/2010
5 1/16/2010
I had to use the extra DATE() function to truncate my datetime field.
SELECT COUNT(*), DATE_ADD( DATE(wo.date_created), INTERVAL (7 - DAYOFWEEK( wo.date_created )) DAY) week_ending
FROM work_order wo
GROUP BY week_ending;
Previous Sunday:
STR_TO_DATE(CONCAT(YEARWEEK(timestamp,2),'0'),'%X%V%w')
Previous Monday:
STR_TO_DATE(CONCAT(YEARWEEK(timestamp,3),'1'),'%x%v%w')
DATE_FORMAT(date,format) reference:
%V - Week (01..53), where Sunday is the first day of the week; WEEK() mode 2; used with %X
%v - Week (01..53), where Monday is the first day of the week; WEEK() mode 3; used with %x
%w - Day of the week (0=Sunday..6=Saturday)
%X - Year for the week where Sunday is the first day of the week, numeric, four digits; used with %V
%x - Year for the week, where Monday is the first day of the week, numeric, four digits; used with %v
I like the week function in MySQL, but in my situation, I wanted to know which week of the month a row was in. I utlized this solution:
where run_date is a timestamp like 2021-02-25 00:00:00
concat (
date_format(run_date, '%Y-%m'),
' wk ',
(week(run_date,1) - ( week(date_format(run_date, '%Y-%m-01')) - 1))
) as formatted_date
This outputs:
2021-02-23 ---> 2021-02 wk 4
2021-02-25 ---> 2021-02 wk 4
2021-02-11 ---> 2021-02 wk 2
2021-03-02 ---> 2021-03 wk 1
The idea behind this is that I want to know (with relative certainty) which week of the month in question did the date occur?
So we concatenate:
date_format(run_date, '%Y-%m') to get 2021-02
then we add the literal text string wk
then we use:
week(run_date, 1) to get the week (1 to start Monday) of this record, (which would be 7 because 02/21/2021 is in the 7th week of the year, and we subtract whatever the week is on the 1st day of this same month - the week() for 2021-02-01 is 5, because it is in the 5th week of the year:
(week(date_format(run_date, '%Y-%m-01'))
Unfortunately, this will start out the counting at 0, which people don't like, so we subtract 1 from the last part of the concatenation result so that the "week" start at 1.
This may be a good option:
SELECT
year(datetime_field) as year_date, week(datetime_field) as week_date
FROM
bd.table
GROUP BY
year_date, week_date;
It would look like this:
'2020', '14'
'2020', '15'
'2020', '16'
'2020', '17'
'2020', '18'