Sort dbReadtable using wday in R - mysql

I have a dbReadtable which I wanna sort by week date. My table looks as follow:
Id Date Number
1 2020-11-01 1
2 2020-11-03 3
3 2020-11-02 4
4 2020-11-01 2
5 2020-11-02 4
6 2020-11-03 3
7 2020-11-06 7
8 2020-11-05 4
9 2020-11-08 2
I want the output to look something like this:
Day Number
Sunday 5
Monday 8
Tuseday 6
Thursday 4
Friday 7
For this, I wanna use $wday in lubridate library.
My code looks as follow:
data <- dbReadTable(con, "observations")
How do I solve this?

Using data.table and lubridate and assuming Date is already a date (not a string).
library(lubridate)
library(data.table)
data <- dbReadTable(con, "observations")
data[, by=.(Day=wday(Date, label=TRUE, abbr=FALSE, locale="C")), .(Number=sum(Number))]
# Day Number
#1: Sunday 5
#2: Tuesday 6
#3: Monday 8
#4: Friday 7
#5: Thursday 4
I added locale to return english names for days (I'm french and get french names :-).

Related

Concat results by days ranges

I have an apartment table:
Id: name:
1 apartment1
2 apartment2
3 apartment3
3 apartment4
And an availabilities table:
Id apartment_id availability_date remaning_number_places
1 1 01/02/2017 3
2 1 02/02/2017 2
3 1 03/02/2017 2
4 1 04/02/2017 2
5 2 01/02/2017 2
6 2 03/02/2017 2
7 2 04/02/2017 2
8 3 12/02/2017 2
9 3 03/02/2017 1
10 3 04/02/2017 1
11 4 12/02/2017 2
12 4 02/02/2017 2
I would like to do a search by starting and ending date with a minimum number of places, for example if I search from 01/02/2017 to 04/02/2017 I should have this result:
Apartment_ids availabilities starting_date ending_date nbr_places
[1] [1,2,3,4] 01/02/2017 04/02/2017 2
[2,4] [5,6,7,12] 01/02/2017 04/02/2017 2
The result must be a concatenation of contiguous days corresponding to given dates.
Thank you at advance.
EDIT : Trying to give more details hereunder:
I need an SQL query to look for an apartment availability for a given period.
As a result, if an apartment is available for the whole period I'm expecting to get it. In addition, I also need to get if more than one apartment are required to cover this given period. In that case, I'm expecting a contiguous list of apartments as a result.
Please, can someone help me build this query?

How to create a SQL query that calculate monthly grow in population

I want to create a SQL query that count the number of babies born in month A, then it should count the babies born in month B but the second record should have the sum of month A plus B. For example;
Month | Number
--------|---------
Jan | 5
Feb | 7 <- Here were 2 babies born but it have the 5 of the previous month added
Mar | 13 <- Here were 6 babies born but it have the 7 of the two previous months added
Can somebody maybe please help me with this, is it possible to do something like this?
I have a straight forward table with babyID, BirthDate, etc.
Thank you very much
Consider using a subquery that calculates a running count. Both inner and outer query would be aggregate group by queries:
Using the following sample data:
babyID Birthdate
1 2015-01-01
2 2015-01-15
3 2015-01-20
4 2015-02-01
5 2015-02-03
6 2015-02-21
7 2015-03-11
8 2015-03-21
9 2015-03-27
10 2015-03-30
11 2015-03-31
SQL Query
SELECT MonthName(BirthDate) As BirthMonth, Count(*) As BabyCount,
(SELECT Count(*) FROM BabyTable t2
WHERE Month(t2.BirthDate) <= Month(BabyTable.BirthDate)) As RunningCount
FROM BabyTable
GROUP BY Month(BirthDate)
Output
BirthMonth BabyCount RunningCount
January 3 3
February 3 6
March 5 11

How to get this coming Sunday's date?

I need to get "this coming Sunday"'s date
How could I do this?
I've seen the DAYOFWEEK function but that's not really what I'm after (might be useful in the WHERE clause)
EDIT:
I changed question back from my change to Saturday to the original Sunday since I got some valid answers for Sunday and it may help some people in the future
I found a number of other 'end of week' date questions and answers elsewhere (including here on SO)
The most useful solution for me was the accepted answer found here.
UPDATE
Better use curdate() instead of now(), so the final conversion to DATE type via date() can be omitted.
SELECT curdate() + INTERVAL 6 - weekday(curdate()) DAY;
for next sunday or
SET #date = '2014-03-05';
SELECT #date + INTERVAL 6 - weekday(#date) DAY;
for a variable date.
ORIGINAL ANSWER
Simply use this statement for the next sunday:
SELECT date(now() + INTERVAL 6 - weekday(now()) DAY);
Output
+-----------------------------------------------+
| date(now() + INTERVAL 6 - weekday(now()) DAY) |
+-----------------------------------------------+
| 2014-04-13 |
+-----------------------------------------------+
Explanation:
weekday(now()) returns the current weekday (starting with 0 for monday, 6 is sunday). Subtract the current weekday from 6 and get the remaining days until next sunday as a result. Then add them to the current date and get next sunday's date.
Or if you want to keep it flexible to work with any date:
SET #date = '2014-03-05';
SELECT date(#date + INTERVAL 6 - weekday(#date) DAY);
Output
+-----------------------------------------------+
| date(#date + INTERVAL 6 - weekday(#date) DAY) |
+-----------------------------------------------+
| 2014-03-09 |
+-----------------------------------------------+
To find the next date for given week day use this query. set the value of the week day you want in the THEDAY variable.
SET #THEDAY = 1;
SELECT DATE_ADD(NOW(), INTERVAL if( #THEDAY > WEEKDAY(NOW()) , (#THEDAY - WEEKDAY(NOW())) , (7 - WEEKDAY(NOW())) + #THEDAY) DAY)
Note that the weekday index starts from 0 For Monday ...... 6 For Sunday
Date()+8-WeekDay(Date())
and try this
=IIf(Weekday(Now())=1,DateAdd("d",7,Now()),
IIf(Weekday(Now())=2,DateAdd("d",6,Now()),
IIf(Weekday(Now())=3,DateAdd("d",5,Now()),
IIf(Weekday(Now())=4,DateAdd("d",4,Now()),
IIf(Weekday(Now())=5,DateAdd("d",3,Now()),
IIf(Weekday(Now())=6,DateAdd("d",2,Now()),
IIf(Weekday(Now())=6,DateAdd("d",1,Now()) )))))))
the WEEK function can be paired with STR_TO_DATE for a nice one-liner:
SELECT STR_TO_DATE(CONCAT(YEAR(NOW()),WEEK(NOW(),1), ' Sunday'), '%X%V %W') as `this Sunday`;
+-------------+
| this Sunday |
+-------------+
| 2014-04-13 |
+-------------+;
If you follow the doc links, the overall strategy is mostly gleaned from the note on STR_TO_DATE about year/week conversion. Then the mode argument to WEEK is used to treat Sunday as the last instead of first day of the week. Essentially, we construct a string like this:
'201415 Sunday'
Which is to be interpreted as "in 2014, Sunday of the 15th week".
Just in case, I tested this at the year boundary... looks okay so far!
SELECT STR_TO_DATE(CONCAT(YEAR('2014-12-31'),WEEK('2014-12-31',1), ' Sunday'), '%X%V %W') as `this Sunday`;
+-------------+
| this Sunday |
+-------------+
| 2015-01-04 |
+-------------+
I posted a similar answer in What is the MySQL alternative to Oracle's NEXT_DAY function? which a more general solution to the question being asked here. The solution below will help you get to any specified next day (Sunday, Monday, Tuesday, Wednesday, Thursday, Friday or Saturday) similar to the NEXT_DAY() function in oracle.
Short Version:
Utilizing DAYOFWEEK() you can leverage the number values to create a closed formula that tells you how many days to add. You can then utilize DATE_ADD to help you shift the date. There may be a cleaner way, however you should be able to make a function out of this.
The following is an Excel formula, which you use to verify all 49 use cases: =MOD(MOD(Next-Input, 7)+7,7)
Some examples of how the excel calculations can be translated into SQL:
SELECT (((1-DAYOFWEEK('2018-08-15')) % 7)+7) % 7 AS DaysToAddToGetNextSundayFromWednesday
FROM dual; -- 4
SELECT DATE_ADD('2018-08-15', INTERVAL (((1-DAYOFWEEK('2018-08-15')) % 7)+7) % 7 DAY) AS NextSundayFromDate
FROM dual; -- 2018-08-19
If you plan to use the above often, you'll probably want to make a function or stored procedure.
Long Version:
I've run into this problem multiple times over the years. First time I created a giant case statement for all 49 cases. I found that this made the queries super big and not clean. I wanted a cleaner, simpler solution like a closed in formula. Below are details to to calculations I did to confirm the formula above works. I tested this with MySQL 5.7 if you are using MySQL 8.5 it looks like the function is built in ( Reference: http://www.sqlines.com/mysql/how-to/next_day ).
Note: Excel doesn't return negative results for modulus, where MySQL does. That is why we add 7 and do another modulus.
DAYOFWEEK()
Sun 1
Mon 2
Tues 3
Wed 4
Thur 5
Fri 6
Sat 7
Input Next Expected Days to Add Formula Result
1 1 0 0
1 2 1 1
1 3 2 2
1 4 3 3
1 5 4 4
1 6 5 5
1 7 6 6
2 1 6 6
2 2 0 0
2 3 1 1
2 4 2 2
2 5 3 3
2 6 4 4
2 7 5 5
3 1 5 5
3 2 6 6
3 3 0 0
3 4 1 1
3 5 2 2
3 6 3 3
3 7 4 4
4 1 4 4
4 2 5 5
4 3 6 6
4 4 0 0
4 5 1 1
4 6 2 2
4 7 3 3
5 1 3 3
5 2 4 4
5 3 5 5
5 4 6 6
5 5 0 0
5 6 1 1
5 7 2 2
6 1 2 2
6 2 3 3
6 3 4 4
6 4 5 5
6 5 6 6
6 6 0 0
6 7 1 1
7 1 1 1
7 2 2 2
7 3 3 3
7 4 4 4
7 5 5 5
7 6 6 6
7 7 0 0
The accepted answer will return previous Saturday on Sunday.
If you need the next Saturday for Sunday use this
SELECT
CAST(
Case When weekday(now()) = 6 Then (now() + INTERVAL weekday(now()) DAY)
else (now() + INTERVAL 5 - weekday(now()) DAY)
end
As Date) as saturday

Find first and last business day in R or Mysql

I'm looking to get a list of the first and last business days of the month.
Its basically a list of business days:
2009-01-03
2009-01-04
2009-01-05
...
I just want to get a list of the first and last days, basically and max and min day(date) for each year-month combination.
Any suggestions?
Your question states that you already have a list of business days and that you need a way of finding the minimum and maximum for each year-month combination.
You can use ddply in package plyr to do this. I also make use of package lubridate because it has some convenience functions to extract the year and month from a date.
Create some data:
library(lubridate)
x <- sample(seq(as.Date("2011-01-01"), by="1 day", length.out=365), 100)
df <- data.frame(date=x, year=year(x), month=month(x))
Now extract the min and max for each month:
library(plyr)
ddply(df, .(year, month), summarize, first=min(date), last=max(date))
year month first last
1 2011 1 2011-01-03 2011-01-30
2 2011 2 2011-02-03 2011-02-19
3 2011 3 2011-03-06 2011-03-29
4 2011 4 2011-04-09 2011-04-30
5 2011 5 2011-05-01 2011-05-29
6 2011 6 2011-06-04 2011-06-28
7 2011 7 2011-07-02 2011-07-29
8 2011 8 2011-08-10 2011-08-30
9 2011 9 2011-09-01 2011-09-28
10 2011 10 2011-10-07 2011-10-31
11 2011 11 2011-11-01 2011-11-28
12 2011 12 2011-12-01 2011-12-30

Sum of overlap durations for each combination of 2 foreign keys in MySQL

i have a database with workers, stations and session. A session describes at which time which worker has been on which station. I managed to build a query that gives me the duration of the overlap of each session.
SELECT
sA.station_id,
sA.worker_id AS worker1,
sB.worker_id AS worker2,
SEC_TO_TIME(
TIME_TO_SEC(LEAST(sA.end,sB.end)) - TIME_TO_SEC(GREATEST(sA.start,sB.start))
) AS overlap
FROM
`sessions` AS sA,
`sessions` AS sB
WHERE
sA.station_id = sb.station_id
AND
sA.station_id = 6
AND (
sA.start BETWEEN sB.start AND sB.end
OR
sA.end BETWEEN sB.start AND sB.end
)
With this query i get an result like this
station_id worker1 worker2 overlap
6 1 1 09:00:00
6 2 1 02:30:00
6 5 1 00:00:00
6 1 1 09:00:00
6 2 1 01:30:00
6 3 1 09:00:00
...
6 12 3 02:00:00
6 14 3 01:00:00
6 17 3 02:00:00
...
What i would like now is to sum up the overlap for every combination of worker1 and worker2 to get the overall overlap duration.
I tried different ways of using SUM() and GROUP BY but i never got the wanted result.
SELECT
...
SEC_TO_TIME(
**SUM**(TIME_TO_SEC(LEAST(sA.end,sB.end)) - TIME_TO_SEC(GREATEST(sA.start,sB.start)))
) AS overlap
...
#has as result
station_id worker1 worker2 overlap
6 1 1 838:59:59
#in combination with
GROUP BY
worker1
#i get
station_id worker1 worker2 overlap
6 1 1 532:30:00
6 2 1 -33:00:00
6 3 1 270:30:00
6 5 1 598:30:00
6 6 1 542:00:00
6 7 1 508:00:00
6 8 5 53:00:00
6 9 1 54:30:00
6 10 1 310:00:00
6 11 1 -108:00:00
6 12 1 593:30:00
6 14 1 97:30:00
6 15 1 -53:30:00
6 17 1 293:30:00
the last result is close but i am still missing a lot of combinations. I also dont understand why the combination 8 - 5 is displayed.
thanks for ur help (and time to read)
aaargh, sorry for my stupidity, the solution was fairly simple
....
SUM(((UNIX_TIMESTAMP(LEAST(sA.end,sB.end))-UNIX_TIMESTAMP(GREATEST(sA.start,sB.start)))/3600))
...
GROUP BY station_id, worker1, worker2
ORDER BY worker1, worker2
i switched to using timestamps and transforming it to hours by /3600 because my former used approach with TIME_TO_SEC and SEC_TO_TIME only used the TIME part of the DATETIME field and thereby produced some wrong numbers. With MySQL 5.5 i could use TO_SECONDS but unfortunately my server is still runing 5.1.