Blockquote
Copy/Paste data:
productNumber Account BuyDate SellDate RelevantYYYYMM
27530 8605148 11/5/15 7:03 PM 11/11/15 2:02 PM 201511
27530 8582063 10/14/15 7:17 PM 10/16/15 1:48 PM 201510
27530 8566748 9/30/15 6:51 PM 10/13/15 2:09 PM 201510
101167 8622268 11/27/15 7:50 PM 11/27/15 8:35 PM 201511
101167 8622267 11/27/15 8:49 AM 11/27/15 11:02 AM 201511
101167 8622265 11/26/15 8:47 AM 11/26/15 11:14 AM 201511
101167 8622272 11/25/15 7:43 PM 11/25/15 8:40 PM 201511
102432 8611407 11/12/15 5:41 PM 11/25/15 11:50 AM 201511
102432 8600664 11/2/15 12:04 AM 11/4/15 12:56 PM 201511
102432 8573179 10/5/15 2:03 PM 10/7/15 3:47 PM 201510
127819 8581822 10/14/15 7:49 PM 10/18/15 10:46 AM 201510
127819 8572308 10/2/15 4:38 PM 10/4/15 2:28 PM 201510
127819 8571220 10/2/15 9:34 AM 10/2/15 4:25 PM 201510
141105 8612529 11/16/15 7:45 AM 11/16/15 3:06 PM 201511
141105 8612460 11/14/15 10:04 AM 11/14/15 12:48 PM 201511
141105 8608738 11/10/15 12:53 PM 11/10/15 3:19 PM 201511
141105 8603007 11/3/15 5:28 PM 11/9/15 3:54 PM 201511
141105 8595018 10/28/15 7:23 PM 11/2/15 2:09 PM 201511
141105 8562238 10/22/15 8:40 AM 10/27/15 5:11 PM 201510
I need to get a count of ProductNumber group by RelevantYYYYMM (201512 means December 2015). However, the logic should be:
ProductNumber and its most recent BuyDate should be within that RelevantYYYYMM.
Previous BuyDate associated with the ProductNumber's latest BuyDate should be within 30 days range. Example: Most recent BuyDate for Product 27530 is 11/5/15. Previous BuyDate for product is 10/14/15, which is within 30 days from 11.5.15.
3rd BuyDate should be within 30 days range from 2nd BuyDate. Example: 2nd BuyDate for ProductNumber 27530 is 10/14/15 and 3rd BuyDate is 9/30/15, which is within 30 days range of 10/14/15.
This validation should be done for each ProductNumber and RelevantYYYYMM associated with that Number. Example: For RelevantYYYYMM 201510 (October 2015), ProductNumber 27530 should not show up in my count because Stpes 1-3 aren't met. Explanationn: The most recent date for the ProductNumber 27530 in 201510 (October 2015) is 10/14/2015. Previous BuyDate is 9/30/2015, which is within 30 days range of 10/14/2015. However, there isn't another BuyDate for that ProductNumber prior to 9/30/2015 that is within 30 days range. It fails to validate step 3 so it gets eliminated from the count.
code:
--get all products and assign YYYYMM
drop table #firstbuy
declare #StartDate as date = '01/01/2015'
declare #EndDate as date = '12/31/2015'
select ProductNumber, Account, BuyDate, SellDate,
CAST(DATEPART(yyyy, BuyDate) AS varchar(4))+
CAST(REPLICATE('0', 2-LEN(MONTH(BuyDate))) AS varchar(2)) +
CAST(DATEPART(MONTH, BuyDate) AS varchar(2)) AS RelevantYYYYMM
into #firstbuy
From products V
WHERE
V.BuyDate BETWEEN #StartDate AND #EndDate
--select * from #firstbuy
--Rank by BuyDate desc. Use ProductNumber and RelevantYYYYMM for partition by
drop table #firstbuypart2
select *
into #firstbuypart2
from (
select ProductNumber, Account, BuyDate, SellDate, RelevantYYYYMM,
ROW_NUMBER() OVER (PARTITION BY ProductNumber, RelevantYYYYMM ORDER BY BuyDate DESC) AS getcount1
from #firstbuy
) a
--select * from #firstbuypart2
--Grab records that has count = 1. This will give you most recent BuyDate per RelevantYYYYMM
drop table #firstbuypart3
select ProductNumber, BuyDate, SellDate, RelevantYYYYMM
into #firstbuypart3
from #firstbuypart2
where getcount1 = 1
Group BY ProductNumber, RelevantYYYYMM, BuyDate, SellDate,
order by ProductNumber
--select * from #firstbuypart3
--Not sure what logic to use to get only one specific row per ProductNumber and RelevantYYYYMM
drop table #firstbuypart4
select b.*, a.BuyDate as BuyDateA, a.SellDate as SellDateA,
CAST(DATEPART(yyyy, a.BuyDateA) AS varchar(4))+
CAST(REPLICATE('0', 2-LEN(MONTH(a.BuyDateA))) AS varchar(2)) +
CAST(DATEPART(MONTH, a.BuyDateA) AS varchar(2)) AS RelevantYYYYMM_A
into #firstdischargepart4
From products a
JOIN #firstbuypart3 b on a.ProductNumber = b.ProductNumber
WHERE
DATEDIFF(DAY,b.BuyDate,a.BuyDate) BETWEEN 0 AND 30
--select * from #firstbuypart4
I think this could be what you need:
ATTENTION_1: You should NOT use culture specific date time formats! Look here: https://stackoverflow.com/a/34275965/5089204
ATTENTION_2: Be aware of DateTime! BETWEEN #StartDate AND #EndDate will NOT include BuyDates from #EndDate, if there is a time!
SET LANGUAGE ENGLISH;
DECLARE #tbl TABLE(productNumber INT,Account INT,BuyDate DATETIME,SellDate DATETIME);
INSERT INTO #tbl VALUES
(27530,8605148,'11/5/15 7:03 PM','11/11/15 2:02 PM')
,(27530,8582063,'10/14/15 7:17 PM','10/16/15 1:48 PM')
,(27530,8566748,'9/30/15 6:51 PM','10/13/15 2:09 PM')
,(101167,8622268,'11/27/15 7:50 PM','11/27/15 8:35 PM')
,(101167,8622267,'11/27/15 8:49 AM','11/27/15 11:02 AM')
,(101167,8622265,'11/26/15 8:47 AM','11/26/15 11:14 AM')
,(101167,8622272,'11/25/15 7:43 PM','11/25/15 8:40 PM')
,(102432,8611407,'11/12/15 5:41 PM','11/25/15 11:50 AM')
,(102432,8600664,'11/2/15 12:04 AM','11/4/15 12:56 PM')
,(102432,8573179,'10/5/15 2:03 PM','10/7/15 3:47 PM')
,(127819,8581822,'10/14/15 7:49 PM','10/18/15 10:46 AM')
,(127819,8572308,'10/2/15 4:38 PM','10/4/15 2:28 PM')
,(127819,8571220,'10/2/15 9:34 AM','10/2/15 4:25 PM')
,(141105,8612529,'11/16/15 7:45 AM','11/16/15 3:06 PM')
,(141105,8612460,'11/14/15 10:04 AM','11/14/15 12:48 PM')
,(141105,8608738,'11/10/15 12:53 PM','11/10/15 3:19 PM')
,(141105,8603007,'11/3/15 5:28 PM','11/9/15 3:54 PM')
,(141105,8595018,'10/28/15 7:23 PM','11/2/15 2:09 PM')
,(141105,8562238,'10/22/15 8:40 AM','10/27/15 5:11 PM');
declare #StartDate as date = '01/01/2015';
declare #EndDate as date = '12/31/2015';
WITH Extended AS
(
SELECT ProductNumber
,Account
,BuyDate
,SellDate
,CAST(YEAR(BuyDate) AS VARCHAR(4))+ REPLACE(STR(MONTH(BuyDate),2),' ','0') AS RelevantYYYYMM
,ROW_NUMBER() OVER(PARTITION BY ProductNumber ORDER BY productNumber,BuyDate DESC) AS RowInx
,COUNT(BuyDate) OVER(PARTITION BY ProductNumber) AS CountBuyDates
FROM #tbl
WHERE BuyDate BETWEEN #StartDate AND #EndDate --ATTENTION!!! Be aware of DateTime! this will NOT include BuyDates from #EndDate, if there is a time!
)
,DayDiffs AS
(
SELECT *
,DATEDIFF(DAY,ext.BuyDate
,(SELECT innerExt.BuyDate FROM Extended AS innerExt WHERE innerExt.productNumber=ext.productNumber AND innerExt.RowInx=ext.RowInx-1)) AS IntervalRecentToSecond
,DATEDIFF(DAY,(SELECT innerExt.BuyDate FROM Extended AS innerExt WHERE innerExt.productNumber=ext.productNumber AND innerExt.RowInx=ext.RowInx-1)
,(SELECT innerExt.BuyDate FROM Extended AS innerExt WHERE innerExt.productNumber=ext.productNumber AND innerExt.RowInx=ext.RowInx-2)) AS IntervalSecondToThird
FROM Extended AS ext
WHERE ext.CountBuyDates>=3 --min three
AND ext.RowInx=3 --this is the relevant row
)
SELECT productNumber
,Account
,RelevantYYYYMM AS Relev
,IntervalRecentToSecond AS Diff1To2
,IntervalSecondToThird AS Diff2To3
FROM DayDiffs
The result would be:
productNumber Account Relev Diff1To2 Diff2To3
27530 8566748 201509 14 22
101167 8622265 201511 1 0
102432 8573179 201510 28 10
127819 8571220 201510 0 12
141105 8608738 201511 4 2
I must admit, that I did not really understand, how the grouping by your "RelevantYYYYMM" should work. But I think, you'll be able to fiddle this in your self... If not: just come back with a short explanation.
Related
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.
There are two different tables, just need to subtract price between same month with same year, if no data just show zero for that particular month and year .Now, it just subtracting with row by row irrespective of month and year.
Table 1 Table2
Price tran_date Price post_date
60 2018-01-01 30 2018-01-15
40 2018-02-08 30 2018-02-02
50 2018-12-28 30 2018-11-01
40 2019-03-01 10 2019-01-08
80 2019-04-11 60 2019-04-29
40 2019-10-01
Expected Answer:
Sum(price). Year
30 January 2018
10 February 2018
30 November 2018
50 December 2018
-10 January 2019
40 March 2019
20 April 2019.
40 October 2019
Actual Answer:
Sum(Price) Year
30 January 2018
10 February 2018
10 December 2018
30 March 2019
20 April 2019
-40 October 2019
SQL Query for table1
Select sum(price) from table1 where date(tran_date)
between ‘2018-01-01’ and ‘2019-12-31’
group by month(tran_date),year(tran_date)
SQL Query for table2
Select sum(price) from table2 where date(post_date)
between ‘2018-01-01’ and ‘2019-12-31’
group by month(post_date),year(post_date)
It’s should not subtract from 1st row of table1 with 1st row of table2,it should subtract with same month with same year. If there is no data just show zero for that particular month and year.
Please do help.Thanks in Advance.
seems you want the absolute difference, try add abs()
sample
select date_year, date_month,
abs(sum(price))
from ((select date_year, date_month, price from
(values (60, '2018', '01'),
(40, '2018', '02'),
(50, '2018', '12'),
(40, '2019', '03'),
(80, '2019', '04') ) table1 (price, date_year, date_month)
) union all
(select date_year, date_month, - price from (
values (30, '2018', '01'),
(30, '2018', '02'),
(30, '2018', '11'),
(10, '2019', '01'),
(60, '2019', '04'),
(40, '2019', '10')
) table2 (price, date_year, date_month)
)
) t
group by date_year, date_month
order by date_year, date_month
see the fiddle
https://www.db-fiddle.com/f/qVQYB2KXSTbJNEkSH1oGuG/0
Is this what you want?
select year(dte), month(dte),
greatest( sum(price), 0)
from ((select tran_date as dte, price from table1
) union all
(select post_date, - price from table2
)
) t
group by year(dte), month(dte);
It seems very strange to not subtract the values. I suspect you might just want:
select year(dte), month(dte),
sum(price)
from ((select tran_date as dte, price from table1
) union all
(select post_date, - price from table2
)
) t
group by year(dte), month(dte)
I have a payments table, Where I update the subscription renewal date and amount, now I have a query to select previous 13 months sum of amounts column, But how do I add zero if no payment data is available for any month in the selected last 13 months of record.
SELECT DATE_FORMAT(dtSubscriptionRenewalDate, "%b - %Y") AS month, SUM(intPaymentAmount) as usd13mon FROM `tbl_pi_payment` WHERE strCurrencyCode = 'USD' and dtSubscriptionRenewalDate <= NOW() and dtSubscriptionRenewalDate >= Date_add(Now(),interval - 13 month) GROUP BY DATE_FORMAT(dtSubscriptionRenewalDate, "%Y-%m")
month usd13mon
Oct - 2018 55
Dec - 2018 79
Jan - 2019 16
Feb - 2019 93
Mar - 2019 80
Apr - 2019 83
May - 2019 34
Jun - 2019 23
Jul - 2019 25
Aug - 2019 37
Sep - 2019 17
Oct - 2019 44
In the above-mentioned output the nov 2018 month is missing as there was data available in the table.
You may try introducing a calendar table which represents every month which you want to appear in your report:
SELECT
m.my,
COALESCE(SUM(t.intPaymentAmount), 0) AS usd13mon
FROM
(
SELECT 'Nov - 2018' AS my UNION ALL
SELECT 'Dec - 2018' UNION ALL
SELECT 'Jan - 2019' UNION ALL
...
SELECT 'Nov - 2019'
) m
LEFT JOIN tbl_pi_payment t
ON m.my = DATE_FORMAT(t.dtSubscriptionRenewalDate, '%b - %Y') AND
t.strCurrencyCode = 'USD' AND
t.dtSubscriptionRenewalDate BETWEEN NOW() AND DATE_ADD(NOW(), INTERVAL - 13 MONTH)
GROUP BY
m.my;
I have a simple table with bunch of applicants, where they have their Start Time, End Time and Date data. I want to figure out who is available for a specific date within a Time Range.
Table below shows where Start and End Date Columns tells us they are booked for that Date/Time .........
AppID StartTime EndTime Date
H12 8:00 13:00 12/1/2013
H12 14:00 16:00 12/1/2013
H12 19:00 21:00 12/1/2013
H14 17:00 18:00 12/1/2013
H13 14:00 16:00 12/1/2013
H13 11:00 15:00 12/2/2013
H15 8:00 13:00 12/2/2013
So in the Table above how can I write a Query that will say...Give me all the applications for 12/1/2013 which are NOT working between 17:00 - 18:00? So basically it should return H12 & H13 (Because its time slot for 17-18 pm is not available within table for 12/1/2013).
This query returns the apps ID which were not working at a time range on a specific date.
SELECT
[AppID] = FreeApps
FROM table_name t1
WHERE AppID NOT IN (-- Not in the set of apps that were busy at the time range
SELECT AppID
FROM table_name t2
WHERE ((StartTime >= '17:00' AND StartTime <= '18:00')
OR (EndTime >= '17:00' AND EndTime <= '18:00'))
AND Date = '12/1/2013'
AND t1.AppID=t2.AppID)
GROUP BY AppID
;WITH t1 as
(
SELECT DISTINCT AppID
FROM <table>
WHERE date = '20130112'
)
SELECT AppID
FROM t1
WHERE
NOT EXISTS
(SELECT * FROM <table> t2
WHERE t2.STARTTIME < '18:00'
AND t2.ENDTIME > '17:00'
AND t1.AppID = t2.AppID
AND t2.date = '20130112'
)
i have a table and the columns like
Start_date timestamp,
end_date timestamp,
id number,
cost number(10,2).
And the data which i inserted into the table 'll be like this
1,'2013-02-03 00:00:00','2013-02-03 00:00:00',75*0.06
1,'2013-02-04 00:00:00','2013-02-04 00:00:00',75*0.06
1,'2013-02-05 00:00:00','2013-02-05 00:00:00',75*0.06
1,'2013-02-06 00:00:00','2013-02-06 00:00:00',75*0.06
1,'2013-02-07 00:00:00','2013-02-07 00:00:00',75*0.06
1,'2013-02-08 00:00:00','2013-02-08 00:00:00',75*0.06
1,'2013-02-09 00:00:00','2013-02-09 00:00:00',75*0.06
and now i want to group the columns Start_date and end_date by Sunday to Saturday.
can you please help me on this.
Thanks in Advance.
This is the best I can offer you as your question is impossible to understand as well as that sample you provided. ISO week table for 2013:
SELECT start_date -- 1/1/2013 --
, TRUNC(start_date, 'iw') wk_starts
, TRUNC(start_date, 'iw') + 7 - 1/86400 wk_ends
, TO_NUMBER (TO_CHAR (start_date, 'IW')) ISO_wk#_iw
, TO_CHAR(start_date, 'DAY') wk_day
FROM
(
SELECT TRUNC(SYSDATE, 'YEAR')-1 + LEVEL AS start_date
FROM dual
CONNECT BY LEVEL <=
(
SELECT TRUNC(ADD_MONTHS (SYSDATE, 12), 'Y')-TRUNC(SYSDATE, 'Y') "Num of Days in 2013"
FROM dual
)
)
/
START_DATE WK_STARTS WK_ENDS ISO_WK# WK_DAY
----------------------------------------------------------------------
1/1/2013 12/31/2012 1/6/2013 11:59:59 PM 1 TUESDAY
1/2/2013 12/31/2012 1/6/2013 11:59:59 PM 1 WEDNESDAY
.....
1/7/2013 1/7/2013 1/13/2013 11:59:59 PM 2 MONDAY
1/8/2013 1/7/2013 1/13/2013 11:59:59 PM 2 TUESDAY
.....
You can add any other formats for your date and order by it I guess...