SQL Rollup last 4 weeks total - sql

I have a table which I want to get the previous four weeks Order total in a query. But I want to return it with a SELECT (A total of the row's previous 4 weeks Order1 column - if they exist)
PurchasingID Order1 Date FourWeekTotal
------------ ------------------- ------- ---------------
1 1.00 2013-04-21 14.00
2 2.00 2013-04-14 12.00
3 3.00 2013-04-07 9.00
4 4.00 2013-03-31 5.00
5 5.00 2013-03-24 0.00

My understanding is for each record in your table, you want to see the sum of Order1 for itself and each record that has a Date value within four weeks prior to the primary record. Here you go:
create table MysteryTable
(
PurchasingId int not null primary key identity(1,1),
Order1 money not null,
[Date] date not null
)
insert MysteryTable( Order1, [Date] ) values ( 1.00, '2013-04-21' )
insert MysteryTable( Order1, [Date] ) values ( 2.00, '2013-04-14' )
insert MysteryTable( Order1, [Date] ) values ( 3.00, '2013-04-07' )
insert MysteryTable( Order1, [Date] ) values ( 4.00, '2013-03-31' )
insert MysteryTable( Order1, [Date] ) values ( 5.00, '2013-03-24' )
select
t1.PurchasingId
, t1.Order1
, t1.Date
, SUM( ISNULL( t2.Order1, 0 ) ) FourWeekTotal
from
MysteryTable t1
left outer join MysteryTable t2
on DATEADD( ww, -4, t1.Date ) <= t2.Date and t1.Date > t2.Date
group by
t1.PurchasingId
, t1.Order1
, t1.Date
order by
t1.Date desc
Explanation:
Join the table on itself, t1 representing the records to return, t2 to be the records to aggregate. Join based on t1's Date minus four weeks being less than or equal to t2's Date and t1's Date being greater than t2's Date. Then group the records by the t1 fields and sum t2.Order1. Left outer join is to account for the one record that will not have any preceding data.

Try this...
Declare #LBDate date
SET #LBDate = DATEADD(d,-28,getdate())
Now write ur select query...
Select * from Orders where Date between #LBDate and Getdate()
You can also use your required date instead to current date..

Related

How to retrieve default value even when do no exist record in database

Querying data as showed below there is no record on database for day 2021-10-03.
date
value
2021-10-01
100
2021-10-02
90
2021-10-04
10
2021-10-05
40
I would like to execute the query using date between as SELECT ... WHERE date BETWEEN '2021-10-01' AND '2021-10-05' and in case of do not exist data for a specific day, to retrieve zero as exemplified below:
date
value
2021-10-01
100
2021-10-02
90
2021-10-03
10
2021-10-04
10
2021-10-05
40
Is it possible? in bigQuery?
I tried the query below, but retrieved duplicated values.
WITH `project.myproject` AS (
SELECT
DATA_VENDA AS date,
CAST(SUM(VLR_VENDA_TABELA) AS FLOAT64) AS total,
FROM `project.myproject`
WHERE
(DATA_VENDA BETWEEN '2020-10-02'
AND '2020-10-07')
AND COD_CP = '0000010232'
GROUP BY
DATA_VENDA
ORDER BY
DATA_VENDA
),
dates AS (
SELECT total, date
FROM `project.myproject`, UNNEST(GENERATE_DATE_ARRAY(date('2020-10-02'), date('2020-10-07'))) AS date
)
SELECT d.date, IFNULL(t.total, 0) total
FROM dates d
LEFT JOIN `project.myproject` t
ON d.date = t.date
AND d.total = t.total
ORDER BY d.date
I found out the answers running command below. The difference from that to this is that in this new one I removed the line AND d.total = t.total, who was responsible for creating duplicated data. The final answer follow below:
WITH `project.myproject` AS (
SELECT
DATA_VENDA AS date,
CAST(SUM(VLR_VENDA_TABELA) AS FLOAT64) AS total,
FROM `project.myproject`
WHERE
(DATA_VENDA BETWEEN '2020-10-02'
AND '2020-10-07')
AND COD_CP = '0000010232'
GROUP BY
DATA_VENDA
ORDER BY
DATA_VENDA
),
dates AS (
SELECT total, date
FROM `project.myproject`, UNNEST(GENERATE_DATE_ARRAY(date('2020-10-02'), date('2020-10-07'))) AS date
)
SELECT d.date, IFNULL(t.total, 0) total
FROM dates d
LEFT JOIN `project.myproject` t
ON d.date = t.date
ORDER BY d.date
You can simply do that with the common table expression(CTE) as shown below.
DECLARE #Datatemp TABLE (
Id INT IDENTITY(1,1) NOT NULL,
CDate DATETIME,
Val INT
)
INSERT INTO #Datatemp SELECT '2021-10-01',10
INSERT INTO #Datatemp SELECT '2021-10-02',50
INSERT INTO #Datatemp SELECT '2021-10-04',24
INSERT INTO #Datatemp SELECT '2021-10-05',18
;WITH DateTemp(Date) AS (
SELECT CAST('2021-10-01' AS DATETIME)
UNION ALL
SELECT [Date]+1
FROM DateTemp
WHERE [Date] < '2021-10-05'
)
SELECT DateTemp.[Date] CDat
,ISNULL(t.Val, 0) Val
FROM DateTemp
LEFT JOIN #Datatemp t ON t.CDate = DateTemp.[Date]
ORDER BY DateTemp.[Date]
--OPTION (MAXRECURSION 0)
By default number of iterations for recursive CTE is 100. As long as this number is exceeded, the query will be interrupted and an error will be generated. If you want to remove this restriction, you can specify MAXRECURSION 0.

SQL find average time difference between rows for a given category

I browsed SO but could not quite find the exact answer or maybe it was for a different language.
Let's say I have a table, where each row is a record of a trade:
trade_id customer trade_date
1 A 2013-05-01 00:00:00
2 B 2013-05-01 10:00:00
3 A 2013-05-02 00:00:00
4 A 2013-05-05 00:00:00
5 B 2013-05-06 12:00:00
I would like to have the average time between trades, in days or fraction of days, for each customer, and the number of days since last trade. So for instance for customer A, time between trades 1 and 3 is 1 day and between trades 3 and 4 is 3 days, for an average of 2. So the end table would look like something like this (assuming today it's the 2013-05-10):
customer avg_time_btw_trades time_since_last_trade
A 2.0 5.0
B 5.08 3.5
If a customer has only got 1 trade I guess NULL is fine as output.
Not even sure SQL is the best way to do this (I am working with SQL server), but any help is appreciated!
SELECT
customer,
DATEDIFF(second, MIN(trade_date), MAX(trade_date)) / (NULLIF(COUNT(*), 1) - 1) / 86400.0,
DATEDIFF(second, MAX(trade_date), GETDATE() ) / 86400.0
FROM
yourTable
GROUP BY
customer
http://sqlfiddle.com/#!6/eb46e/7
EDIT: Added final field that I didn't notice, apologies.
The following SQL script uses your data and gives the expected results.
DECLARE #temp TABLE
( trade_id INT,
customer CHAR(1),
trade_date DATETIME );
INSERT INTO #temp VALUES (1, 'A', '20130501');
INSERT INTO #temp VALUES (2, 'B', '20130501 10:00');
INSERT INTO #temp VALUES (3, 'A', '20130502');
INSERT INTO #temp VALUES (4, 'A', '20130505');
INSERT INTO #temp VALUES (5, 'B', '20130506 12:00');
DECLARE #getdate DATETIME
-- SET #getdate = getdate();
SET #getdate = '20130510';
SELECT s.customer
, AVG(s.days_btw_trades) AS avg_time_between_trades
, CAST(DATEDIFF(hour, MAX(s.trade_date), #getdate) AS float)
/ 24.0 AS time_since_last_trade
FROM (
SELECT CAST(DATEDIFF(HOUR, t2.trade_date, t.trade_date) AS float)
/ 24.0 AS days_btw_trades
, t.customer
, t.trade_date
FROM #temp t
LEFT JOIN #temp t2 ON t2.customer = t.customer
AND t2.trade_date = ( SELECT MAX(t3.trade_date)
FROM #temp t3
WHERE t3.customer = t.customer
AND t3.trade_date < t.trade_date)
) s
GROUP BY s.customer
You need a date difference between every trade and average them.
select
a.customer
,avg(datediff(a.trade_date, b.trade_date))
,datediff(now(),max(a.trade_date))
from yourTable a, yourTable b
where a.customer = b.customer
and b.trade_date = (
select max(trade_date)
from yourTable c
where c.customer = a.customer
and a.trade_date > c.trade_date)
#gets the one earlier date for every trade
group by a.customer
Just for grins I added a solution that would use CTE's. You could probably use a temp table if the first query is too large. I used #MatBailie creation script for the table:
CREATE TABLE customer_trades (
id INT IDENTITY(1,1),
customer_id INT,
trade_date DATETIME,
PRIMARY KEY (id),
INDEX ix_user_trades (customer_id, trade_date)
)
INSERT INTO
customer_trades (
customer_id,
trade_date
)
VALUES
(1, '2013-05-01 00:00:00'),
(2, '2013-05-01 10:00:00'),
(1, '2013-05-02 00:00:00'),
(1, '2013-05-05 00:00:00'),
(2, '2013-05-06 12:00:00')
;
;WITH CTE as(
select customer_id, trade_date, datediff(hour,trade_date,ISNULL(LEAD(trade_date,1) over (partition by customer_id order by trade_date),GETDATE())) Trade_diff
from customer_trades
)
, CTE2 as
(SELECT customer_id, trade_diff, LAST_VALUE(trade_diff) OVER(Partition by customer_id order by trade_date) Curr_Trade from CTE)
SELECT Customer_id, AVG(trade_diff) AV, Max(Curr_Trade) Curr_Trade
FROM CTE2
GROUP BY customer_id

How to group value within a certain date range or every certain days in SQL server

For example table would be:
Customer OrderDate OrderAmt
-------- ---------- ---------
A1 20140101 920.00
A2 20140111 301.00
A2 20140123 530.00
A1 20140109 800.00
A3 20140110 500.00
A1 20140115 783.00
A3 20140217 500.00
A1 20140219 1650.00
A1 20140225 780.00
...
A3 20140901 637.00
I want to group them and calculate the sum(OrderAmt) within every 20 days and group by customer start from 20140101.
For what it's worth, you can accomplish what you describe with a pretty simple DATEDIFF() / GROUP BY operation, as below: whether or not that is actually what you want might be another question. I suspect that the DateBucket calculation might actually be something else ...
CREATE TABLE #tmpCustomer (Customer VARCHAR(2), OrderDate VARCHAR(10), OrderAmt DECIMAL(6,2))
INSERT INTO #tmpCustomer (Customer, OrderDate, OrderAmt)
SELECT 'A1',20140101, 920.00 UNION
SELECT 'A2',20140111, 301.00 UNION
SELECT 'A2',20140123, 530.00 UNION
SELECT 'A1',20140109, 800.00 UNION
SELECT 'A3',20140110, 500.00 UNION
SELECT 'A1',20140115, 783.00 UNION
SELECT 'A3',20140217, 500.00 UNION
SELECT 'A1',20140219, 1650.00 UNION
SELECT 'A1',20140225, 780.00 UNION
SELECT 'A3',20140901, 637.00
SELECT
Customer,
(DATEDIFF(day, '1/1/2014', CAST(OrderDate AS DATE)) / 20) + 1 AS DateBucket,
SUM(OrderAmt) SumOrderAmt
FROM #tmpCustomer
GROUP BY Customer, (DATEDIFF(day, '1/1/2014', CAST(OrderDate AS DATE)) / 20) + 1
ORDER BY Customer, DateBucket
You need to do two things:
(1) Create some sort of guide hold the '20 day groups' information. A Recursive CTE does this pretty well, and
(2) Recast that varchar date as an actual date for comparison purposes.
Then it's just joining the order data into that daterange grouping and summing the order amounts.
-------------------------
-- Here i'm just recreating your example
-------------------------
DECLARE #customerOrder TABLE (Customer varchar(2), OrderDate varchar(8), OrderAmt decimal(8,2))
INSERT INTO #customerOrder (Customer, OrderDate, OrderAmt)
VALUES
('A1', '20140101', 920.00),
('A2', '20140111', 301.00),
('A2', '20140123', 530.00),
('A1', '20140109', 800.00),
('A3', '20140110', 500.00),
('A1', '20140115', 783.00),
('A3', '20140217', 500.00),
('A1', '20140219', 1650.00),
('A1', '20140225', 780.00),
('A3', '20140901', 637.00)
-------------------------
-- Set up a table that lists off 20 day periods starting from 1/1/2014
-------------------------
DECLARE #startDate datetime, #endDate datetime;
SET #startDate = {d N'2014-01-01'};
SET #endDate = {d N'2014-12-31'};
WITH [dates] ([Sequence], [startDate], [maxExcludedDate]) AS
(SELECT 1 AS [Sequence]
,#startDate AS [startDate]
,DATEADD(d, 20, #startDate) AS [maxExcludedDate]
UNION ALL
SELECT Sequence + 1 AS Sequence
,DATEADD(d, 20, [startDate]) AS [startDate]
,DATEADD(d, 40, [startDate]) AS [maxExcludedDate]
FROM [dates]
WHERE [startDate] < #endDate
)
, dateFrame AS
(
SELECT
[startDate]
,[maxExcludedDate]
FROM [dates]
)
-------------------------
-- Set up a table that holds the orderDates as actual dates
-------------------------
, castData AS
(
SELECT
cast(orderdate as datetime) castDate
,OrderAmt
FROM #customerOrder
)
-------------------------
-- JOIN and sum.
-------------------------
SELECT
[startDate]
, Sum(OrderAmt) perodAmt
FROM
dateFrame df
left join castData cd
on cd.castDate >= df.startDate
and cd.castDate < df.maxExcludedDate
GROUP BY
[startDate]
ORDER by
[startDate]
Assuming that the OrderDate is a numeric field (not varchar). I'm also assuming that you don't need to go much more than a year in the future. If you want the gaps shown, keep the left join, if you don't want the gaps, then make it an inner join. (You can also make the hardcoded date a variable of where to start, I just kept it as the 20140101 that you mentioned.
with Numbers as
(Select 0 as Num
UNION ALL
Select Num+1
FROM Numbers
WHERE Num+1<= 20
)
, DateList AS
(Select Year(DateAdd(dd,20*(Num), Cast('2014-01-01' as date))) * 10000+Month(DateAdd(dd,20*(Num), Cast('2014-01-01' as date)))*100+Day(DateAdd(dd,20*(Num), Cast('2014-01-01' as date))) Groupingdatemin
, Year(DateAdd(dd,20*(Num+1)-1, Cast('2014-01-01' as date)))*10000+ MONTH(DateAdd(dd,20*(Num+1)-1, Cast('2014-01-01' as date)))*100+DAY(DateAdd(dd,20*(Num+1)-1, Cast('2014-01-01' as date))) Groupingdatemax
from Numbers
)
select Customer, sum(orderamt), Groupingdatemin, Groupingdatemax from DateLIst d LEFT JOIN
<yourtable> t on t.orderdate between d.Groupingdatemin and d.Groupingdatemax
group by customer, Groupingdatemin, Groupingdatemax

How to get date difference statistics by group with TSQL

I have a table with columns of product and sold date, and want to query the statistics of sold interval of each product group(max interval, min interval ...) , is there any good advice to make it, appreciate~
Prod SaleDate
-------------------
A 2013-02-05
D 2013-02-24
B 2013-03-01
A 2013-03-12
D 2013-03-22
A 2013-04-03
D 2013-04-08
. . .
Sold interval means days interval between two adjacent date.
Sold interval of A:
DATEDIFF(d, '2013-02-05', '2013-03-12')
DATEDIFF(d, '2013-03-12', '2013-04-03')
...
Sold interval of D:
DATEDIFF(d, '2013-02-24', '2013-03-22')
DATEDIFF(d, '2013-03-22', '2013-04-08')
and I want get the average, max and min value of sold interval.
Prod IntervalAvg IntervalMax IntervalMin
-----------------------------------------------------
A xxx xxx xxx
B xxx xxx xxx
C
. . .
Thanks Kahn's answer give me a hint. I re-implement my code for sql server 2000 by "left outer join".
DECLARE #DATA TABLE (Prod CHAR(1), SaleDate SMALLDATETIME)
INSERT INTO #DATA VALUES ('A','2013-02-05')
INSERT INTO #DATA VALUES ('D','2013-02-24')
INSERT INTO #DATA VALUES ('B','2013-03-01')
INSERT INTO #DATA VALUES ('A','2013-03-12')
INSERT INTO #DATA VALUES ('D','2013-03-22')
INSERT INTO #DATA VALUES ('A','2013-04-03')
INSERT INTO #DATA VALUES ('D','2013-04-08')
SELECT
t.Prod
, MAX(t.Interval) IntervalMax
, MIN(t.Interval) IntervalMin
, AVG(t.Interval) IntervalAvg
FROM
(
SELECT t1.*, DATEDIFF(dd, MAX(t2.SaleDate), t1.SaleDate) Interval
FROM #DATA t1
LEFT OUTER JOIN #DATA t2 ON t1.Prod = t2.Prod AND t1.SaleDate > t2.SaleDate
GROUP BY t1.Prod, t1.SaleDate
)t
GROUP BY t.Prod
ORDER BY t.Prod
Here's one way that should work:
-- Test data
DECLARE #DATA TABLE (Prod CHAR(1), SaleDate DATE)
INSERT INTO #DATA VALUES ('A','2013-02-05')
,('D','2013-02-24')
,('B','2013-03-01')
,('A','2013-03-12')
,('D','2013-03-22')
,('A','2013-04-03')
,('D','2013-04-08')
-- Actual query
;WITH CTE AS
(SELECT D.*, CA.NextSaleDate
, DATEDIFF(DD, SaleDate, NextSaleDate) DDiff
FROM #DATA D
OUTER APPLY (SELECT MIN(SaleDate) NextSaleDate FROM #DATA B WHERE B.Prod = D.Prod AND B.SaleDate > D.SaleDate) CA)
SELECT DISTINCT Prod, AvgInterval, MaxInterval, MinInterval
FROM CTE C
CROSS APPLY (SELECT AVG(DDiff) AvgInterval, MAX(DDiff) MaxInterval, MIN(DDiff) MinInterval FROM CTE B WHERE B.Prod = C.Prod) CA

Insert data into temp table, multiple columns from one Table

I have a table with columns: ID (Int), Date (Date) and Price (Decimal). Date column is in format 2013-04-14:
Table Example
ID Date Price
1 2012/05/02 23.5
1 2012/05/03 25.2
1 2012/05/04 22.5
1 2012/05/05 22.2
1 2012/05/06 26.5
2 2012/05/02 143.5
2 2012/05/03 145.2
2 2012/05/04 142.2
2 2012/05/05 146.5
3 2012/05/02 83.5
3 2012/05/03 85.2
3 2012/05/04 80.5
Query Example:
I want to be able to select all ID1 and ID3's data between a date range from the table and have this in a table with three columns, ordered by Date column. Also I would want to insert this into a temporary table to perform mathematical calculations on the data. Please comment if there is a better way.
Correct Result Example
Date ID1 ID3
2012-05-02 23.5 83.5
2012-05-03 25.2 85.2
2012-05-04 22.5 80.2
Any help and advice will be appreciated,
Thanks
Try the following.
CREATE TABLE #temp (
Date date,
x money,
y money
)
;
SELECT
Date,
MAX(CASE WHEN id=1 THEN price END) AS x,
MAX(CASE WHEN id=3 THEN price END) AS y
FROM Top40
WHERE Date BETWEEN '2012-05-02' AND '2012-05-04'
GROUP BY
Date
;
See SQL Fiddle for working example
EDIT:
To use the LAG window function on the x and y columns, you'll have to use a common table expression or CTE first.
WITH prices AS(
SELECT
Date as myDate,
MAX(CASE WHEN id=1 THEN price END) AS x,
MAX(CASE WHEN id=3 THEN price END) AS y
FROM Top40
WHERE Date BETWEEN '2012-05-02' AND '2012-05-04'
GROUP BY
Date
)
SELECT
myDate,
p.x,
(p.x/(LAG(p.x) OVER (ORDER BY MyDate))-1) as x_return,
p.y,
(p.y/(LAG(p.y) OVER (ORDER BY MyDate))-1) as y_return
FROM prices p
ORDER BY
myDate
;
See new SQL Fiddle for example.
The simplest way to do it in code (although it may not perform well with large data sets) is to do something like:
SELECT [Date], x = MAX(CASE WHEN ID = 1 THEN PRICE END)
, y = MAX(CASE WHEN ID = 3 THEN PRICE END)
INTO #tmp
FROM Top40
GROUP BY [Date]
Or...
select Date , t1.Price as Stock_1_Price , t2.Price as Stock_3_price
from ( select "Date" , max(Price) as Price from myData where ID = 1 group by "Date" ) t1
full join ( select "Date" , max(Price) as Price from myData where ID = 3 group by "Date" ) t2 on t2.Date = t1.Date
As far as populating a temp table, any of the usual ways works:
Table variable:
declare #work table
(
yyyymmdd varchar(32) not null ,
stock_1_price money null ,
stock_3_price money null
)
insert #work ( yyyymmdd , stock_1_price , stock_3_price )
select Date , t1.Price as Stock_1_Price , t2.Price as Stock_3_price
from ( select "Date" , max(Price) as Price from myData where ID = 1 group by "Date" ) t1
full join ( select "Date" , max(Price) as Price from myData where ID = 3 group by "Date" ) t2 on t2.Date = t1.Date
Declared temp table in tempdb
create table #work
(
yyyymmdd varchar(32) not null primary key clustered ,
stock_1_price money null ,
stock_3_price money null
)
insert #work ( yyyymmdd , stock_1_price , stock_3_price )
select Date , t1.Price as Stock_1_Price , t2.Price as Stock_3_price
from ( select "Date" , max(Price) as Price from myData where ID = 1 group by "Date" ) t1
full join ( select "Date" , max(Price) as Price from myData where ID = 3 group by "Date" ) t2 on t2.Date = t1.Date
non-declare temp table in tempdb via select into:
select Date , t1.Price as Stock_1_Price , t2.Price as Stock_3_price
into #work
from ( select "Date" , max(Price) as Price from myData where ID = 1 group by "Date" ) t1
full join ( select "Date" , max(Price) as Price from myData where ID = 3 group by "Date" ) t2 on t2.Date = t1.Date