Get the count of statuses by date but only count continuous rows - sql-server

I have this data:
ID Name Status Date
1 Machine1 Active 2018-01-01
2 Machine2 Fault 2018-01-01
3 Machine3 Active 2018-01-01
4 Machine1 Fault 2018-01-02
5 Machine2 Active 2018-01-02
6 Machine3 Active 2018-01-02
7 Machine2 Active 2018-01-03
8 Machine1 Fault 2018-01-03
9 Machine2 Active 2018-01-04
10 Machine1 Fault 2018-01-04
11 Machine3 Active 2018-01-06
INPUT
and i want these data in output
EXPECTED OUTPUT
Name Last Status Count
Machine1 Fault 3
Machine2 Active 3
Machine3 Active 1 Because Date is not Continuous
*Count : Last number of status in continuous history

I believe it is as simple as this:
WITH cte1 AS (
SELECT
Name,
Status,
DATEADD(DAY, ROW_NUMBER() OVER (PARTITION BY Name, Status ORDER BY Date DESC) - 1, Date) AS GroupingDate
FROM testdata
), cte2 AS (
SELECT
Name,
Status,
RANK() OVER (PARTITION BY Name ORDER BY GroupingDate DESC) AS GroupingNumber
FROM cte1
)
SELECT Name, Status AS LastStatus, COUNT(*) AS LastStatusCount
FROM cte2
WHERE GroupingNumber = 1
GROUP BY Name, Status
ORDER BY Name
Result and DBFiddle:
| Name | LastStatus | LastStatusCount |
|----------|------------|-----------------|
| Machine1 | Fault | 3 |
| Machine2 | Active | 3 |
| Machine3 | Active | 1 |
In order to understand how this works, look at the intermediate values generated by CTE:
| Name | Status | Date | RowNumber | GroupingDate | GroupingNumber |
|----------|--------|---------------------|-----------|---------------------|----------------|
| Machine1 | Fault | 04/01/2018 00:00:00 | 1 | 04/01/2018 00:00:00 | 1 |
| Machine1 | Fault | 03/01/2018 00:00:00 | 2 | 04/01/2018 00:00:00 | 1 |
| Machine1 | Fault | 02/01/2018 00:00:00 | 3 | 04/01/2018 00:00:00 | 1 |
| Machine1 | Active | 01/01/2018 00:00:00 | 1 | 01/01/2018 00:00:00 | 4 |
| Machine2 | Active | 04/01/2018 00:00:00 | 1 | 04/01/2018 00:00:00 | 1 |
| Machine2 | Active | 03/01/2018 00:00:00 | 2 | 04/01/2018 00:00:00 | 1 |
| Machine2 | Active | 02/01/2018 00:00:00 | 3 | 04/01/2018 00:00:00 | 1 |
| Machine2 | Fault | 01/01/2018 00:00:00 | 1 | 01/01/2018 00:00:00 | 4 |
| Machine3 | Active | 06/01/2018 00:00:00 | 1 | 06/01/2018 00:00:00 | 1 |
| Machine3 | Active | 02/01/2018 00:00:00 | 2 | 03/01/2018 00:00:00 | 2 |
| Machine3 | Active | 01/01/2018 00:00:00 | 3 | 03/01/2018 00:00:00 | 2 |
The trick here is that if two numbers are contiguous then subtracting contiguous numbers from them will result in same value. E.g. if we have 5, 6, 8, 9 then subtracting 1, 2, 3, 4 in that order will produce 4, 4, 5, 5.

I think this will work, though SQLFiddle is having a fit at the moment, so I can't test:
SELECT [Name], [Status], ct as [Count]
FROM (
SELECT
[name],
[status],
[date],
1 + (SUM( grp ) OVER (PARTITION BY [name], [status] ORDER BY [date] ROWS BETWEEN 1 PRECEDING AND 0 FOLLOWING ) * grp) ct,
row_number() over(partition by [name] order by [date] desc) rn
FROM
(
SELECT *, CASE WHEN LAG([Date]) OVER(PARTITION BY [name], [status] ORDER BY [date] ) = DATEADD(day, -1, [date]) THEN 1 ELSE 0 END grp
FROM t
) x
) y
WHERE
rn = 1
It first off uses LAG to look at the current row and the previous row (grouping the data into machine name and status, ordering the data by date) and if the current date is 1 day different to the previous date it records a 1 else a 0
These 1s and zeroes are summed in a running total fashion, resetting when the machine name or status changes (the partition of the sum() over() )
Also we want to consider the data just in terms of the machine name, and we only want the latest record from each machine, so we partition by the machine name, and count in order of date descending, then just pick (with the where clause) the rows that are numbered 1 for each machine
It actually makes a lot more sense if you run the queries separately, like this
Calculate the "is the current report consecutive with the previous report, for the given status and machine" 1 = yes, 0 = no:
SELECT *, CASE WHEN LAG([Date]) OVER(PARTITION BY [name], [status] ORDER BY [date] ) = DATEADD(day, -1, [date]) THEN 1 ELSE 0 END grp
FROM t
Calculate the "what is the running total of the current block of consecutive reports":
SELECT
[name],
[status],
[date],
1 + (SUM( grp ) OVER (PARTITION BY [name], [status] ORDER BY [date] ROWS BETWEEN 1 PRECEDING AND 0 FOLLOWING ) * grp) ct,
row_number() over(partition by [name] order by [date] desc) rn
FROM
(
SELECT *, CASE WHEN LAG([Date]) OVER(PARTITION BY [name], [status] ORDER BY [date] ) = DATEADD(day, -1, [date]) THEN 1 ELSE 0 END grp
FROM t
) x
Then of course, the whole thing but without the where clause, so you can see the data we're discarding:
SELECT [Name], [Status], ct as [Count]
FROM (
SELECT
[name],
[status],
[date],
1 + (SUM( grp ) OVER (PARTITION BY [name], [status] ORDER BY [date] ROWS BETWEEN 1 PRECEDING AND 0 FOLLOWING ) * grp) ct,
row_number() over(partition by [name] order by [date] desc) rn
FROM
(
SELECT *, CASE WHEN LAG([Date]) OVER(PARTITION BY [name], [status] ORDER BY [date] ) = DATEADD(day, -1, [date]) THEN 1 ELSE 0 END grp
FROM t
) x
) y
Fiddle finally woke up:
http://www.sqlfiddle.com/#!18/77dae/2

Related

SQL Query to get in/out time

I need to create a report when the user entering and exiting time. So far I only manage to get the min and max time. Here, the example of table:
ID | Flag_Location (bit) | Time
----------------------------
1001 | 1 | 8:00
1001 | 1 | 9:00
1001 | 1 | 10:00
1001 | 0 | 11:00
1001 | 0 | 12:00
1001 | 1 | 13:00
1001 | 1 | 14:00
The output that I need for the report is like this :
ID | ENTERTIME | EXITTIME
-------------------------
1001 | 8:00 | 10:00
1001 | 13:00 | 14:00
So far I only manage to get 1 row of result :
ID | ENTERTIME | EXITTIME
-------------------------
1001 | 8:00 | 14:00
You can use the window function to create an ad-hoc Grp
Example
Select ID
,TimeIn = min(Time)
,TimeOut = max(Time)
From (
Select *
,Grp = sum(case when flag_location=0 then 1 else 0 end ) over (partition by id order by time)
From YourTable
) A
Where Flag_Location=1
Group By ID,Grp
Returns
ID TimeIn TimeOut
1001 08:00:00.0000000 10:00:00.0000000
1001 13:00:00.0000000 14:00:00.0000000
If it helps with the visualization, the nested query generates the following:
You can just bucket the to identify group by and do group by as below:
;with cte as (select *, bucket = sum(case when flag_location = 0 then 1 when flag_location = 1 and nextflag = 0 then 2 else 0 end) over (partition by id order by [time]),
[time] as endtime from
(
select *,
lag(flag_location) over(partition by id order by [time]) nextflag
from #table4
) a
)
select id, min([time]), max([time]) from cte
where flag_location = 1
group by id, bucket
Query results:
+------+------------------+------------------+
| id | Entertime | ExitTime |
+------+------------------+------------------+
| 1001 | 08:00:00.0000000 | 10:00:00.0000000 |
| 1001 | 13:00:00.0000000 | 14:00:00.0000000 |
+------+------------------+------------------+
Try below query (explanations in code)
declare #tbl table (ID int, Flag_Location bit, Time varchar(5));
insert into #tbl values
(1001,1,'8:00'),
(1001,1,'9:00'),
(1001,1,'10:00'),
(1001,0,'11:00'),
(1001,0,'12:00'),
(1001,1,'13:00'),
(1001,1,'14:00');
select ID,
cast(max(ts) as varchar(10)),
cast(min(ts) as varchar(10))
from (
select ID, ts, Flag_Location,
row_number() over (order by ts) -
row_number() over (partition by Flag_Location order by ts) grp
from (
select *,
-- add 0 at the beginning for correct cast and cast it to timestamp for correct ordering
cast(right('00000' + time, 5) as timestamp) ts
from #tbl
) a
) a where Flag_Location = 1
group by ID, grp

LAG of MIN in SQL Analytic

I have a table containing employees id, year id, client id, and the number of sales. For example:
--------------------------------------
id_emp | id_year | sales | client id
--------------------------------------
4 | 1 | 14 | 1
4 | 1 | 10 | 2
4 | 2 | 11 | 1
4 | 2 | 17 | 2
For a employee, I want to obtain rows with the minimum sales per year and the minimum sales of the previous year.
One of the queries I tried is the following:
select distinct
id_emp,
id_year,
MIN(sales) OVER(partition by id_emp, id_year) AS min_sales,
LAG(min(sales), 1) OVER(PARTITION BY id_emp, id_year
ORDER BY id_emp, id_year) AS previous
from facts
where id_emp = 4
group by id_emp, id_year, sales;
I get the result:
-------------------------------------
id_emp | id_year | sales | previous
-------------------------------------
4 | 1 | 10 | (null)
4 | 1 | 10 | 10
4 | 2 | 11 | (null)
but I expect to get:
-------------------------------------
id_emp | id_year | sales | previous
-------------------------------------
4 | 1 | 10 | (null)
4 | 2 | 11 | 10
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE EMPLOYEE_SALES ( id_emp, id_year, sales, client_id ) AS
SELECT 4, 1, 14, 1 FROM DUAL
UNION ALL SELECT 4, 1, 10, 2 FROM DUAL
UNION ALL SELECT 4, 2, 11, 1 FROM DUAL
UNION ALL SELECT 4, 2, 17, 2 FROM DUAL;
Query 1:
SELECT ID_EMP,
ID_YEAR,
SALES AS SALES,
LAG( SALES ) OVER ( PARTITION BY ID_EMP ORDER BY ID_YEAR ) AS PREVIOUS
FROM (
SELECT e.*,
ROW_NUMBER() OVER ( PARTITION BY id_emp, id_year ORDER BY sales ) AS RN
FROM EMPLOYEE_SALES e
)
WHERE rn = 1
Query 2:
SELECT ID_EMP,
ID_YEAR,
MIN( SALES ) AS SALES,
LAG( MIN( SALES ) ) OVER ( PARTITION BY ID_EMP ORDER BY ID_YEAR ) AS PREVIOUS
FROM EMPLOYEE_SALES
GROUP BY ID_EMP, ID_YEAR
Results - Both give the same output:
| ID_EMP | ID_YEAR | SALES | PREVIOUS |
|--------|---------|-------|----------|
| 4 | 1 | 10 | (null) |
| 4 | 2 | 11 | 10 |
You mean like this?
select id_emp, id_year, min(sales) as min_sales,
lag(min(sales)) over (partition by id_emp order by id_year) as prev_year_min_sales
from facts
where id_emp = 4
group by id_emp, id_year;
I believe it is because you are using sales column in your group by statement.
Try to remove it and just use
GROUP BY id_emp,id_year
You could get your desired output using ROW_NUMBER() and LAG() analytic functions.
For example,
Table
SQL> SELECT * FROM t;
ID_EMP ID_YEAR SALES CLIENT_ID
---------- ---------- ---------- ----------
4 1 14 1
4 1 10 2
4 2 11 1
4 2 17 2
Query
SQL> WITH DATA AS
2 (SELECT t.*,
3 row_number() OVER(PARTITION BY id_emp, id_year ORDER BY sales) rn
4 FROM t
5 )
6 SELECT id_emp,
7 id_year ,
8 sales ,
9 lag(sales) over(order by sales) previous
10 FROM DATA
11 WHERE rn =1;
ID_EMP ID_YEAR SALES PREVIOUS
---------- ---------- ---------- ----------
4 1 10
4 2 11 10

Change the Value on Duplicate Rows

I need assistance on how to code duplicate Line IDs for the same Purchase Order and assign the additional line IDs with a new number. I would like to use Line ID + 100 for the additional duplicate rows. For example if Purchase Order #11 has three Line ID #5s then the first would stay as 5 and the second would be 501 and the third would be 502, however, I can only get a 1, 2 or 3 or if no duplicate just 1. I am not sure what to use to increment. I am hoping some one can assist or guide. Thank you
PurchaseOrderID LineID PackingList NewLineID
11 1 12323 1
11 1 78786 2
11 2 67523 1
11 3 44559 1
11 4 44559 1
11 5 96545 1
11 5 12323 2
11 5 34569 3
The Packing Slip causes the duplicates for the same line ID.
Below is what I am trying to use which is giving me the above NewLineID:
SELECT
PurchaseOrderID,
LineID,
PackingList,
ROW_NUMBER() over
(
partition by PurchaseOrderID, LineID
order by PurchaseOrderID, LineID
) as NewLineID
FROM PurchaseOrderTransactions
Using ROW_NUMBER and CASE:
WITH Cte AS(
SELECT
PurchaseOrderID,
LineID,
PackingList,
RN = ROW_NUMBER() OVER (PARTITION BY PurchaseOrderID, LineID ORDER BY LineID)
FROM PurchaseOrderTransactions
)
SELECT
PurchaseOrderID,
LineID,
PackingList,
NewLineID = CASE
WHEN RN = 1 THEN LineID
ELSE (LineID * 100) + (RN - 1)
END
FROM Cte
Without using a CTE:
SELECT
PurchaseOrderID,
LineID,
PackingList,
NewLineID =
CASE
WHEN ROW_NUMBER() OVER (PARTITION BY PurchaseOrderID, LineID ORDER BY LineID) = 1 THEN LineID
ELSE (LineID * 100) + (ROW_NUMBER() OVER (PARTITION BY PurchaseOrderID, LineID ORDER BY LineID) - 1)
END
FROM PurchaseOrderTransactions
SQL Fiddle
| PurchaseOrderID | LineID | PackingList | NewLineID |
|-----------------|--------|-------------|-----------|
| 11 | 1 | 12323 | 1 |
| 11 | 1 | 78786 | 101 |
| 11 | 2 | 67523 | 2 |
| 11 | 3 | 44559 | 3 |
| 11 | 4 | 44559 | 4 |
| 11 | 5 | 96545 | 5 |
| 11 | 5 | 12323 | 501 |
| 11 | 5 | 34569 | 502 |

The highest value from list-distinct

Can anyone help me with query, I have table
vendorid, agreementid, sales
12001 1004 700
5291 1004 20576
7596 1004 1908
45 103 345
41 103 9087
what is the goal ?
when agreemtneid >1 then show me data when sales is the highest
vendorid agreementid sales
5291 1004 20576
41 103 9087
Any ideas ?
Thx
Well you could try using a CTE and ROW_NUMBER something like
;WITH Vals AS (
SELECT *, ROW_NUMBER() OVER(PARTITION BY AgreementID ORDER BY Sales DESC) RowID
FROM MyTable
WHERE AgreementID > 1
)
SELECT *
FROM Vals
WHERE RowID = 1
This will avoid you returning multiple records with the same sale.
If that was OK you could try something like
SELECT *
FROM MyTable mt INNER JOIN
(
SELECT AgreementID, MAX(Sales) MaxSales
FROM MyTable
WHERE AgreementID > 1
) MaxVals ON mt.AgreementID = MaxVals.AgreementID AND mt.Sales = MaxVals.MaxSales
SELECT TOP 1 WITH TIES *
FROM MyTable
ORDER BY DENSE_RANK() OVER(PARTITION BY agreementid ORDER BY SIGN (SIGN (agreementid - 2) + 1) * sales DESC)
Explanation
We break table MyTable into partitions by agreementid.
For each partition we construct a ranking or its rows.
If agreementid is greater than 1 ranking will be equal to ORDER BY sales DESC.
Otherwise ranking for every single row in partition will be the same: ORDER BY 0 DESC.
See how it looks like:
SELECT *
, SIGN (SIGN (agreementid - 2) + 1) * sales AS x
, DENSE_RANK() OVER(PARTITION BY agreementid ORDER BY SIGN (SIGN (agreementid - 2) + 1) * sales DESC) AS rnk
FROM MyTable
+----------+-------------+-------+-------+-----+
| vendorid | agreementid | sales | x | rnk |
+----------|-------------|-------+-------+-----+
| 0 | 0 | 3 | 0 | 1 |
| -1 | 0 | 7 | 0 | 1 |
| 0 | 1 | 3 | 0 | 1 |
| -1 | 1 | 7 | 0 | 1 |
| 41 | 103 | 9087 | 9087 | 1 |
| 45 | 103 | 345 | 345 | 2 |
| 5291 | 1004 | 20576 | 20576 | 1 |
| 7596 | 1004 | 1908 | 1908 | 2 |
| 12001 | 1004 | 700 | 700 | 3 |
+----------+-------------+-------+-------+-----+
Then using TOP 1 WITH TIES construction we leave only rows where rnk equals 1.
you can try like this.
SELECT TOP 1 sales FROM MyTable WHERE agreemtneid > 1 ORDER BY sales DESC
I really do not know the business logic behind agreement_id > 1. It looks to me you want the max sales (with ties) by agreement id regardless of vendor_id.
First, lets create a simple sample database.
-- Sample table
create table #sales
(
vendor_id int,
agreement_id int,
sales_amt money
);
-- Sample data
insert into #sales values
(12001, 1004, 700),
(5291, 1004, 20576),
(7596, 1004, 1908),
(45, 103, 345),
(41, 103, 9087);
Second, let's solve this problem using a common table expression to get a result set that has each row paired with the max sales by agreement id.
The select statement just applies the business logic to filter the data to get your answer.
-- CTE = max sales for each agreement id
;
with cte_sales as
(
select
vendor_id,
agreement_id,
sales_amt,
max(sales_amt) OVER(PARTITION BY agreement_id) AS max_sales
from
#sales
)
-- Filter by your business logic
select * from cte_sales where sales_amt = max_sales and agreement_id > 1;
The screen shot below shows the exact result you wanted.

How to calculate SUM balance of all accounts in T-SQL?

I have this table and data
CREATE TABLE #transactions (
[transactionId] [int] NOT NULL,
[accountId] [int] NOT NULL,
[dt] [datetime] NOT NULL,
[balance] [smallmoney] NOT NULL,
CONSTRAINT [PK_transactions_1] PRIMARY KEY CLUSTERED
( [transactionId] ASC)
)
INSERT #transactions ([transactionId], [accountId], [dt], [balance]) VALUES
(1, 1, CAST(0x0000A13900107AC0 AS DateTime), 123.0000),
(2, 1, CAST(0x0000A13900107AC0 AS DateTime), 192.0000),
(3, 1, CAST(0x0000A13A00107AC0 AS DateTime), 178.0000),
(4, 2, CAST(0x0000A13B00107AC0 AS DateTime), 78.0000),
(5, 2, CAST(0x0000A13D011D1860 AS DateTime), 99.0000),
(6, 2, CAST(0x0000A13F00000000 AS DateTime), 97.0000),
(7, 1, CAST(0x0000A13D0141E640 AS DateTime), 201.0000),
(8, 3, CAST(0x0000A1420094DD60 AS DateTime), 4000.0000),
(9, 3, CAST(0x0000A14300956A00 AS DateTime), 4100.0000),
(10, 3, CAST(0x0000A14700000000 AS DateTime), 4200.0000),
(11, 2, CAST(0x0000A14B00B84BB0 AS DateTime), 110.0000)
I need two queries.
For each transaction, I want to return in a query the most recent balance for each account, and an extra column with a SUM of each account balance at that point in time.
Same as 1 but grouped by date without the time portion. So the latest account balance at the end of each day (where there is a transaction in any account) for each account, but SUMed together as in 1.
Data above is sample data that I just made up, but my real table has hundreds of rows and ten accounts (which may increase soon). Each account has a unique accountId. Seems quite a tricky piece of SQL.
EXAMPLE
For 1. I need a result like this:
+---------------+-----------+-------------------------+---------+-------------+
| transactionId | accountId | dt | balance | sumBalances |
+---------------+-----------+-------------------------+---------+-------------+
| 1 | 1 | 2013-01-01 01:00:00.000 | 123 | 123 |
| 2 | 1 | 2013-01-01 01:00:00.000 | 192 | 192 |
| 3 | 1 | 2013-01-02 01:00:00.000 | 178 | 178 |
| 4 | 2 | 2013-01-03 01:00:00.000 | 78 | 256 |
| 5 | 2 | 2013-01-05 17:18:00.000 | 99 | 277 |
| 7 | 1 | 2013-01-05 19:32:00.000 | 201 | 300 |
| 6 | 2 | 2013-01-07 00:00:00.000 | 97 | 298 |
| 8 | 3 | 2013-01-10 09:02:00.000 | 4000 | 4298 |
| 9 | 3 | 2013-01-11 09:04:00.000 | 4100 | 4398 |
| 10 | 3 | 2013-01-15 00:00:00.000 | 4200 | 4498 |
| 11 | 2 | 2013-01-19 11:11:00.000 | 110 | 4511 |
+---------------+-----------+-------------------------+---------+-------------+
So, for transactionId 8, I take the latest balance for each account in turn and then sum them. AccountID 1: is 201, AccountId 2 is 97 and AccountId 3 is 4000. Therefore the result for transactionId 8 will be 201+97+4000 = 4298. When calculating the set must be ordered by dt
For 2. I need this
+------------+-------------+
| date | sumBalances |
+------------+-------------+
| 01/01/2013 | 192 |
| 02/01/2013 | 178 |
| 03/01/2013 | 256 |
| 05/01/2013 | 300 |
| 07/01/2013 | 298 |
| 10/01/2013 | 4298 |
| 11/01/2013 | 4398 |
| 15/01/2013 | 4498 |
| 19/01/2013 | 4511 |
+------------+-------------+
So on date 15/01/2013 the latest account balance for each account in turn (1,2,3) is 201,97,4200. So the result for that date would be 201+97+4200 = 4498
This gives your first desired resultset (SQL Fiddle)
WITH T
AS (SELECT *,
balance -
isnull(lag(balance) OVER (PARTITION BY accountId
ORDER BY dt, transactionId), 0) AS B
FROM #transactions)
SELECT transactionId,
accountId,
dt,
balance,
SUM(B) OVER (ORDER BY dt, transactionId ROWS UNBOUNDED PRECEDING) AS sumBalances
FROM T
ORDER BY dt;
It subtracts the current balance of the account from the previous balance to get the net difference then calculates a running total of those differences.
And that can be used as a base for your second result
WITH T1
AS (SELECT *,
balance -
isnull(lag(balance) OVER (PARTITION BY accountId
ORDER BY dt, transactionId), 0) AS B
FROM #transactions),
T2 AS (
SELECT transactionId,
accountId,
dt,
balance,
ROW_NUMBER() OVER (PARTITION BY CAST(dt AS DATE) ORDER BY dt DESC, transactionId DESC) AS RN,
SUM(B) OVER (ORDER BY dt, transactionId ROWS UNBOUNDED PRECEDING) AS sumBalances
FROM T1)
SELECT CAST(dt AS DATE) AS [date], sumBalances
FROM T2
WHERE RN=1
ORDER BY [date];
Part 1
; WITH a AS (
SELECT *, r = ROW_NUMBER()OVER(PARTITION BY accountId ORDER BY dt)
FROM #transactions t
)
, b AS (
SELECT t.*
, transamount = t.balance - ISNULL(t0.balance,0)
FROM a t
LEFT JOIN a t0 ON t0.accountId = t.accountId AND t0.r + 1 = t.r
)
SELECT transactionId, accountId, dt, balance
, sumBalance = SUM(transamount)OVER(ORDER BY dt, transactionId)
FROM b
ORDER BY dt
Part 2
; WITH a AS (
SELECT *, r = ROW_NUMBER()OVER(PARTITION BY accountId ORDER BY dt)
FROM #transactions t
)
, b AS (
SELECT t.*
, transamount = t.balance - ISNULL(t0.balance,0)
FROM a t
LEFT JOIN a t0 ON t0.accountId = t.accountId AND t0.r + 1 = t.r
)
, c AS (
SELECT transactionId, accountId, dt, balance
, sumBalance = SUM(transamount)OVER(ORDER BY CAST(dt AS DATE))
, r1 = ROW_NUMBER()OVER(PARTITION BY accountId, CAST(dt AS DATE) ORDER BY dt DESC)
FROM b
)
SELECT dt = CAST(dt AS DATE)
, sumBalance
FROM c
WHERE r1 = 1
ORDER BY CAST(dt AS DATE)

Resources