SQL Consecutive Date Cumulative Count - sql

I am doing some roster analysis and need to identify when an employee has worked for 5 or more consecutive days. In my table, I can extract data something like the below (note, there are lot more columns, this is just a cut down example):
Emp
Start
First_Entry
1234
23/06/2016
1
1234
24/06/2016
1
1234
24/06/2016
0
1234
25/06/2016
1
1234
26/06/2016
1
1234
27/06/2016
1
1234
28/06/2016
1
1234
29/06/2016
1
1234
29/06/2016
0
1234
30/06/2016
1
1234
2/07/2016
1
1234
3/07/2016
1
1234
3/07/2016
0
1234
4/07/2016
1
1234
4/07/2016
0
1234
5/07/2016
1
1234
6/07/2016
1
1234
9/07/2016
1
1234
10/07/2016
1
1234
11/07/2016
1
1234
12/07/2016
1
And what I am after is something like this:
Emp
Start
First_Entry
Consecutive_Days
Over_5
Status
1234
23/06/2016
1
1
0
Worked < 5
1234
24/06/2016
1
2
0
Worked < 5
1234
24/06/2016
0
2
0
Worked < 5
1234
25/06/2016
1
3
0
Worked < 5
1234
26/06/2016
1
4
0
Worked < 5
1234
27/06/2016
1
5
1
Worked >= 5
1234
28/06/2016
1
6
1
Worked >= 5
1234
29/06/2016
1
7
1
Worked >= 5
1234
29/06/2016
0
7
1
Worked >= 5
1234
30/06/2016
1
8
1
Worked >= 5
1234
02/07/2016
1
1
0
Worked < 5
1234
03/07/2016
1
2
0
Worked < 5
1234
03/07/2016
0
2
0
Worked < 5
1234
04/07/2016
1
3
0
Worked < 5
1234
04/07/2016
0
3
0
Worked < 5
1234
05/07/2016
1
4
0
Worked < 5
1234
06/07/2016
1
5
1
Worked >= 5
1234
09/07/2016
1
1
0
Worked < 5
1234
10/07/2016
1
2
0
Worked < 5
1234
11/07/2016
1
3
0
Worked < 5
1234
12/07/2016
1
4
0
Worked < 5
I'm really not sure how to go about getting the cumulative count for consecutive days, so any help you can give will be amazing

Probably someone would come up with a brilliant solution but this would do. Your problem looks like an "Gaps and Islands" problem. Finding islands of date ranges we can find out the rest easily. In the below SQL, #mindate is not a must, but makes it easier.
CREATE TABLE #temptable
(
[Emp] CHAR(4),
[startDate] DATE,
[First_Entry] BIT
);
INSERT INTO #temptable
(
[Emp],
[startDate],
[First_Entry]
)
VALUES
('1234', N'2016-06-23', 1),
('1234', N'2016-06-24', 1),
('1234', N'2016-06-24', 0),
('1234', N'2016-06-25', 1),
('1234', N'2016-06-26', 1),
('1234', N'2016-06-27', 1),
('1234', N'2016-06-28', 1),
('1234', N'2016-06-29', 1),
('1234', N'2016-06-29', 0),
('1234', N'2016-06-30', 1),
('1234', N'2016-07-02', 1),
('1234', N'2016-07-03', 1),
('1234', N'2016-07-03', 0),
('1234', N'2016-07-04', 1),
('1234', N'2016-07-04', 0),
('1234', N'2016-07-05', 1),
('1234', N'2016-07-06', 1),
('1234', N'2016-07-09', 1),
('1234', N'2016-07-10', 1),
('1234', N'2016-07-11', 1),
('1234', N'2016-07-12', 1);
DECLARE #minDate DATE;
SELECT #minDate = DATEADD(d, -1, MIN(startDate))
FROM #temptable;
WITH firstOnly
AS (SELECT *
FROM #temptable
WHERE First_Entry = 1),
grouper (emp, startDate, grp)
AS (SELECT Emp,
startDate,
DATEDIFF(d, #minDate, startDate) - ROW_NUMBER() OVER (PARTITION BY Emp ORDER BY startDate)
FROM firstOnly),
islands (emp, START, [end])
AS (SELECT emp,
MIN(startDate),
MAX(startDate)
FROM grouper
GROUP BY emp,
grp),
consecutives (emp, startDate, consecutive_days)
AS (SELECT f.Emp,
f.startDate,
-- i.START,
-- i.[end],
ROW_NUMBER() OVER (PARTITION BY f.Emp, i.START ORDER BY i.START)
FROM firstOnly f
INNER JOIN islands i
ON f.startDate
BETWEEN i.START AND i.[end])
SELECT t.Emp,
t.startDate,
t.First_Entry,
c.consecutive_days,
CAST(CASE
WHEN c.consecutive_days < 5 THEN
0
ELSE
1
END AS BIT) Over_5,
CASE
WHEN c.consecutive_days < 5 THEN
'Worked < 5'
ELSE
'Worked >= 5'
END [Status]
FROM consecutives c
INNER JOIN #temptable t
ON t.Emp = c.emp
AND t.startDate = c.startDate;
DROP TABLE #temptable;

This is a island and gap problem, You can try to use LAG window function to get the previous startDate row for each Emp, ten use SUM window function to calculate which days are continuous.
Finally, We can use CASE WHEN expression to judge whether the day is greater than 5.
;WITH CTE AS (
SELECT [Emp],
[startDate],
[First_Entry],
SUM(CASE WHEN DATEDIFF(dd,f_Dt,startDate) <= 1 THEN 0 ELSE 1 END) OVER(PARTITION BY Emp ORDER BY startDate) grp
FROM (
SELECT *,
LAG(startDate,1,startDate) OVER(PARTITION BY Emp ORDER BY startDate) f_Dt
FROM T
) t1
)
SELECT [Emp],
[startDate],
[First_Entry],
SUM(CASE WHEN First_Entry = 1 THEN 1 ELSE 0 END) OVER(PARTITION BY Emp,grp ORDER BY startDate) Consecutive_Days,
(CASE WHEN SUM(CASE WHEN First_Entry = 1 THEN 1 ELSE 0 END) OVER(PARTITION BY Emp,grp ORDER BY startDate) >= 5 THEN 1 ELSE 0 END) Over_5,
(CASE WHEN SUM(CASE WHEN First_Entry = 1 THEN 1 ELSE 0 END) OVER(PARTITION BY Emp,grp ORDER BY startDate) >= 5 THEN 'Worked >= 5' ELSE 'Worked < 5' END) Status
FROM CTE
sqlfiddle

Related

Sum over partition reset when running total is 0

I have a query that is taking transactions (buying and selling of items) to calculate the gain/loss when the running total resets back to 0.
The fiddle is here: https://www.db-fiddle.com/f/974UVvE6id2rEiBPR78CKx/0
The units of each item can be added and subtracted and each time they come back to 0 for a account and item combination we want to calculate the net result of those transactions.
You can see it working in the fiddle for the first few (when open = 0), however it fails if there are multiple transactions before getting to 0 (eg 1 increment, 2 separate decrements of units).
From this data:
INSERT INTO t
(account, item, units, price, created_at)
VALUES
(2, 'A', -1, '$120.00', '2022-09-23 17:33:07'),
(2, 'A', 1, '$110.00', '2022-09-23 17:34:31'),
(1, 'B', -1, '$70.00', '2022-09-23 17:38:31'),
(1, 'B', 1, '$50.00', '2022-09-23 17:36:31'),
(1, 'B', 2, '$50.00', '2022-09-23 17:40:31'),
(1, 'B', -1, '$60.00', '2022-09-23 17:41:31'),
(1, 'B', -1, '$70.00', '2022-09-23 17:42:31'),
(1, 'B', 1, '$50.00', '2022-09-23 17:35:31'),
(1, 'B', -1, '$60.00', '2022-09-23 17:33:31'),
(2, 'B', 1, '$70.00', '2022-09-23 17:43:31'),
(2, 'B', 1, '$75.00', '2022-09-23 17:45:31'),
(2, 'B', -2, '$80.00', '2022-09-23 17:46:31')
;
I need to produce this result (net is the relevant column which we cannot get right in the fiddle, it shows incorrect values for the last two net values):
account
item
units
price
created_at
open
cost
net
2
A
-1
$120.00
2022-09-23T17:33:07.000Z
-1
$120.00
1
B
-1
$60.00
2022-09-23T17:33:31.000Z
-1
$60.00
2
A
1
$110.00
2022-09-23T17:34:31.000Z
0
-$110.00
$10.00
1
B
1
$50.00
2022-09-23T17:35:31.000Z
0
-$50.00
$10.00
1
B
1
$50.00
2022-09-23T17:36:31.000Z
1
-$50.00
1
B
-1
$70.00
2022-09-23T17:38:31.000Z
0
$70.00
$20.00
1
B
2
$50.00
2022-09-23T17:40:31.000Z
2
-$100.00
1
B
-1
$60.00
2022-09-23T17:41:31.000Z
1
$60.00
1
B
-1
$70.00
2022-09-23T17:42:31.000Z
0
$70.00
$30.00
2
B
1
$70.00
2022-09-23T17:43:31.000Z
1
-$70.00
2
B
1
$75.00
2022-09-23T17:45:31.000Z
2
-$75.00
2
B
-2
$80.00
2022-09-23T17:46:31.000Z
0
$160.00
$15.00
View on DB Fiddle
We start by establishing cost and every time the running total is 0. By using lag and count we make groups out of every run that leads to zero divided by account and item. We use the groups we just created and find the running total of cost, but only display the result when our original running_total = 0.
select account
,item
,units
,price
,created_at
,running_total as open
,cost
,case running_total when 0 then sum(cost) over(partition by account, item, grp order by created_at) end as net
from
(
select *
,count(mark_0) over(partition by account, item order by created_at) as grp
from (
select *
,case when lag(running_total) over(partition by account, item order by created_at) = 0 then 1 when lag(running_total) over(partition by account, item order by created_at) is null then 1 end as mark_0
from (
select *
,sum(units) over(partition by account, item order by created_at) as running_total
,price*units*-1 as cost
from t
) t
) t
) t
order by created_at
account
item
units
price
created_at
open
cost
net
2
A
-1
120.00
2022-09-23 17:33:07+01
-1
120.00
null
1
B
-1
60.00
2022-09-23 17:33:31+01
-1
60.00
null
2
A
1
110.00
2022-09-23 17:34:31+01
0
-110.00
10.00
1
B
1
50.00
2022-09-23 17:35:31+01
0
-50.00
10.00
1
B
1
50.00
2022-09-23 17:36:31+01
1
-50.00
null
1
B
-1
70.00
2022-09-23 17:38:31+01
0
70.00
20.00
1
B
2
50.00
2022-09-23 17:40:31+01
2
-100.00
null
1
B
-1
60.00
2022-09-23 17:41:31+01
1
60.00
null
1
B
-1
70.00
2022-09-23 17:42:31+01
0
70.00
30.00
2
B
1
70.00
2022-09-23 17:43:31+01
1
-70.00
null
2
B
1
75.00
2022-09-23 17:45:31+01
2
-75.00
null
2
B
-2
80.00
2022-09-23 17:46:31+01
0
160.00
15.00
Fiddle
You can use a recursive cte, building up the results row by row, using a JSON object to store running open and cost values for every unique item:
with recursive transactions as (
select row_number() over (order by t1.created_at) id, t1.* from t t1
order by t1.created_at
),
cte(id, account, item, unit, price, created_at, open, cost, net, p) as (
select t.*, t.unit, -1*t.price*t.unit, 0, (select jsonb_object_agg(t1.item,
jsonb_build_object('u', 0, 'c', 0)) from transactions t1)||jsonb_build_object(t.item,
jsonb_build_object('u', t.unit, 'c', -1*t.price*t.unit))
from transactions t where t.id = 1
union all
select t.*, (c.p -> t.item -> 'u')::int + t.unit, -1*t.price*t.unit,
case when (c.p -> t.item -> 'u')::int + t.unit = 0
then (c.p -> t.item -> 'c')::int + -1*t.price*t.unit else 0 end,
c.p || jsonb_build_object(t.item, jsonb_build_object('u', (c.p -> t.item -> 'u')::int + t.unit, 'c',
case when (c.p -> t.item -> 'u')::int + t.unit = 0 then 0
else (c.p -> t.item -> 'c')::int + -1*t.price*t.unit end))
from cte c join transactions t on t.id = c.id + 1
)
select account, item, unit, price, created_at,
open, cost, case when net > 0 then net end
from cte;

How to get conditional sequence

I have a question about sequence function in SQL Server.
First, I created a base table. Here is my code.
CREATE TABLE TEST2(
SEQ int IDENTITY (1, 1) NOT NULL,
Dates date,
CNT int,
)
INSERT INTO TEST2 (Dates, CNT)
VALUES
('2020-01-01', 0),
('2020-01-02', 0),
('2020-01-03', 0),
('2020-01-04', 1),
('2020-01-05', 0),
('2020-01-06', 1),
('2020-01-07', 0),
('2020-01-08', 0),
('2020-01-09', 0),
('2020-01-10', 0),
('2020-01-11', 0),
('2020-01-09', 2),
('2020-01-10', 0),
('2020-01-11', 0)
Here my attempt code.
CASE WHEN CNT != 0
THEN 0
ELSE CNT = 0
THEN (ROW_NUMBER() OVER(ORDER BY Dates))
END NEW_SEQ
It consists of two columns(Dates, CNT).
And I want to get the following result using the WHEN CASE expressions.
Here is my example results.
SEQ
Dates
CNT
NEW_SEQ
1
2020-01-01
0
0
2
2020-01-02
0
2
3
2020-01-03
0
3
4
2020-01-04
1
0
5
2020-01-05
0
1
6
2020-01-06
1
0
7
2020-01-07
0
1
8
2020-01-08
0
2
9
2020-01-09
0
3
10
2020-01-10
0
4
11
2020-01-11
0
5
12
2020-01-09
2
0
13
2020-01-10
0
1
14
2020-01-11
0
2
I want to get like this using CASE WHEN Method.
Please check my issue. Thank you.
You can use analytical function as follows:
select t.Dates, t.CNT,
row_number() over (partition by sm order by seq) - 1 as NEW_SEQ
from
(select t.*,
sum(case when cnt = 0 then 0 else 1 end) over (order by seq) as sm
from test t) t

Create a lapsed concept based on logic across every row per ID

I am trying to get to a lapsed_date which is when there are >12 weeks (ie. 84 days) for a given ID between:
1) onboarded_at and current_date (if no applied_at exists) - this means lapsed_now if >84 days
2) onboarded_at and min(applied_at) (if one exists)
3) each consecutive applied_at
4) max(applied_at) and current_date - this means lapsed_now if >84 days
If there are multiple instances where he lapsed, then we only show the latest lapsed date.
The attempt I have works for most but not all cases. Can you assists make it work universally?
Sample set:
CREATE TABLE #t
(
id VARCHAR(10),
rank INTEGER,
onboarded_at DATE,
applied_at DATE
);
INSERT INTO #t VALUES
('A',1,'20180101','20180402'),
('A',2,'20180101','20180403'),
('A',3,'20180101','20180504'),
('B',1,'20180201','20180801'),
('C',1,'20180301','20180401'),
('C',2,'20180301','20180501'),
('C',3,'20180301','20180901'),
('D',1,'20180401',null)
Best attempt:
SELECT onb.id,
onb.rank,
onb.onboarded_at,
onb.applied_at,
onb.lapsed_now,
CASE WHEN lapsed_now = 1 OR lapsed_previous = 1
THEN 1
ELSE 0
END lapsed_ever,
CASE WHEN lapsed_now = 1
THEN DATEADD(DAY, 84, lapsed_now_date)
ELSE min_applied_at_add_84
END lapsed_date
FROM
(SELECT *,
CASE
WHEN DATEDIFF(DAY, onboarded_at, MIN(ISNULL(applied_at, onboarded_at)) over (PARTITION BY id)) >= 84
THEN 1
WHEN DATEDIFF(DAY, MAX(applied_at) OVER (PARTITION BY id), GETDATE()) >= 84
THEN 1
ELSE 0
END lapsed_now,
CASE
WHEN MAX(DATEDIFF(DAY, onboarded_at, ISNULL(applied_at, GETDATE()))) OVER (PARTITION BY id) >= 84
THEN 1
ELSE 0
END lapsed_previous,
MAX(applied_at) OVER (PARTITION BY id) lapsed_now_date,
DATEADD(DAY, 84, MIN(CASE WHEN applied_at IS NULL THEN onboarded_at ELSE applied_at END) OVER (PARTITION BY id)) min_applied_at_add_84
FROM #t
) onb
Current solution:
id rank onboarded_at applied_at lapsed_now lapsed_ever lapsed_date
A 1 2018-01-01 2018-04-02 1 1 2018-07-27
A 2 2018-01-01 2018-04-03 1 1 2018-07-27
A 3 2018-01-01 2018-05-04 1 1 2018-07-27
B 2 2018-02-01 2018-08-01 1 1 2018-10-24
C 1 2018-03-01 2018-04-01 0 1 2018-06-24
C 2 2018-03-01 2018-05-01 0 1 2018-06-24
C 3 2018-03-01 2018-09-01 0 1 2018-06-24
D 1 2018-04-01 null 1 1 2018-06-24
Expected solution:
id rank onboarded_at applied_at lapsed_now lapsed_ever lapsed_date
A 1 2018-01-01 2018-04-02 1 1 2018-07-27 (not max lapsed date)
A 2 2018-01-01 2018-04-03 1 1 2018-07-27
A 3 2018-01-01 2018-05-04 1 1 2018-07-27 (May 4 + 84)
B 1 2018-02-01 2018-08-01 0 1 2018-04-26 (Feb 1 + 84)
C 1 2018-03-01 2018-04-01 0 1 2018-07-24
C 2 2018-03-01 2018-05-01 0 1 2018-07-24 (May 1 + 84)
C 3 2018-03-01 2018-09-01 0 1 2018-07-24
D 1 2018-04-01 null 1 1 2018-06-24
Bit of guesswork here, but hopefully this does the trick:
SELECT res.id,
res.rank,
res.onboarded_at,
res.applied_at,
res.lapsed_now,
CASE WHEN lapsed_now = 1 OR lapsed_previous = 1
THEN 1
ELSE 0
END lapsed_ever,
CASE
WHEN lapsed_now = 1
THEN DATEADD(DAY, 84, lapsed_now_date)
WHEN applied_difference_gt84 IS NOT NULL
THEN DATEADD(DAY, 84, applied_difference_gt84)
WHEN DATEDIFF(DAY, min_applied_at_add_84, GETDATE()) < 84
THEN DATEADD(DAY, 84, onboarded_at)
ELSE min_applied_at_add_84
END lapsed_date
FROM (
SELECT *, MAX(applied_difference) OVER (PARTITION BY id ORDER BY rank ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) applied_difference_gt84
FROM
(
SELECT *,
CASE
WHEN DATEDIFF(DAY, onboarded_at, MIN(ISNULL(applied_at, onboarded_at)) over (PARTITION BY id)) >= 84
AND DATEDIFF(DAY, MAX(applied_at) OVER (PARTITION BY id), GETDATE()) >= 84
THEN 1
WHEN DATEDIFF(DAY, ISNULL(MAX(applied_at) OVER (PARTITION BY id), onboarded_at), GETDATE()) >= 84
THEN 1
ELSE 0
END lapsed_now,
CASE
WHEN MAX(DATEDIFF(DAY, onboarded_at, ISNULL(applied_at, GETDATE()))) OVER (PARTITION BY id) >= 84
THEN 1
ELSE 0
END lapsed_previous,
CASE
WHEN DATEDIFF(MONTH, applied_at, LEAD(applied_at, 1) OVER (PARTITION BY id ORDER BY rank)) >= 2
THEN applied_at
ELSE NULL
END applied_difference,
ISNULL(MAX(applied_at) OVER (PARTITION BY id), onboarded_at) lapsed_now_date,
DATEADD(DAY, 84, MIN(CASE WHEN applied_at IS NULL THEN onboarded_at ELSE applied_at END) OVER (PARTITION BY id)) min_applied_at_add_84
FROM #t
) onb
) res
Results:
id rank onboarded_at applied_at lapsed_now lapsed_ever lapsed_date
A 1 2018-01-01 2018-04-02 1 1 2018-07-27
A 2 2018-01-01 2018-04-03 1 1 2018-07-27
A 3 2018-01-01 2018-05-04 1 1 2018-07-27
B 1 2018-02-01 2018-08-01 0 1 2018-04-26
C 1 2018-03-01 2018-04-01 0 1 2018-07-24
C 2 2018-03-01 2018-05-01 0 1 2018-07-24
C 3 2018-03-01 2018-09-01 0 1 2018-07-24
D 1 2018-04-01 (null) 1 1 2018-06-24
It's a bit messy because of the need to calculate the difference between the applied_at dates.
#Jim, inspired by your answer, I created the following solution.
I think it is easily understandable and intuitive, knowing the lapsed criteria:
SELECT id, onboarded_at, applied_at,
max(case when (zero_applicants is not null and current_date - onboarded_at > 84) or (last_applicant is not null and current_date - last_applicant > 84) then 1 else 0 end) over (partition by id) lapsed_now,
max(case when (zero_applicants is not null and current_date - onboarded_at > 84) or (one_applicant is not null and applied_at - onboarded_at > 84)
or (one_applicant is not null and current_date - applied_at > 84) or (next_applicant is not null and next_applicant- applied_at > 84)
or (last_applicant is not null and current_date - last_applicant > 84) then 1 else 0 end) over(partition by id) lapsed_ever,
max(case when zero_applicants is not null and current_date - onboarded_at > 84 then onboarded_at + 84
when one_applicant is not null and applied_at - onboarded_at > 84 then onboarded_at + 84
when one_applicant is not null and current_date - applied_at > 84 then applied_at + 84
when next_applicant is not null and next_applicant - applied_at > 84 then applied_at + 84
when last_applicant is not null and current_date - last_applicant > 84 then last_applicant + 84
end) over (partition by id) lapsed_date
from (
select *,
case when MAX(applied_at) OVER (PARTITION BY id) is null then onboarded_at end as zero_applicants,
case when count(applied_at) over(partition by id)=1 then onboarded_at end as one_applicant,
case when count(applied_at) over(partition by id)>1 then LEAD(applied_at, 1) OVER (PARTITION BY id ORDER BY applied_at) end as next_applicant,
case when LEAD(applied_at, 1) OVER (PARTITION BY id ORDER BY applied_at) is null then MAX(applied_at) over(partition by id) end as last_applicant
from #t
) res
order by id, applied_at

SQL calculation based on another column

I am extracting data out of SQL database and need to calculate the opening balance of a stock item per project. I am getting the opening balance for the stock inclusive of all the projects.
item code | Project | Qty In | Qty Out
----------+---------+--------+---------
1234 1 0 90
1234 1 90 0
1234 2 431 0
1234 2 0 22
1234 3 925 0
1234 3 0 925
1234 3 925 0
1234 3 0 20
1234 3 0 40
1234 3 0 30
1234 3 0 40
1234 3 0 60
1234 3 0 50
1234 3 0 24
1234 3 0 40
1234 3 0 30
1234 3 0 17
1234 3 0 80
1234 3 0 30
1234 4 16 0
1234 4 0 16
1234 5 22 0
1234 5 0 23
Query:
select OpeningBalanceQty = Qty_On_Hand +
(select case when ServiceItem = 0
then IsNull(sum (QtyOut), 0)
else 0
end
from table1
where AccountLink=StockLink and txdate>='2016-06-01' and project ='2' ) -
(select case when ServiceItem = 0
then IsNull(sum (QtyIn), 0)
else 0
end from table1
where AccountLink=StockLink and txdate>='2016-06-01' and project ='2')
from tablel join table2 on table1.AccountLink = table2.StockLink
I have used project 2 as an example, it has two transactions(qty in:431)& (qty out:22)
My opening balance should be 409 but it is giving the total for the product item
My full code:
select Table1.TxDate,Table2.Pack,Table1.Reference,
OpeningBalanceQty= (select case when ServiceItem = 0 then IsNull(sum
(QtyOut), 0) else 0 end from Table1 where AccountLink=StockLink and
ProjectCode in('2') ) - (select case when ServiceItem = 0 then IsNull(sum
(QtyIn), 0) else 0 end from Table1 where AccountLink=StockLink and
ProjectCode in('2'))
,ProjectCode,ProjectDescription, Code, Description_1, Sum(ActualQuantity)*-1
as [Qty Processed],Sum(Debit)-Sum(Credit) as [Value],Trcode
from Table1
join Table2
on Table1 .AccountLink = Table2.StockLink
where ServiceItem = 0 and txdate>='2017-06-01 00:00:00' and txdate<='2017-
06-30 00:00:00' and Code='1234'
Group by Description_1, Code,ProjectCode, ProjectDescription, stocklink,
serviceitem,Qty_On_Hand,Table1.Reference,Table2.Pack,Table1.TxDate,trcode
Do you think this could be helpful for you?
SELECT PROJECT, SUM( QTYIN-QTYOUT) AS OPEN_BAL_QTY
FROM yourtable
WHERE txdate>='2016-06-01'
GROUP BY PROJECT
Output:
PROJECT OPEN_BAL_QTY
1 0
2 409
3 464
4 0
5 -1
1° update: after your new information (pls, next time, try to give all the information in your initial post, and well formatted: see tour of stackoverflow to learn how to do).
If you are using MSSQL 2005 or later, you can try this:
SELECT TABLE1.TXDATE
,TABLE2.PACK
,TABLE1.REFERENCE
, SUM(QTYIN-QTYOUT) OVER (PARTITION BY TABLE1.PROJECTCODE) AS OPEN_BAL_QTY
,PROJECTCODE
,PROJECTDESCRIPTION
,CODE
,DESCRIPTION_1
,-SUM(ACTUALQUANTITY) AS QTY PROCESSED
, SUM(DEBIT) - SUM(CREDIT) AS VALUE
,TRCODE
FROM TABLE1
JOIN TABLE2 ON TABLE1.ACCOUNTLINK = TABLE2.STOCKLINK
WHERE SERVICEITEM = 0
AND TXDATE >= '2017-06-01 00:00:00'
AND TXDATE <= '2017-06-30 00:00:00'
AND CODE = '1234'
GROUP BY DESCRIPTION_1
,CODE
,PROJECTCODE
,PROJECTDESCRIPTION
,STOCKLINK
,SERVICEITEM
,QTY_ON_HAND
,TABLE1.REFERENCE
,TABLE2.PACK
,TABLE1.TXDATE
,TRCODE
2° update
If it doesn't work for you, you should try:
SELECT A.*
,B.OPEN_BAL_QTY
FROM
SELECT TABLE1.TXDATE
,TABLE2.PACK
,TABLE1.REFERENCE
,PROJECTCODE
,PROJECTDESCRIPTION
,CODE
,DESCRIPTION_1
,-SUM(ACTUALQUANTITY) AS QTY PROCESSED
, SUM(DEBIT) - SUM(CREDIT) AS VALUE
,TRCODE
FROM TABLE1
JOIN TABLE2 ON TABLE1.ACCOUNTLINK = TABLE2.STOCKLINK
WHERE SERVICEITEM = 0
AND TXDATE >= '2017-06-01 00:00:00'
AND TXDATE <= '2017-06-30 00:00:00'
AND CODE = '1234'
GROUP BY DESCRIPTION_1
,CODE
,PROJECTCODE
,PROJECTDESCRIPTION
,STOCKLINK
,SERVICEITEM
,QTY_ON_HAND
,TABLE1.REFERENCE
,TABLE2.PACK
,TABLE1.TXDATE
,TRCODE
) A
LEFT JOIN (SELECT PROJECTCODE, SUM( QTYIN-QTYOUT) AS OPEN_BAL_QTY
FROM TABLE1
WHERE TXDATE>='2017-06-01'
AND TXDATE <= '2017-06-30 00:00:00'
GROUP BY PROJECT) B ON A.PROJECT_CODE = B.PROJECT_CODE

Fetch data in MS SQL 2008

I have three tables which are like:
table1
id,
created_Date
table2
id
district_ID
status_ID
table3
district_ID
district_Name
Now i need the records in following format
Srno District_name <10 days >10 and <20 days >20 days
1 xxx 12 15 20
2 yyy 8 0 2
count days as per current date
for example: if the created date is 10-08-2013 and current date is 13-08-2013 the date difference will be 3
So what should my query be? Any suggestions will be appreciated.
Thank you
table1
id created_Date
1 2013-07-12 13:32:10.957
2 2013-07-12 13:32:10.957
3 2013-08-01 10:00:10.957
4 2013-08-10 13:32:10.957
5 2013-08-10 14:32:10.957
table2
id district_ID status_id
1 1 3
2 2 3
3 2 7
4 3 4
5 4 3
table1
district_ID district_Name
1 xxx
2 yyy
3 zzz
4 aaa
5 bbb
I would have a look at using DATEDIFF and CASE.
DATEDIFF (Transact-SQL)
Returns the count (signed integer) of the specified datepart
boundaries crossed between the specified startdate and enddate.
Something like
SELECT District_name,
SUM(
CASE
WHEN DATEDIFF(day,created_Date, getdate()) < 10
THEN 1
ELSE 0
END
) [<10 days],
SUM(
CASE
WHEN DATEDIFF(day,created_Date, getdate()) >= 10 AND DATEDIFF(day,created_Date, getdate()) < 20
THEN 1
ELSE 0
END
) [>10 and <20 days],
SUM(
CASE
WHEN DATEDIFF(day,created_Date, getdate()) >= 20
THEN 1
ELSE 0
END
) [>20 days]
FROM Your_Tables_Here
GROUP BY District_name
;with cte as (
select t3.district_Name, datediff(day, t1.created_Date, getdate()) as diff
from table1 as t1 as t1
inner join table2 as t2 on t2.id = t1.id
inner join table3 as t3 on t3.district_id = t2.district_id
)
select
district_Name,
sum(case when diff < 10 then 1 else 0 end) as [<10 days],
sum(case when diff >= 10 and diff < 20 then 1 else 0 end) as [>=10 and < 20 days],
sum(case when diff >= 20 then 1 else 0 end) as [>= 20 days]
from cte
group by district_Name