I am trying to find the last entry for the previous years quarter.
All I can access is year i.e 2021 and quarter i.e 1
Here is the data in my database:
id
name
start
end
16
April 2021
2021-04-01
2021-04-30
15
March 2021
2021-03-01
2021-03-31
14
February 2021
2021-02-01
2021-02-28
57
November 2020
2020-11-01
2020-11-30
55
October 2020
2020-10-01
2020-10-31
29
September 2020
2020-09-01
2020-09-30
27
July 2020
2020-07-01
2020-07-31
24
April 2020
2020-04-01
2020-04-30
23
March 2020
2020-03-01
2020-03-31
22
February 2020
2020-02-01
2020-02-29
21
January 2020
2020-01-01
2020-01-31
Using the MySQL quarter function I can get it to print out the quarter as an integer in another column:
SET #given_year = 2021;
SET #given_quarter = 1;
SELECT
id, name, start, end, QUARTER(end) as "Q"
FROM
submissions
id
name
start
end
Q
16
April 2021
2021-04-01
2021-04-30
2
15
March 2021
2021-03-01
2021-03-31
1
14
February 2021
2021-02-01
2021-02-28
1
57
November 2020
2020-11-01
2020-11-30
4
55
October 2020
2020-10-01
2020-10-31
4
29
September 2020
2020-09-01
2020-09-30
3
27
July 2020
2020-07-01
2020-07-31
3
24
April 2020
2020-04-01
2020-04-30
2
23
March 2020
2020-03-01
2020-03-31
1
22
February 2020
2020-02-01
2020-02-29
1
21
January 2020
2020-01-01
2020-01-31
1
I tried using WHERE and LIKE but it is returning 0 rows:
SELECT * FROM (
SELECT
id, name, start, end, QUARTER(end) as "Q"
FROM
submissions as s
) AS vs
WHERE
vs.end
LIKE
#given_year
AND
vs.Q < #given_quarter
I also need to account for the possibility that there may be no rows this year and I need to find the previous year.
For example with these two rows, if I was passed the year 2021 and quarter 1 I would need to return November of the previous year and a different quarter.
id
name
start
end
Q
14
February
2021
2021-02-01
2021-02-28
57
November
2020
2020-11-01
2020-11-30
If I understand correctly, you want all the rows from the quarter in the data before a given quarter. You can filter and use dense_rank():
select s.*
from (select s.*,
dense_rank() over (order by year(start) desc, quarter(start) desc) as seqnum
from submissions s
where year(start) < #given_year or
(year(start) = #given_year and quarter(start) < #given_quarter)
) s
where seqnum = 1;
The above returns all rows from the previous quarter (which is what I thought you wanted). If you want only one row:
select s.*
from submissions s
where year(start) < #given_year or
(year(start) = #given_year and quarter(start) < #given_quarter)
order by start desc
limit 1;
Related
I have a table with ID and Date columns.
Table A:
ID
Date
24
2019-10-29
24
2019-10-30
24
2019-10-31
.....
....
I need to add a column called "Week_Num" such that:
If there is a new "ID" and the first date begins on a Tuesday (eg: 29th Oct,2019 in ID 24 is Tuesday) then the week will start with 1
Week will always end on Saturday irrespective of whether 7 days are over or not with only one exception (see point 3)
If there is a new "ID" and the first date begins before Tuesday (eg: 25th Oct,2020 in ID 25 is Sunday) then the week will start with 0 and once it reaches Tuesday the week_num will become 1.
Expected Output:
ID
Date
Day_Of_Week
Week_Num
24
2019-10-29
Tue
1
24
2019-10-30
Wed
1
24
2019-10-31
Thur
1
24
2019-11-01
Fri
1
24
2019-11-02
Sat
1
24
2019-11-03
Sun
2
24
2019-11-04
Mon
2
24
2019-11-05
Tues
2
24
2019-11-06
Wed
2
24
2019-11-07
Thurs
2
24
2019-11-08
Fri
2
24
2019-11-09
Sat
2
24
..........
.
..
24
2020-03-14
.
..
25
2020-10-25
Sun
0
25
2020-10-26
Mon
0
25
2020-10-27
Tue
1
25
2020-10-28
Wed
1
25
2020-10-29
Thur
1
25
2020-10-30
Fri
1
25
2020-10-31
Sat
1
What I have so far:
select
distinct ID,min(Date) over (partition by ID order by date) as firstTuesdayOfSeason
from
TableA
group by ID,Date
having datepart(weekday,Date)=3
which gets the first Tuesday for every new ID and gives the following output:
ID
firstTuesdayOfSeason
24
2019-10-29
25
2020-10-27
I was thinking of joining this table with the Table A (the one with ID, Date as columns) but I don't know how to implement the weird Saturday logic.
This might work for you.
Find min-date, offset to Tuesday for each ID, and calculate using date-diff for each row against the min-date
select a.ID, a.Date, weekday(a.Date), greatest(0, 1 + floor((datediff(a.Date, b.since) - b.off) / 7)) week_num
from TableA a
join (
select ID, min(Date) As since, (case when weekday(min(Date)) > 1 then 8 - weekday(min(Date)) else 1 - weekday(min(Date)) end) off
from TableA
group by ID
) b ON a.ID = b.ID
order by a.ID, a.Date
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=657c96465338a398ced73bc256ff92c0
There is a column representing 24 hours.
Data comes in every 15 minutes.
For example, at 10:15, the value is entered in the DateTime column of the 10H column.
But... The client wants to set the standard for the day at 6:30 a.m. and set it to 6:30 the next day.
If you look at the column below, should sum the value from column 6h.. Is there any way?
DateTime 0H 1H ..6H....7H...8H..9H..10H..~23H
2020 11 10 00:00:00 979 958
2020 11 10 00:15:00 987 954
2020 11 10 00:30:00 987 958
2020 11 10 00:45:00 960 956
2020 11 11 00:00:00 0 0
2020 11 11 00:15:00 0 0
2020 11 11 00:30:00 0 0
2020 11 11 00:45:00 0 0
2020 11 12 00:00:00 995 995
2020 11 12 00:15:00 991 993
2020 11 12 00:30:00 1000 993
2020 11 12 00:45:00 993 996
I want value
2020-11-15 06:30 ~ 2020-11-16 06:30 values sum
Consider breaking hour blocks into separate SELECT segments that add corresponding hour columns. Then, bind all parts together by UNION ALL. Finally, aggregate all hour blocks for final SUM.
Below sums all values between 2020-11-15 06:30 - 2020-11-16 06:30 (not including upper limit). Be sure to fill in the abbreviated ... for needed columns:
SELECT SUM(sub.HoursTotal) AS DayTotal
FROM
(
-- PARTIAL HOUR - 6:30 AM - 6:45 AM
SELECT [6h] AS HoursTotal
FROM myTable
WHERE logdatetime BETWEEN '2020 11-15 00:30:00' AND
'2020 11-15 00:45:00'
UNION ALL
-- FULL HOURS - 7:00 AM - 23:00 PM
SELECT [7h] + [8h] + ... + [23h] AS HoursTotal
FROM myTable
WHERE logdatetime BETWEEN '2020 11-15 00:00:00' AND
'2020 11-15 00:45:00'
UNION ALL
-- FULL HOURS - 12:00 AM - 5:00 AM
SELECT [0h] + [1h] + ... + [5h] AS HoursTotal
FROM myTable
WHERE logdatetime BETWEEN '2020 11-16 00:00:00' AND
'2020 11-16 00:45:00'
UNION ALL
-- PARTIAL HOUR - 6:00 AM - 6:15 AM
SELECT [6h] AS HoursTotal
FROM myTable
WHERE logdatetime BETWEEN '2020 11-16 00:00:00' AND
'2020 11-16 00:15:00'
) sub
Of course, ideally your table maintains a normalized structure of long format with two columns for datetime and value. Then, querying is much easier:
logDateTimewithHour Value
2020 11-15 00:00:00 ###
2020 11-15 00:15:00 ###
2020 11-15 00:30:00 ###
2020 11-15 00:45:00 ###
2020 11-15 01:00:00 ###
2020 11-15 01:15:00 ###
2020 11-15 01:30:00 ###
2020 11-15 01:45:00 ###
... ...
2020 11-16 22:00:00 ###
2020 11-16 22:15:00 ###
2020 11-16 22:30:00 ###
2020 11-16 22:45:00 ###
2020 11-16 23:00:00 ###
2020 11-16 23:15:00 ###
2020 11-16 23:30:00 ###
2020 11-16 23:45:00 ###
SELECT SUM(Value) AS DayTotal
FROM myLongTable
WHERE logDateTimewithHour BETWEEN '2020 11-15 06:30:00'
AND '2020 11-16 06:15:00'
If I don't use GROUP_CONCAT() then there is no difficulty to the group and order the rows according to date-month-year
Following code:
SELECT FROM_UNIXTIME(orders.date_time,'%d %m %Y') AS date,
SUM(orders.net_amount) AS total_sales,
COUNT(FROM_UNIXTIME(orders.date_time,'%D %b %Y')) AS total_orders
FROM orders
JOIN users ON orders.user_id = users.id
WHERE FROM_UNIXTIME(orders.date_time,'%d %m %Y') != DATE_FORMAT(users.reg_date_time, '%d %m %Y')
GROUP BY date
ORDER BY Month(1)
O/P:
21 12 2019 1092 1 pinky
04 01 2020 1050 1 harshit
30 12 2019 21 1 robin
05 01 2020 987 2 chetan
31 12 2019 1239 2 rahul
30 11 2019 157.5 1 rahul
01 01 2020 651 1 rahul
15 12 2019 1575 1 isha
03 01 2020 598.5 1 manvi
SEE the names are not concating
But as soon as I add this line:
GROUP_CONCAT(users.firstname SEPARATOR '-')) AS names
like this:
SELECT FROM_UNIXTIME(orders.date_time,'%d %m %Y') AS date,
SUM(orders.net_amount) AS total_sales,
GROUP_CONCAT(users.firstname SEPARATOR '-') AS names,
COUNT(FROM_UNIXTIME(orders.date_time,'%D %b %Y')) AS total_orders
FROM orders
JOIN users ON orders.user_id = users.id
WHERE FROM_UNIXTIME(orders.date_time,'%d %m %Y') != DATE_FORMAT(users.reg_date_time, '%d %m %Y')
GROUP BY date
ORDER BY Month(1)
O/P:
01 01 2020 651 1 rahul
03 01 2020 598.5 1 manvi
04 01 2020 1050 1 harshit
05 01 2020 987 2 chetan-saurabh
15 12 2019 1575 1 isha
21 12 2019 1092 1 pinky
30 11 2019 157.5 1 rahul
30 12 2019 21 1 robin
31 12 2019 1239 2 rahul-manvi
then the order changed by day-order(without proper month and year order) but the grouping is correct.
Am I doing something wrong?
Use ORDER BY MONTH(orders.date_time). The problem is that your date column is not formatted as a valid MySQL date, so it's not extracting the month correctly.
I have output as below
ID Date
Null 2012-10-01
1 2012-10-02
2 2012-10-03
NULL 2012-10-04
3 2012-10-05
NULL 2012-10-06
4 2012-10-07
NULL 2012-10-08
5 2012-10-10
NULL 2012-10-11
NULL 2012-10-12
6 2012-10-13
NULL 2012-10-16
As it has missing dates with value as NULL. I need to show final output as
2012-10-01 - 2012-10-01 (1 day )
2012-10-04 - 2012-10-04(1 day )
2012-10-06 - 2012-10-06(1 day )
2012-10-08 - 2012-10-08(1 day )
2012-10-11 - 2012-10-12(2 day )
2012-10-14 - 2012-10-14(1 day )
You can generate the date ranges using the following query:
select
min(date) as start,
max(date) as end,
datediff(max(date), min(date)) + 1 as numDays
from
(select #curRow := #curRow + 1 AS row_number, id, date
from Table1 join (SELECT #curRow := 0) r where ID is null) T
group by
datediff(date, '2012-10-01 00:00:00') - row_number;
The logic is based on a clever trick for grouping consecutive ranges. First, we filter and number the rows in the subquery. Then, the rows that are grouped together are found by comparing the number of days after 2012-10-01 to the row number. If any rows share this value, then they must be consecutive, otherwise there would be a "jump" between two rows and the expression datediff(date, '2012-10-01 00:00:00') - row_number would no longer match.
Sample output (DEMO):
START END NUMDAYS
October, 01 2012 00:00:00+0000 October, 01 2012 00:00:00+0000 1
October, 04 2012 00:00:00+0000 October, 04 2012 00:00:00+0000 1
October, 06 2012 00:00:00+0000 October, 06 2012 00:00:00+0000 1
October, 08 2012 00:00:00+0000 October, 08 2012 00:00:00+0000 1
October, 11 2012 00:00:00+0000 October, 12 2012 00:00:00+0000 2
October, 16 2012 00:00:00+0000 October, 16 2012 00:00:00+0000 1
From there I think it should be pretty trivial for you to get the exact output you are looking for.
I have a table with a column Year and ID
YEAR ID
1988 29
1989 89
1990 22
1992 9
1994 8
1998 23
1922 20
August 1990 12
September 2009 14
August 1991 11
November 2009 33
October 1990 30
January 1990 55
March 2001 24
Is there way I can sort the table in such a way that my final result is in Order.. I am looking for the result like
YEAR ID
1922 20
1988 29
1989 89
1990 22
1992 9
1994 8
1998 23
January 1990 55
August 1990 12
October 1990 30
August 1991 11
March 2001 24
September 2009 14
November 2009 33
Thank you in advance
Just replace myYear with your table name...
select year,id
from
(select year,id,
case when STR_TO_DATE(year,'%Y') is not null then STR_TO_DATE(year,'%Y') else STR_TO_DATE(year,'%M %Y') end as d,
case when STR_TO_DATE(year,'%Y') is not null then 0 else 1 end as ob
from myYear
) y
order by ob asc,d asc;