SQL alternative to inner join - sql-server

I have a table which has data that appears as:
Staion Date Temperature
A 2015-07-31 8
B 2015-07-31 6
C 2015-07-31 8
A 2003-02-21 4
B 2003-02-21 7
C 2003-02-21 7
For each date I need to create arrays so that it has the following combination:
c1 = (A + B)/2, c2 = (A + B + C)/3 and c3 = (B + C)/2
Right I am doing three different inner join on the table itself and doing a final inner join to achieve the following as result:
Date c1 c2 c3
2015-07-31 7 7.33 7
2003-02-21 5.5 6 7
Is there a cleaner way to do this?

No need for a JOIN, you could simply use a GROUP BY and an aggregation function:
WITH CTE AS
(
SELECT [Date],
MIN(CASE WHEN Staion = 'A' THEN Temperature END) A,
MIN(CASE WHEN Staion = 'B' THEN Temperature END) B,
MIN(CASE WHEN Staion = 'C' THEN Temperature END) C
FROM dbo.YourTable
GROUP BY [date]
)
SELECT [Date],
(A+B)/2 c1,
(A+B+C)/3 c2,
(B+C)/2 c3
FROM CTE;

SUM Function is very useful in such cases:
SELECT
c1 = SUM(CASE WHEN Staion IN ('A', 'B') THEN Temperature ELSE 0 END) / 2,
c2 = SUM(Temperature) / 3,
c3 = SUM(CASE WHEN Staion IN ('B', 'C') THEN Temperature ELSE 0 END) / 2,
[Date]
FROM dbo.Table
GROUP BY [Date]

You can do it with just two joins and almost literally the formulas you've provided:
declare #t table (Station char(1) not null,[Date] date not null, Temperature int not null)
insert into #t(Station,[Date],Temperature) values
('A','20150731',8),
('B','20150731',6),
('C','20150731',8),
('A','20030221',4),
('B','20030221',7),
('C','20030221',7)
select
B.[Date],
c1 = (A.Temperature + B.Temperature)/2.0,
c2 = (A.Temperature + B.Temperature + C.Temperature)/3.0,
c3 = (B.Temperature + C.Temperature)/2.0
from
#t B
inner join
#t A
on
B.[Date] = A.[Date]
inner join
#t C
on
B.[Date] = C.[Date]
where
A.Station = 'A' and
B.Station = 'B' and
C.Station = 'C'
Result:
Date c1 c2 c3
---------- --------------- ----------- ----------
2015-07-31 7.000000 7.333333 7.000000
2003-02-21 5.500000 6.000000 7.000000

You can use pivot and calculation on pivoted data as below:
select [Date], c1 = (A+B)/2.0, c2 = (A+B+C)/3.0, C3 = (B+C)/2.0 from
( select * from #yourstation ) s
pivot (max(temparature) for station in ([A], [B], [C])) p
Your input table:
create table #yourStation (station char(1), date date, Temparature int)
insert into #yourStation (station, date, Temparature) values
('A','2015-07-31', 8 )
,('B','2015-07-31', 6 )
,('C','2015-07-31', 8 )
,('A','2003-02-21', 4 )
,('B','2003-02-21', 7 )
,('C','2003-02-21', 7 )

Related

SQL : Filter Column with row wise values

T-SQL:
Below is my table on which i need to apply row wise filter on a col.
my criteria is that the Val should be : 0 AND (1 OR 1.1) AND 2
The original table is
name val
aaa 0
aaa 1
aaa 1.1
aaa 2
bbb 0
bbb 2
ccc 0
ccc 1
ccc 2
The expected result will be
name val
aaa 0
aaa 1
aaa 1.1
aaa 2
ccc 0
ccc 1
ccc 2
Could anyone suggest a solution. I am trying the Where clause but i am not able to give the conditions within the where clause.
Appreciate any help
The following will return all rows from the group when the conditions are satisfied:
DECLARE #test TABLE(
name varchar(10) NOT NULL
, value varchar(10) NOT NULL
);
INSERT INTO #test(name, value)
VALUES
('aaa', '0')
,('aaa', '1')
,('aaa', '1.1')
,('aaa', '2')
,('bbb', '0')
,('bbb', '2')
,('ccc', '0')
,('ccc', '1')
,('ccc', '2');
SELECT a.name, a.value
FROM #test a
CROSS APPLY(SELECT COUNT(*) FROM #test b WHERE b.name = a.name AND value IN('0', '2')) AS b(cnt)
CROSS APPLY(SELECT COUNT(*) FROM #test b WHERE b.name = a.name AND value IN('1', '1.1')) AS c(cnt)
WHERE b.cnt = 2 AND c.cnt >= 1;
The 3 conditions are specified as a cte and join to your original table. The matching rows should be 3
; with
-- your table
tbl as
(
select name = 'aaa', val = 0 union all
select name = 'aaa ', val = 1 union all
select name = 'aaa', val = 1.1 union all
select name = 'aaa', val = 2 union all
select name = 'bbb', val = 0 union all
select name = 'bbb', val = 2 union all
select name = 'ccc', val = 0 union all
select name = 'ccc', val = 1 union all
select name = 'ccc', val = 2
),
-- your condition
val as
(
select val1 = 0, val2 = 0 union all
select val1 = 1, val2 = 1.1 union all
select val1 = 2, val2 = 2
),
cte_name as
(
select t.name
from tbl t
inner join val v on t.val = v.val1
or t.val = v.val2
group by name
having count(distinct v.val1) = 3 -- matching rows should be 3
)
-- the query
select t.*
from tbl t
inner join cte_name n on t.name = n.name
One other version:
DECLARE #test TABLE(
name varchar(10) NOT NULL
, value decimal(5,1) NOT NULL
);
INSERT INTO #test(name, value)
VALUES
('aaa', 0)
,('aaa', 1)
,('aaa', 1.1)
,('aaa', 2)
,('bbb', 0)
,('bbb', 2)
,('ccc', 0)
,('ccc', 1)
,('ccc', 2);
select a.name, a.value
from #test a
join (
select name,
sum(case when value IN(0,2) then 1 else 0 end) as c02,
sum(case when value IN(1,1.1) then 1 else 0 end) as c1
from #test group by name
) g on g.name=a.name and c02=2 and c1>=1

Recursive cte with values from 2 tables

I need some help with this please.
I would like to create a recursive query with values from a table for the anchor, multiplied by a coefficient from another table.
Let me be more explicit :
Tables structure and filling :
create table T
(
Site varchar(10) primary key,
Price money,
Year int
);
create table B
( Site varchar(10),
Coeff float,
Year int
);
insert into T values /* Each Site appears only once here */
('A', 125.10, 2003),
('B', 78.10, 2002),
('C', 23.34, 2001)
insert into B values /* Each (Site,Year) appears only once here */
('A', 12, 2003),
('A', 0.111, 2004),
('B', 0.322, 2002),
('B', 0.333, 2003),
('C', 0.555, 2001),
('C', 0.666, 2002)
My recursive formula is :
Price (n) = Price (n-1)* Coeff(n-1)
(where n is the year)
Here is my last attempt :
;WITH cte
AS (SELECT T.Site, T.Year, T.Price as RootPrice FROM T
UNION ALL
SELECT T.Site, T.Year, CAST(cte.RootPrice * B.Coeff AS MONEY) AS PriceYear
FROM T INNER JOIN cte ON T.Site = cte.Site AND T.Year = cte.Year INNER JOIN B ON cte.Year = B.Year AND cte.Site = B.Site)
SELECT * FROM cte
This cte is running endlessly. What am I missing ?
Edit :
Output needed :
Site | Price | Year
---------------------------
A | 1501.2 | 2003
A | 166.78 | 2004
B | 25.15 | 2002
B | 8.37 | 2003
C | 12.95 | 2001
C | 8.63 | 2002
This produces the output you want:
;WITH CTE AS
(
SELECT
Site = T.Site,
Year = T.Year,
Price = CONVERT(MONEY, T.Price * B.Coeff)
FROM
T AS T
INNER JOIN B AS B ON
T.Site = B.Site AND
T.Year = B.Year
UNION ALL
SELECT
Site = C.Site,
Year = C.Year + 1,
Price = CONVERT(MONEY, C.Price * B.Coeff)
FROM
CTE AS C
INNER JOIN B AS B ON
C.Site = B.Site AND
C.Year + 1 = B.Year
)
SELECT
*
FROM
CTE AS C
ORDER BY
C.Site,
C.Year
The problem with your solution is that the anchor doesn't start with the correct price, you should multiply the price with coeff on the anchor. Keep in mind that the anchor is the first set of the resulting CTE and it is included in it.
So your anchor:
SELECT
T.Site,
T.Year,
T.Price as RootPrice
FROM
T
Should start with the correct price for that year:
SELECT
Site = T.Site,
Year = T.Year,
Price = CONVERT(MONEY, T.Price * B.Coeff)
FROM
T AS T
INNER JOIN B AS B ON
T.Site = B.Site AND
T.Year = B.Year
And remove the T reference on the recursive set, since you don't need it anymore.
If you also want to see the root prices, you can tamper a little with the recursive join expression:
;WITH CTE AS
(
SELECT
Site = T.Site,
Year = T.Year,
Price = T.Price,
IsRoot = 1
FROM
#T AS T
UNION ALL
SELECT
Site = C.Site,
Year = CASE WHEN C.IsRoot = 1 THEN C.Year ELSE C.Year + 1 END,
Price = CONVERT(MONEY, C.Price * B.Coeff),
IsRoot = 0
FROM
CTE AS C
INNER JOIN #B AS B ON C.Site = B.Site
WHERE
(C.IsRoot = 1 AND C.Year = B.Year) OR
(C.IsRoot = 0 AND C.Year + 1 = B.Year)
)
SELECT
*
FROM
CTE AS C
ORDER BY
C.Site,
C.Year,
C.IsRoot DESC
/*
Results:
Site Year Price IsRoot
---------- ----------- --------------------- -----------
A 2003 125,10 1
A 2003 1501,20 0
A 2004 166,6332 0
B 2002 78,10 1
B 2002 25,1482 0
B 2003 8,3744 0
C 2001 23,34 1
C 2001 12,9537 0
C 2002 8,6272 0
*/

Getting a column based on a record

In the input table the values keep changing every week. So, the next week column E would be have A instead of F and at that point I would want the E field.
So, whichever field has A has to be selected but the field having A should be the last field in the table that has an A as a record.
Input Table:
A | B | C | D | E
A A A A F
12 32 43 23 2
Output :
D
A
23
I understand that your data is unnormalized for some reason if you need a logic to get the results you can use this code:
DECLARE #table TABLE (A varchar(3), B varchar(3),C varchar(3), D varchar(3), E varchar(3))
;WITH cte
AS (SELECT ColumnName
,ColumnValue
,Row_number()
OVER(
partition BY ColumnName
ORDER BY Rn) ResultOrder
FROM (SELECT Row_number() OVER (ORDER BY (SELECT NULL))Rn,a ,b ,c ,d ,e FROM #table) p
UNPIVOT ( ColumnValue
FOR ColumnName IN( a ,b ,c ,d ,e)) AS unpvt),
cte1
AS (SELECT Ntile(5)
OVER(
ORDER BY ColumnName) ColumnId
,*
FROM cte),
cte2
AS (SELECT DISTINCT Isnull(NULLIF(ColumnId - 1, 0), 5) ColumnId
,ColumnName
FROM cte1
WHERE ColumnValue = 'F')
SELECT result
FROM (SELECT CASE ColumnId
WHEN 1 THEN 'A'
WHEN 2 THEN 'B'
WHEN 3 THEN 'C'
WHEN 4 THEN 'D'
WHEN 5 THEN 'E'
END Result
,0 ResultOrder
FROM cte2
UNION
SELECT ColumnValue
,resultorder
FROM cte1 a
WHERE EXISTS (SELECT 1
FROM cte2 b
WHERE a.ColumnId = b.ColumnId)) AS R
ORDER BY resultorder
Result For
insert #table VALUES
('A','A','A','A','F')
,('12','32','43','23','2')
A B C D E
---- ---- ---- ---- ----
A A A A F
12 32 43 23 2
result
------
D
23
A
Result For
insert #table VALUES
('F','A','A','A','A')
,('12','32','43','23','2')
A B C D E
---- ---- ---- ---- ----
F A A A A
12 32 43 23 2
result
------
E
A
2
Explanation:
CTE table does the Unpivot the table and create a row number for order the column name and the value
CT1 table creates a group base on column name using the NTILE to create 5 groups
CTE2 table get the previous column where the value is equal F
The Select Is complex to translate the ColumnId to ColumnName, if it not necessary,
you can use
SELECT ColumnValue Result
FROM cte1 a
WHERE EXISTS (SELECT 1
FROM cte2 b
WHERE a.ColumnId = b.ColumnId)
Result
------
A
23
(2 row(s) affected)
OR
SELECT ColumnValue Result
FROM cte1 a
WHERE EXISTS (SELECT 1
FROM cte2 b
WHERE a.ColumnId = b.ColumnId)
AND a.ResultOrder = 2
Result
------
23
(1 row(s) affected)

Dynamic update for different colums using between two date like calendar date

CREATE PROCEDURE [dbo].[CalendarMonthly]
(
#FROMDATE VARCHAR(25)
)
AS
BEGIN
SET NOCOUNT ON
DECLARE #ADate DATETIME
DECLARE #MonthCount INT
SET #ADate = #FROMDATE
SET #MonthCount = (SELECT DAY(EOMONTH(#ADate)))
DECLARE #tmpTable TABLE
(
TRoomID INT, DAY1 INT, DAY2 INT, DAY3 INT, DAY4 INT, DAY5 INT, DAY6 INT, DAY7 INT
)
INSERT INTO #tmpTable
SELECT RM.ROOMID,
0,0,0,0,0,0,0
FROM RoomMaster AS RM
LEFT JOIN RoomTypes AS RT ON RM.RoomTypeID = RT.RoomTypeID
WHERE RM.RoomMasterStatus <> 99
DECLARE #RoomID INT
DECLARE #ForDate DATE
DECLARE #dtFromDate DATE
DECLARE #dtToDate DATE
SET #dtFromDate = CONVERT(DATE,#FromDate)
SET #ForDate = #dtFromDate
SET #dtToDate = CONVERT(DATE,CONVERT(VARCHAR,YEAR(#dtFromDate)) +'-'+ CONVERT(VARCHAR,MONTH(DATEADD(M,1,#dtFromDate)))+'-1')
SET #dtToDate = DATEADD(D,-1,#dtToDate)
DECLARE #DayCount INT
WHILE #ForDate <= #dtToDate
BEGIN
SET #DayCount = DAY(#ForDate)
IF #DayCount = 1
BEGIN
-- Checkin
UPDATE #tmpTable SET DAY1 = 1
FROM #tmpTable TT
JOIN RoomCheckinDetails AS RCD ON RCD.RoomID = TT.TRoomID
JOIN RoomCheckinMaster AS RCM ON RCM.CheckinID = RCD.CheckinID
WHERE CONVERT(DATE,RCD.CheckinDate) = #ForDate
AND RCD.RoomID = TT.TRoomID
-- Expected Checkin
UPDATE #tmpTable SET DAY1 = 8
FROM #tmpTable TT
JOIN RoomBookingDetails AS RBD ON RBD.RoomID = TT.TRoomID
JOIN RoomBookingMaster AS RBM ON RBM.ReservationID = RBD.ReservationID
WHERE CONVERT(DATE,RBD.ExpectedCheckinDate) = #ForDate
AND RBD.RoomID = TT.TRoomID
END
ELSE IF #DayCount = 2
.
.
.
.
.
.
---upto Day count 7
SET #ForDate = DATEADD(Day,1,#ForDate)
END
SELECT * FROM #tmpTable
END
My question is:
ex: checkindate = 04/06/2017, checoutdate = 9/06/2017 in compare two date I have update to columns day1 to columns day6 values is 0.
Instead of creating a temporary table and using a cursor to update each set of columns, this is a set based solution that avoids all of that.
For the first part, if you just need 7 days then you can use a simple values tally table with a common table expression and the Table Value Constructor (Transact-SQL):
declare #fromdate date = '20170605';
;with dates as (
select
[Date]=convert(date,dateadd(day,rn-1,#fromdate))
, rn
from (values (1),(2),(3),(4),(5),(6),(7)) t(rn)
)
Otherwise, you can generate an adhoc table of dates using stacked ctes in a common table expression like this:
declare #fromdate date = '20170605';
declare #thrudate date = dateadd(day,6,#fromdate)
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
, dates as (
select top (datediff(day, #fromdate, #thrudate)+1)
[Date]=convert(date,dateadd(day,row_number() over(order by (select 1))-1,#fromdate))
, rn = row_number() over(order by (select 1))
from n as deka cross join n as hecto cross join n as kilo
cross join n as tenK cross join n as hundredK
order by [Date]
)
Then cross join the dates with roommaster, and left join both the checkin and booking tables to see if a room has a reservation or is currently occupied:
, cte as (
select
rm.roomid
, d.rn
, Value = case
when rcd.roomid is not null then 1
when rbd.roomid is not null then 8
else 0
end
from dates d
cross join roommaster rm
left join roomcheckindetails rcd
on rm.roomid = rcd.roomid
and d.date >= rcd.checkindate
and d.date <= rcd.checkoutdate
left join roombookingdetails rbd
on rm.roomid = rbd.roomid
and d.date >= rbd.expectedcheckindate
and d.date <= rbd.expectedcheckoutdate
where rm.roommasterstatus <> 99
)
Then for the last piece, you can use conditional aggregation or pivot() (pick one) like so:
select
roomid
, Day1 = min(case when rn = 1 then value end)
, Day2 = min(case when rn = 2 then value end)
, Day3 = min(case when rn = 3 then value end)
, Day4 = min(case when rn = 4 then value end)
, Day5 = min(case when rn = 5 then value end)
, Day6 = min(case when rn = 6 then value end)
, Day7 = min(case when rn = 7 then value end)
from cte
group by roomid
select
roomid
, Day1 = [1]
, Day2 = [2]
, Day3 = [3]
, Day4 = [4]
, Day5 = [5]
, Day6 = [6]
, Day7 = [7]
from cte
pivot (min(value) for rn in ([1],[2],[3],[4],[5],[6],[7]))p
rextester demo with conditional aggregation: http://rextester.com/RUJ98491
rextester demo with pivot(): http://rextester.com/YNKU89188
both return the same results for my demo data:
+--------+------+------+------+------+------+------+------+
| roomid | Day1 | Day2 | Day3 | Day4 | Day5 | Day6 | Day7 |
+--------+------+------+------+------+------+------+------+
| 2 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
| 3 | 0 | 8 | 8 | 8 | 8 | 0 | 0 |
+--------+------+------+------+------+------+------+------+
Number and Calendar table reference:
Generate a set or sequence without loops - 2 - Aaron Bertrand
The "Numbers" or "Tally" Table: What it is and how it replaces a loop - Jeff Moden
Creating a Date Table/Dimension in sql Server 2008 - David Stein
Calendar Tables - Why You Need One - David Stein
Creating a date dimension or calendar table in sql Server - Aaron Bertrand

SQL Server - Running Total with Carry Forward

Needs some help on the following:
Table #Data contains the Opening and Closing Stock for a product over 5 days
Table #BackData contains some post dated transactions
How can i Update the table #Data with a Running Total including a carry forward
CREATE TABLE #Data (
Prod VARCHAR(20)
,SDate DATE
,OStock INT
,CStock INT
)
CREATE TABLE #BackData (
Prod VARCHAR(20)
,SDate DATE
,CStock INT
)
INSERT INTO #Data
SELECT 'p1', '2016-06-06', 10, 10
UNION ALL
SELECT 'p1', '2016-06-07', 10, 14
UNION ALL
SELECT 'p1', '2016-06-08', 14, 13
UNION ALL
SELECT 'p1', '2016-06-09', 13, 13
UNION ALL
SELECT 'p1', '2016-06-10', 13, 11
INSERT INTO #BackData
SELECT 'p1', '2016-06-06', 2
UNION ALL
SELECT 'p1', '2016-06-07', 4
UNION ALL
SELECT 'p1', '2016-06-09', -1
UNION ALL
SELECT 'p1', '2016-06-10', -2
DROP TABLE #Data
DROP TABLE #BackData
Desired Output :
Prod| SDate |OStock |CStock|
p1 |2016-06-06 |10 |12 |
p1 |2016-06-07 |12 |16 |
p1 |2016-06-08 |16 |16 |
p1 |2016-06-09 |16 |15 |
p1 |2016-06-10 |15 |13 |
EDIT
This is what i had managed to write before i got the answer, using two updates because the actual table had too many columns to use in a single query.
UPDATE D
SET D.CStock = FL.NewCStock
FROM #Data D
INNER JOIN (
SELECT DT.Prod
,DT.SDate
,SUM(IIF(RwNm = 1, DT.CStock, 0) + ISNULL(BD.CStock, 0)) OVER (
PARTITION BY DT.Prod ORDER BY DT.SDate ROWS UNBOUNDED PRECEDING
) NewCStock
FROM (
SELECT Prod
,SDate
,CStock
,ROW_NUMBER() OVER (
PARTITION BY Prod ORDER BY SDate
) AS RwNm
FROM #Data
) DT
LEFT JOIN #BackData BD ON DT.Prod = DT.Prod
AND BD.SDate = DT.SDate
) FL ON D.Prod = FL.Prod
AND D.SDate = FL.SDate
UPDATE D
SET D.OStock = PV.NewOStock
FROM #Data D
INNER JOIN (
SELECT Prod
,SDate
,ISNULL(LAG(CStock) OVER (
PARTITION BY Prod ORDER BY SDate
), CStock) AS NewOStock
FROM #Data
) PV ON D.Prod = PV.Prod
AND D.SDate = PV.SDate
You can use the following query to UPDATE:
;WITH ToUpdate AS (
SELECT d1.OStock, d1.CStock,
COALESCE(LAG(d2.CStock2) OVER (PARTITION BY d2.Prod
ORDER BY d2.SDate),
d1.OStock) AS OStock2,
d2.CStock2
FROM #Data AS d1
JOIN (
SELECT d.Prod, d.SDate, d.OStock, d.CStock,
COALESCE(t.newCStock,
LAG(t.newCStock) OVER (PARTITION BY d.Prod
ORDER BY d.SDate)) AS CStock2
FROM #Data AS d
LEFT JOIN (
SELECT bd.Prod, bd.SDate,
drn.CStock + SUM(bd.CStock) OVER (PARTITION BY bd.Prod
ORDER BY bd.SDate) AS newCStock
FROM #BackData AS bd
INNER JOIN (
SELECT Prod, CStock,
ROW_NUMBER() OVER (PARTITION BY Prod ORDER BY SDate) AS rn
FROM #Data
) AS drn ON bd.Prod = drn.Prod AND drn.rn = 1
) AS t ON t.Prod = d.Prod AND t.SDate = d.SDate
) AS d2 ON d1.Prod = d2.Prod AND d1.SDate= d2.SDate
)
UPDATE ToUpdate
SET OStock = OStock2,
CStock = CStock2
This looks awfully convoluted, but I couldn't think of anything simpler.
Demo here
You can rebuild values in #Data table with the help of recursive CTE:
;WITH cte AS (
SELECT top 1 d.Prod,
d.SDate,
d.OStock,
d.OStock + b.CStock as CStock
FROM #Data d
LEFT JOIN #BackData b
ON b.Prod = d.Prod and b.SDate = d.SDate
ORDER BY d.SDate ASC
UNION ALL
SELECT c.Prod,
DATEADD(day,1,c.SDate),
c.CStock,
c.CStock + ISNULL(b.CStock,0)
FROM cte c
INNER JOIN #Data d
ON d.Prod = c.Prod AND d.SDate = DATEADD(day,1,c.SDate)
OUTER APPLY (SELECT CStock FROM #BackData b WHERE b.Prod = d.Prod and b.SDate = d.SDate) as b
)
SELECT *
FROM cte
Output:
Prod SDate OStock CStock
-------------------- ---------- ----------- -----------
p1 2016-06-06 10 12
p1 2016-06-07 12 16
p1 2016-06-08 16 16
p1 2016-06-09 16 15
p1 2016-06-10 15 13
To update #Data:
UPDATE d
SET OStock = c.OStock, CStock = c.CStock
FROM #Data d
INNER JOIN cte c
ON c.Prod = d.Prod AND c.SDate = d.SDate
Shouldn't the result be like :
Prod SDate OStock CStock
p1 2016-06-06 10 12
p1 2016-06-07 12 20 (#Data CStock 14 + #BakData 2 + 4)
p1 2016-06-08 20 19 (#Data CStock 13 + #BakData 2 + 4)
p1 2016-06-09 19 18 (#Data CStock 13 + #BakData 2 + 4 - 1)
p1 2016-06-10 18 14 (#Data CStock 11 + #BakData 2 + 4 - 1 -2)
This query will produce the above result
update d
set OStock = d.OStock + a.OAdj,
CStock = d.CStock + a.CAdj
from #Data d
cross apply
(
select OAdj = sum(case when Oflag = 1 then x.CStock else 0 end),
CAdj = sum(x.CStock)
from
(
select *, Oflag = case when x.SDate = d.SDate then 0 else 1 end
from #BackData x
where x.Prod = d.Prod
and x.SDate <= d.SDate
) x
) a
Based on your expected output, it seems that you are re-calculating the daily Opening / Closing balance based on the figure from 2016-06-06
Here is a solution that will gives you your expected output.
; with
cte as
(
select Prod, SDate, OStock, CStock,
rn = row_number() over (partition by Prod order by SDate)
from #Data
),
adj as
(
select Prod, SDate, CStock
from cte
where rn = 1
union all
select Prod, SDate, CStock
from #BackData
)
update d
set OStock = coalesce(o.OStock, d.OStock),
CStock = c.CStock
from #Data d
cross apply
(
select OStock = sum(x.CStock)
from adj x
where x.Prod = d.Prod
and x.SDate < d.SDate
) o
cross apply
(
select CStock = sum(x.CStock)
from adj x
where x.Prod = d.Prod
and x.SDate <= d.SDate
) c
Result :
p1 2016-06-06 10 12
p1 2016-06-07 12 16
p1 2016-06-08 16 16
p1 2016-06-09 16 15
p1 2016-06-10 15 13

Resources