My requirement is to populate week number against calendar date.The catch is week number will start from October 1 and end at December 7.
So week commencing October 1 will be treated as week 1 , 7th October as week 2 and so on last week number will populate against December 7. Rest will have week number column as NULL. How to do it in hive ?
with t as (select date '2014-10-23' as dt)
select case
when dt between cast(concat(date_format(dt,'yyyy'),'-10-01') as date)
and cast(concat(date_format(dt,'yyyy'),'-12-07') as date)
then datediff (dt,cast(concat(date_format(dt,'yyyy'),'-10-01') as date)) div 7 + 1
end as week_number
from t
+-------------+
| week_number |
+-------------+
| 4 |
+-------------+
Related
I have a table that contains week number in string and number. I want to sum number with week and get the next week.
for example
tableA
week num
2022-1 1
2022-3 3
output
week num new_week
2022-1 1 2022-2
2022-3 3 2022-6
2022-52 2 2023-2
As a result, I converted the week into the date, added the week to the date, and finally converted the date back to the week. However, when I try to work date to week, I have issues. The SQL below is what I'm using
CONCAT(YEAR(DATEADD('week', num, date)), WEEK(DATEADD('week', num, date)))
I am not using the calendar year. Due to the fact that my week begins on the first Friday of every year, the calculation is incorrect. Would it be possible to avoid the need to convert week into date and date into week?
I wrote a small JS UDF to do your "week" math. It seems if December 31 is Thursday, then that year has 53 weeks. Good thing is, you don't need to convert your "year-week" to dates.
create or replace function addweeks( spcweek VARCHAR, num VARCHAR ) returns VARCHAR
LANGUAGE JAVASCRIPT
AS
$$
year = parseInt(SPCWEEK.substring( 0, 4 ));
week = parseInt(SPCWEEK.substring( 5 ));
week = week + parseInt(NUM);
weekinyear = (new Date(year, 11, 31).getDay() == 4 ? 53 : 52);
while (week > weekinyear ) {
week = week - weekinyear;
weekinyear = (new Date(year, 11, 31).getDay() == 4 ? 53 : 52);
year ++;
}
return year + "-" + week;
$$
;
select myweek, num, addweeks( myweek, num) new_week
from mydata;
+---------+-----+----------+
| MYWEEK | NUM | NEW_WEEK |
+---------+-----+----------+
| 2022-1 | 1 | 2022-2 |
| 2022-3 | 3 | 2022-6 |
| 2022-52 | 2 | 2023-2 |
| 2020-52 | 2 | 2021-1 |
+---------+-----+----------+
I think you can correct my logic if there is an error in calculating the total weeks of the year.
With a bit of string fiddling you could do the calulation like this.
SELECT week, num, CONCAT( SUBSTRING(week FROM 1 for 5), num + SUBSTRING(week FROM INSTR(week, '-')+1))
FROM table;
CREATE TABLE rpt_tab (
e_id NUMBER(10),
region VARCHAR2(20),
stages VARCHAR2(20),
end_date DATE
);
INSERT INTO rpt_tab VALUES(11,'Mumbai','STG_1','12-04-22');
INSERT INTO rpt_tab VALUES(12,'France','STG_1','13-04-22');
INSERT INTO rpt_tab VALUES(13,'France','STG_1','14-04-22');
COMMIT;
I need to write a logic that will give me the data after finding the last Tuesday from the end_date column. I need a report with the logic as mentioned below:
If today is 12th April i.e SYSDATE and day is Tuesday then the report should give me only today's date data only.
If suppose the date is 13th April i.e tommorows date then the report should give me data count from 12th April(Tuesday) and 13th April.
Basically, the cycle will be from Tueday to Tuesday. If the date is 19th April (Tuesday) then the data count should be from 12th - 19th(Tuesday).
If the date is 19th April then again the cycle will be continued as mention in point no. 1 that will check if the sysdate is Tuesday and sysdate then it will give me the count.
My attempt:
WITH a AS(
SELECT COUNT(*) since_tuesday FROM rpt_tab
WHERE --end_date need to fetch the data count based on the end_date column and check Tuesday week day.
GROUP BY stages
)
SELECT since_tuesday FROM a;
Expected Output if date is 12th April (Tuesday):
+--------------+
| since_tuesday |
+--------------+
| 1 |
+--------------+
Expected Output if date is 13th April:
+--------------+
| since_tuesday |
+--------------+
| 2 |
+--------------+
Expected Output if date is 14th April:
+--------------+
| since_tuesday |
+--------------+
| 3 |
+--------------+
Need to check if sysdate is tuesday, then from there need to populate the count.
Rather than using language/territory specific functions like TO_CHAR or NEXT_DAY, you can do it independently of language and territory using TRUNC(SYSDATE - 1, 'IW') + 1 to shift the date back one day and then truncate it to the start of the ISO week (which is always a Monday) and then shift the day forward one day back to Tuesday:
SELECT COUNT(*) since_tuesday
FROM rpt_tab
WHERE end_date >= TRUNC(SYSDATE - 1, 'IW') + 1
AND end_date < TRUNC(SYSDATE) + 1
GROUP BY stages
Which, for the sample data outputs:
SINCE_TUESDAY
1
db<>fiddle here
You can use the NEXT_DAY() function for this:
WITH rpt_tab AS
(
SELECT 11 as e_id,'Mumbai' as region,'STG_1' as stages, TO_DATE('12-04-22','DD-MM-YY') as end_date FROM dual UNION ALL
SELECT 12,'France','STG_1',TO_DATE('13-04-22','DD-MM-YY') FROM dual UNION ALL
SELECT 13,'France','STG_1',TO_DATE('14-04-22','DD-MM-YY') FROM dual
)
SELECT COUNT(*)
FROM rpt_tab
WHERE end_date BETWEEN TRUNC(NEXT_DAY(end_date),'TUESDAY') - 7) AND TRUNC(NEXT_DAY(end_date),'TUESDAY'))
AND end_date <= TRUNC(SYSDATE);
I'm tasked with pulling the data for the four recent quarters. If I was dealing with dates this would be easy, but I'm not sure how to do so when I have a quarters table that looks like this:
| quarter | year |
+---------+------+
| 1 | 2016 |
| 2 | 2016 |
| 3 | 2016 |
...
I know that I can get the current quarter by doing something like this:
SELECT *
FROM quarters
WHERE quarter = (EXTRACT(QUARTER FROM CURRENT_DATE))
AND year = (EXTRACT(YEAR FROM CURRENT_DATE));
However, I'm not sure the best way to get the four most recent quarters. I thought about getting this quarter from last year, and selecting everything since then, but I don't know how to do that with tuples like this. My expected results would be:
| quarter | year |
+---------+------+
| 1 | 2017 |
| 2 | 2017 |
| 3 | 2017 |
| 4 | 2017 |
Keep in mind they won't always be the same year - in Q12018 this will change.
I've built a SQLFiddle that can be used to tinker with this - http://sqlfiddle.com/#!17/0561a/1
Here is one method:
select quarter, year
from quarters
order by year desc, quarter desc
fetch first 4 rows only;
This assumes that the quarters table only has quarters with data in it (as your sample data suggests). If the table has future quarters as well, then you need to compare the values to the current date:
select quarter, year
from quarters
where year < extract(year from current_date) or
(year = extract(year from current_date) and
quarter <= extract(quarter from current_date)
)
order by year desc, quarter desc
fetch first 4 rows only;
For the case that there can be gaps, like 2/2017 missing, and one would then want to return only three quarters instead of four, one can turn years and quarters into consecutive numbers by multiplying the year by four and adding the quarters.
select *
from quarters
where year * 4 + quarter
between extract(year from current_date) * 4 + extract(quarter from current_date) - 3
and extract(year from current_date) * 4 + extract(quarter from current_date)
order by year desc, quarter desc;
I've written a stored procedure to get the week from a date, it also returns the date at the start of the week as well as the week number and year.
I'm aware of the 'WEEK' function, however this doesn't give me the date at the start of the week and I'm not aware of a function that does this given the week and year.
Question is:
How can I get the 'date' at the start of the week given the week number? Where the start of the week is passed in as a day index, 0 = Sunday, 1 = Monday etc.
My current function doesn't always work and if the first day of the week is Monday, then Sunday falls into the next week, not the end of the same week as I would like it to be.
I was digging around this for a bit too. But I stumbled on some mysql code that also worked. It basically subtracts days based on the day of the week. i.e. If the date is a Wed (4), you know the date was 1-4=-3 days ago.
How about this:
# with Sunday being the start of the week:
select convert(date_add(now(), interval(1-dayofweek(now())) day), date) as WeekStartDate
select convert(date_add(now(), interval(7-dayofweek(now())) day), date) as WeekEndDate
# with Monday being the start of the week:
select convert(date_add(now(), interval(2-dayofweek(now())) day), date) as WeekStartDate
select convert(date_add(now(), interval(8-dayofweek(now())) day), date) as WeekEndDate
Credit:
How do I get the first day of the week of a date in mysql?
Use Sequence engine. You can adapt the following example as needed:
MariaDB [_]> SHOW ENGINES\G
.
.
.
*************************** 3. row ***************************
Engine: SEQUENCE
Support: YES
Comment: Generated tables filled with sequential values
Transactions: YES
XA: NO
Savepoints: YES
.
.
.
MariaDB [_]> SET #`year` := 2016,
-> #`mode` := 1,
-> #`week` := 23;
Query OK, 0 rows affected (0.00 sec)
MariaDB [_]> SELECT
-> `der`.`date`,
-> `der`.`week`,
-> `der`.`year`
-> FROM (
-> SELECT
-> `der`.`date`,
-> WEEK(`der`.`date`, #`mode`) `week`,
-> YEAR(`der`.`date`) `year`
-> FROM (
-> SELECT
-> DATE_ADD(CONCAT(#`year`, '-01-01'), INTERVAL `s`.`seq` DAY) `date`
-> FROM
-> seq_0_to_365 `s`
-> ) `der`
-> ) `der`
-> WHERE
-> `der`.`week` = #`week` AND
-> `der`.`year` = #`year`;
+------------+------+------+
| date | week | year |
+------------+------+------+
| 2016-06-06 | 23 | 2016 |
| 2016-06-07 | 23 | 2016 |
| 2016-06-08 | 23 | 2016 |
| 2016-06-09 | 23 | 2016 |
| 2016-06-10 | 23 | 2016 |
| 2016-06-11 | 23 | 2016 |
| 2016-06-12 | 23 | 2016 |
+------------+------+------+
7 rows in set (0.01 sec)
Solved, I re-wrote the stored procedure:
exitProc:BEGIN
#--
# Procedure:
# weekFromDate
#
# Parameters:
# vcCompKey, the key associated with the company
# dtDate, the date to translate
# dtOutSOW, returned start of week date
# siOutWeek, returned week number
# siOutYear, returned year
#--
DECLARE siDIY SMALLINT; #Day in year
DECLARE siFDOW SMALLINT; #First day of week
DECLARE siGoBack SMALLINT; #Flag used to check for last year
DECLARE siRmonth SMALLINT; #Reference Month
DECLARE siRyear SMALLINT; #Reference Year
DECLARE dtSOY DATE; #Date of start of year
DECLARE vcFMDOY VARCHAR(12);#First month and day of year
DECLARE vcFDOW VARCHAR(12);#First day of the week
DECLARE vcDYSOW VARCHAR(80);#Days of week
#Get the first day of the week for the specified company
SET vcFDOW = vcGetParamValue(vcCompKey, 'Var:First day of week');
IF (vcFDOW IS NULL) THEN
#No entry found, abort!
LEAVE exitProc;
END IF;
#Get the first month and day of the year for the specified company
SET vcFMDOY = vcGetParamValue(vcCompKey, 'Var:First day of year');
IF (vcFMDOY IS NULL) THEN
#No entry found, abort!
LEAVE exitProc;
END IF;
#Set-up days of week
SET vcDYSOW = 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday';
#Get the first day of the week index base 1
SET siFDOW = FIND_IN_SET(LOWER(vcFDOW), LOWER(vcDYSOW)) - 1;
#Get the reference month and year
SET siRmonth = MONTH(dtDate);
SET siRyear = YEAR(dtDate);
SET dtSOY = DATE(CONCAT(siRyear, '/', vcFMDOY));
#Calculate the start of week date
SET dtOutSOW = DATE_SUB(dtDate, INTERVAL (DAYOFWEEK(dtDate) - siFDOW) DAY) + 1;
#Calculate the day in year
SET siDIY = DATEDIFF(dtOutSOW, dtSOY);
#Do we need to go back to the end of the previous year?
SET siGoBack = YEAR(dtDate) - YEAR(dtOutSOW);
IF siGoBack < 0 Or siDIY < 0 Or dtDate < dtOutSOW THEN
#Yes
IF YEAR(dtOutSOW) = YEAR(dtDate) THEN
SET dtOutSOW = DATE_SUB(dtOutSOW, INTERVAL 7 DAY);
END IF;
SET dtSOY = DATE(CONCAT(YEAR(dtOutSOW), '/', vcFMDOY));
SET siDIY = DATEDIFF(dtOutSOW, dtSOY);
END IF;
#Calculate the week no. and year
SET siOutWeek = (siDIY / 7) + 1;
SET siOutYear = YEAR(dtOutSOW);
END
This routine does make use of other tables in my database and allows for companies to have different start of years.
As a test, I will find the start of the current week, first note:
mysql> SELECT NOW(), WEEK(NOW());
+---------------------+-------------+
| NOW() | WEEK(NOW()) |
+---------------------+-------------+
| 2016-06-18 12:10:58 | 24 |
+---------------------+-------------+
Then this is the meat of the function:
mysql> SELECT '2016-01-01'
+ INTERVAL 7*24
- DAYOFWEEK('2016-01-01')
+ 1 DAY;
+----------------------------------------------------------------+
| '2016-01-01' + INTERVAL 7*24 - DAYOFWEEK('2016-01-01') + 1 DAY |
+----------------------------------------------------------------+
| 2016-06-12 |
+----------------------------------------------------------------+
'2016-01-01' is the beginning of the year in question.
24 is the WEEK() number.
+ 1 DAY is to compensate for start of week.
Something else needs to be done for handling your option of what day the week starts week.
Some correction for user1014010's answer. When week starts with Monday you'll receive date of next week for Sundays. There's my correction:
SELECT DATE(DATE_ADD(NOW(), INTERVAL -((5 + DAYOFWEEK(NOW())) % 7) DAY)) AS WeekStartDate
I had created a table long time ago using SQL that had Day, Month, Year, Weekday, Date, and Period (example: April 2016).
This is what my current table looks like:
| Period | Day | Month | Year | Weekday | Date |
|:-----------|-----|-------|------|---------|----------:|
| April 2016 | 21 | April |2016 |Thursday |2016-04-21 |
Now I am needing to add Week (it is week 1, 2,... of that current month).
This select statement gives the correct result:
SELECT datediff(week, dateadd(week, datediff(week, 0, dateadd(month, datediff(month, 0, GETDATE()), 0)), 0), GETDATE() - 1) + 1
This query returns
4
How do I insert a new column called Week into this existing table and have it find the current week number?
I believe that the existing table is using GETDATE() to calculate its values. Unfortunately I do not have my CREATE query anymore.
Any help is much appreciated!
First add a column for week using ALTER TABLE
ALTER TABLE TableName
ADD Week int
Then UPDATE the column with the week number:
UPDATE TableName
SET Week = DATEPART(day, DATEDIFF(day, 0, [Date])/7 * 7)/7 + 1
Note: This week number is based on the day number alone, not the days of the week (Monday, Tuesday) etc.