Help me to populate below columns as date without using to_date or to_char functions.
day
month
year
1
2
1995
2
3
1998
5
6
2020
output
date
01-02-1995
02-03-1998
05-06-2020
If Oracle, then concatenation of zero left-padded values might do the job (see line #7):
SQL> with test (day, month, year) as
2 (select 1, 2, 1995 from dual union all
3 select 2, 3, 1998 from dual
4 )
5 select day, month, year,
6 --
7 lpad(day, 2, '0') ||'-'|| lpad(month, 2, '0') || '-'|| year as result
8 from test;
DAY MONTH YEAR RESULT
---------- ---------- ---------- ----------------------------------------------
1 2 1995 01-02-1995
2 3 1998 02-03-1998
SQL>
If you want query without to_date and to_char. Let try below query:
SELECT
LPAD(EXTRACT(DAY FROM DATE (year || '-' || month || '-' || day)),2,'0')
|| '-'
|| LPAD(EXTRACT(MONTH FROM DATE (year || '-' || month || '-' || day)),2,'0')
|| '-'
|| EXTRACT(YEAR FROM DATE (year || '-' || month || '-' || day))
FROM YOUR_TABLE;
You should use TO_DATE as that is what it is designed for.
However, as an academic exercise, if you start with DATE '0001-01-01' and then use, for Oracle, ADD_MONTHS (or for MySQL, TIMESTAMPADD) for the years and months and addition for the days:
In Oracle:
SELECT t.*,
TO_DATE(year || '-' || month || '-' || day, 'YYYY-MM-DD') AS dt,
ADD_MONTHS(DATE '0001-01-01', 12 * (year - 1) + (month - 1)) + (day - 1) AS dt2
FROM table_name t
Which, for the sample data:
CREATE TABLE table_name(day, month, year) AS
SELECT 1, 2, 1995 FROM DUAL UNION ALL
SELECT 2, 3, 1998 FROM DUAL UNION ALL
SELECT 5, 6, 2020 FROM DUAL;
Outputs:
DAY
MONTH
YEAR
DT
DT2
1
2
1995
1995-02-01 00:00:00
1995-02-01 00:00:00
2
3
1998
1998-03-02 00:00:00
1998-03-02 00:00:00
5
6
2020
2020-06-05 00:00:00
2020-06-05 00:00:00
fiddle
Or MySQL:
SELECT t.*,
TIMESTAMPADD(MONTH, 12 * (year - 1) + (month - 1), DATE '0001-01-01')
+ (day - 1) AS dt
FROM table_name t
Which outputs:
day
month
year
dt
1
2
1995
19950201
2
3
1998
19980302
5
6
2020
20200605
fiddle
Related
I'm trying to get the start/end dates of a non-standard quarter using MySQL. This question/answer works great to get the start/end dates of standard quarters (Jan-Mar, Apr-Jun, etc.).
Any suggestions on how to modify the query if the quarter does not start on a typical fiscal year's quarters (Jan-Mar, Apr-Jun, etc.)? I have a case where I need the quarter to begin on a February (Feb-Apr, May-Jul, etc.) as well as beginning in March (Mar-May, Jun-Aug, etc.).
I have tried adjusting intervals to accommodate the shift in the months by 1 or 2, but because MySQL returns a set 1,2,3,4 for QUARTER() using a standard year's quarters, it's not working correctly.
Here are the queries from the previously linked question that return a start/end on a standard calendar year's quarters (passing in a date I'm interested in getting the start/end of the quarter it is in):
SELECT MAKEDATE(YEAR('2022-11-02'), 1) + INTERVAL QUARTER('2022-11-02') QUARTER - INTERVAL 1 QUARTER AS quarter_start;
+---------------+
| quarter_start |
+---------------+
| 2022-10-01 |
+---------------+
SELECT MAKEDATE(YEAR('2022-11-02'), 1) + INTERVAL QUARTER('2022-11-02') QUARTER - INTERVAL 1 DAY AS quarter_end;
+---------------+
| quarter_end |
+---------------+
| 2022-12-31 |
+---------------+
How can I adjust this to return a quarter_start of 2022-11-01 and quarter_end of 2023-01-31 if the quarter should be shifted forward by 1 month (quarters: Feb-Apr, May-Jul, Aug-Oct, Nov-Jan)?
You'll have to calculate it yourself from the month.
SELECT CASE
WHEN MONTH(date) = 1 THEN FORMAT_DATE(DATE_SUB(date, INTERVAL 1 YEAR), '%Y-11-01'))
WHEN MONTH(date) IN (2, 3, 4) THEN FORMAT_DATE(date, '%Y-02-01'))
WHEN MONTH(date) IN (5, 6, 7) THEN FORMAT_DATE(date, '%Y-05-01'))
WHEN MONTH(date) IN (8, 9, 10) THEN FORMAT_DATE(date, '%Y-08-01'))
ELSE FORMAT_DATE(date, '%Y-11-01'))
END AS quarter_start,
CASE
WHEN MONTH(date) = 1 THEN FORMAT_DATE(date, '%Y-01-31'))
WHEN MONTH(date) IN (2, 3, 4) THEN FORMAT_DATE(date, '%Y-04-30'))
WHEN MONTH(date) IN (5, 6, 7) THEN FORMAT_DATE(date, '%Y-07-31'))
WHEN MONTH(date) IN (8, 9, 10) THEN FORMAT_DATE(date, '%Y-10-31'))
ELSE FORMAT_DATE(DATE_ADD(date, INTERVAL 1 YEAR), '%Y-01-31'))
END AS quarter_end
This is simple date math.
select
date,
date - interval day(date)-1 day - interval (month(date) + offset) mod 3 month as quarter_start,
date - interval day(date)-1 day - interval (month(date) + offset) mod 3 - 3 month - interval 1 day as quarter_end
where offset is 2 for calendar quarters, 1 for quarters beginning in feb/may/aug/nov, 0 for quarters beginning in mar/jun/sep/dec.
I need to count data for a given <week | month | custom> interval grouped by a given time schedule that possibly spans 2 days. The chunks depends on customers working schedules.
Possible cases (for one month interval) :
all data from June 01, 2022 to July 01, 2022, each day between 08:00 pm and 04:00 am (overnight)
all data from June 01, 2022 to June 30, 2022, each day between 04:00 am and 08:00 pm
all data from June 01, 2022 to June 30, 2022, each day between 00:00 am and 23:59 pm
Here's what I came up with:
WITH RECURSIVE seq AS (
SELECT
0 AS value
UNION ALL
SELECT
value + 1
FROM
seq
WHERE
value < 29
),
period AS (
SELECT
'2022-06-01 20:00' + INTERVAL (value * 24 * 60) MINUTE AS start,
'2022-06-01 20:00' + INTERVAL (value * 24 * 60) MINUTE + INTERVAL (8* 60) MINUTE AS end
FROM seq
ORDER BY value DESC
)
SELECT *
FROM (
SELECT
DATE(sd.timestamp - INTERVAL(LEAST(20, 4)) HOUR) as date,
SUM(...) as count,
FROM sensor_data sd
WHERE sd.timestamp BETWEEN '2022-06-01 20:00' AND '2022-07-01 04:00'
AND HOUR(sd.timestamp) >= 20 AND HOUR(sd.timestamp) < 4
GROUP BY
date
) main_data
INNER JOIN period ON DATE(period.start) = date
Unfortunately in doesn't work for the first case (spans two days). Any ideas?
WITH RECURSIVE
cte AS (
SELECT datetime_from range_from,
datetime_from + INTERVAL range_length HOUR range_till
UNION ALL
SELECT range_from + INTERVAL 1 DAY,
range_till + INTERVAL 1 DAY
FROM cte
WHERE range_till < datetime_till
)
SELECT range_from, range_till, COUNT(*) rows_amount
FROM cte
LEFT JOIN test ON test.dt BETWEEN range_from AND range_till
GROUP BY 1, 2;
DEMO with some explanations.
I have sample dates in a table and what I need to get is each of the months between the start date and end date.
sample :
ID Startdate EndDate
1 01-01-2019 01-03-2019
2 01-08-2019 01-02-2020
I need to fetch months and year from these dates.
Desired output :
ID Dates
1 January 2019
1 February 2019
1 March 2019
2 August 2019
2 September 2019
2 October 2019
2 November 2019
2 December 2019
2 January 2020
2 February 2020
How cah I achieve this in MySQL and how to do increment or any loop kind of operation. On the query side I'm not getting any idea to move on this.
Here are a couple of ways to achieve this. The first will only work on MySQL 8+ and uses a recursive CTE to generate the months between StartDate and EndDate:
WITH RECURSIVE CTE AS (
SELECT ID, Startdate AS d, EndDate
FROM dates
UNION ALL
SELECT ID, d + INTERVAL 1 MONTH, EndDate
FROM CTE
WHERE d < EndDate
)
SELECT ID, DATE_FORMAT(d, '%M %Y') AS Dates
FROM CTE
ORDER BY ID, d
The second (which will run on any version of MySQL) uses a numbers table (in this case numbers from 0 to 99, allowing for a range of up to 99 months between StartDate and EndDate; if you need longer, adding more tables to the CROSS JOIN will increase that range by a factor of 10 for each table added) to generate the list of months difference, this is then JOINed to the original table so that the generated date Startdate + INTERVAL n.n MONTH is less than or equal to EndDate:
SELECT ID, DATE_FORMAT(Startdate + INTERVAL n.n MONTH, '%M %Y') AS Dates
FROM dates
JOIN (
SELECT n10.n * 10 + n1.n * 1 AS n
FROM (
SELECT 0 n UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
) n10
CROSS JOIN (
SELECT 0 n UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9
) n1
) n ON Startdate + INTERVAL n.n MONTH <= EndDate
ORDER BY ID, Startdate + INTERVAL n.n MONTH
Having generated our list of dates, we format it using DATE_FORMAT and a format string of %M %Y. For both queries the output is:
ID Dates
1 January 2019
1 February 2019
1 March 2019
2 August 2019
2 September 2019
2 October 2019
2 November 2019
2 December 2019
2 January 2020
2 February 2020
Demo on dbfiddle
I'm trying to get a running total for each month of this year. So my ideal result would be something such as:
January | 4
February | 5
March | 8
April | 10
May | 12
June | 14
July | 16
August | 17
September | 18
October | 21
November | 22
December | 22
The basic count would just check against first of the month such as:
January 1 (sum where created_at < January 1, 2018)
February 1 (sum where created_at < February 1, 2018)
March 1 (sum where created_at < March 1, 2018)
April 1 (sum where created_at < April 1, 2018)
...
Doing it for one month at a time is easy, as I can just do something like this:
SELECT *
FROM businesses
WHERE created_at < CONCAT(YEAR(CURDATE()), "-12-01 00:00:01")
I tried using one of the examples from another Stackoverflow answer, but it's not working quite as desired as it seems like the sort or something is messed up so the counts are not lining up right.
You can see schema build and current SQL here:
http://sqlfiddle.com/#!9/0c23cc/20
Try something like this.
SELECT
MONTHNAME( created_at ) AS theMonth,
(
SELECT
count( * )
FROM
businesses AS u1
WHERE
YEAR ( u1.created_at ) = YEAR ( businesses.created_at )
AND u1.created_at <= date_ADD( last_day( businesses.created_at ), INTERVAL 1 DAY )
) AS totals
FROM
businesses
WHERE
YEAR ( businesses.created_at ) = YEAR ( CURDATE( ) )
GROUP BY
MONTHNAME( businesses.created_at )
ORDER BY
MONTH ( businesses.created_at ) ASC
I am looking to breakdown a Month into weeks(starting Monday) in MySQL.
For example,
Sept 3 - 9th
Sept 10 - 16th
How to achieve this using MySql?
Thanks in advance.
This query will produce the results you want. It generates a table of possible week numbers in the month (0 to 4) using a UNION, and then it adds those week numbers to the computation of the first Monday of the month (stored in the variable #firstday which is JOINed to the table of week numbers).
SELECT #firstday + INTERVAL w WEEK AS start, #firstday + INTERVAL w WEEK + INTERVAL 6 DAY AS end
FROM (SELECT 0 AS w UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) weeks
JOIN (SELECT #firstday := FROM_DAYS(TO_DAYS(CURDATE())-DAY(CURDATE())+1) +
(7 - WEEKDAY(FROM_DAYS(TO_DAYS(CURDATE())-DAY(CURDATE())+1))) % 7) f
HAVING end <= LAST_DAY(#firstday)
Output:
start end
2018-09-03 2018-09-09
2018-09-10 2018-09-16
2018-09-17 2018-09-23
2018-09-24 2018-09-30
To run the query for any given month, replace CURDATE() in the computation of #firstday (4 places) with a date in the month you are interested in e.g.
SELECT #firstday + INTERVAL w WEEK AS start, #firstday + INTERVAL w WEEK + INTERVAL 6 DAY AS end
FROM (SELECT 0 AS w UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) weeks
JOIN (SELECT #firstday := FROM_DAYS(TO_DAYS('2018-01-20')-DAY('2018-01-20')+1) +
(7 - WEEKDAY(FROM_DAYS(TO_DAYS('2018-01-20')-DAY('2018-01-20')+1))) % 7) f
HAVING end <= LAST_DAY(#firstday)
Output:
start end
2018-01-01 2018-01-07
2018-01-08 2018-01-14
2018-01-15 2018-01-21
2018-01-22 2018-01-28
If you have the flexibility of setting variables, you can clean up the query like so:
SET #day = '2018-01-20';
SET #firstday := FROM_DAYS(TO_DAYS(#day)-DAY(#day)+1) + (7 - WEEKDAY(FROM_DAYS(TO_DAYS(#day)-DAY(#day)+1))) % 7;
SELECT #firstday + INTERVAL w WEEK AS start, #firstday + INTERVAL w WEEK + INTERVAL 6 DAY AS end
FROM (SELECT 0 AS w UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) weeks
HAVING end <= LAST_DAY(#firstday)
You can use function week(date) - https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_week