SQL Server 2008 How do I sum rows that match in criteria - sql

This is what my table looks like:
RefNum
Year
CorrespVNum
Proceeds
BaseCost
12345
2019
54321
12345.69
10000.00
12345
2019
54321
500.69
6000.00
12345
2019
65432
12345.69
10000.00
12345
2019
65432
500.69
6000.00
23456
2020
33344
50000.00
15000.00
34567
2021
11155
521.00
1000.00
34567
2021
11155
17.00
800.00
34567
2021
11155
85.00
100.00
I want the result to look like this:
RefNum
Year
CorrespVNum
TotalProceeds
TotalBaseCost
12345
2019
54321
12846.38
16000.00
12345
2019
65432
12846.38
16000.00
23456
2020
33344
50000.00
15000.00
34567
2021
11155
623.00
1900.00
So the matching criteria are the Refnum, Year and CorrespVnum. I have been messing around with a CTE query and I can't seem to get it to work. It works if I only have 2 matching rows but if there are more than 2 then it doesn't work.
Does anyone have any idea how to do this?

select RefNum
,Year
,CorrespVNum
,sum(Proceeds) as TotalProceeds
,sum(BaseCost) as TotalBaseCost
from t
group by RefNum, Year, CorrespVNum
RefNum
Year
CorrespVNum
TotalProceeds
TotalBaseCost
12345
2019
54321
12845
16000
12345
2019
65432
12845
16000
23456
2020
33344
50000
15000
34567
2021
11155
623
1900
Fiddle

you can try this, keep it simple:
with table_1 (Refnum,Year,CorrespVNum,Proceeds,BaseCost)
as
(
Select '12345', '2019', '54321',12345.69,10000
Union all Select '12345', '2019', '54321',500.69,6000
Union all Select '12345', '2019', '65432',12345.69,10000
Union all Select '12345', '2019', '65432',500.69,6000
Union all Select '34567', '2021', '33344',500000,15000
Union all Select '34567', '2021', '11155',521,1000
Union all Select '34567', '2021', '11155',17,800
Union all Select '34567', '2021', '11155',85,100
)
Select
RefNum,
Year,
CorrespVNum,
Sum(BaseCost) as TotalCaseCost
from
table_1
group by
RefNum,
Year,
CorrespVNum

Related

dynamic sum in oracle sql

I want last column 'Output' as stated in table. here the logic is :
for row 1 : sum of LBKUM & weekly_qty
for row 2 : sum of output of row 1 & weekly_qty of row 2
for row 3 : sum of output of row 2 & weekly_qty of row 3
for row 4 : sum of output of row 3 & weekly_qty of row 4
and so on.
Unlike other running total, I want LBKUM only once (in first row calculation) and in the next steps, output of previous row should be considered as shown in the description.
I hope this much would be sufficient.
Thanks in advance.
LOGSYS
MATNR
PLANT
LBKUM
QTY_WITHDRAWL
PLUS_QTY
WEEK
WEEKLY_QTY
Output
SAP
123456789
1234
1408
387
484
06
97
1505
SAP
123456789
1234
1408
1238
2080
07
842
2347
SAP
123456789
1234
1408
1826
1600
08
-226
2121
SAP
123456789
1234
1408
1786
1920
09
134
2255
SAP
123456789
1234
1408
1445
1120
10
-325
1930
SAP
123456789
1234
1408
1224
800
11
-424
1506
SAP
123456789
1234
1408
1299
1280
12
-19
1487
You want something like:
SELECT week,
FIRST_VALUE(lbkum) OVER (ORDER BY week)
+ SUM(weekly_qty) OVER (ORDER BY week) AS running_total
FROM table_name
Which, for the sample data:
CREATE TABLE table_name (LOGSYS, MATNR, PLANT, LBKUM, QTY_WITHDRAWL, PLUS_QTY, WEEK, WEEKLY_QTY, Output) AS
SELECT 'SAP', 123456789, 1234, 1408, 387, 484, 06, 97, 1505 FROM DUAL UNION ALL
SELECT 'SAP', 123456789, 1234, 1408, 1238, 2080, 07, 842, 2347 FROM DUAL UNION ALL
SELECT 'SAP', 123456789, 1234, 1408, 1826, 1600, 08, -226, 2121 FROM DUAL UNION ALL
SELECT 'SAP', 123456789, 1234, 1408, 1786, 1920, 09, 134, 2255 FROM DUAL UNION ALL
SELECT 'SAP', 123456789, 1234, 1408, 1445, 1120, 10, -325, 1930 FROM DUAL UNION ALL
SELECT 'SAP', 123456789, 1234, 1408, 1224, 800, 11, -424, 1506 FROM DUAL UNION ALL
SELECT 'SAP', 123456789, 1234, 1408, 1299, 1280, 12, -19, 1487 FROM DUAL;
Outputs:
WEEK
RUNNING_TOTAL
6
1505
7
2347
8
2121
9
2255
10
1930
11
1506
12
1487
fiddle

How to get most recent balance for every user and its corresponding dates

I have a table called balances. I want to get the most recent balance for each user, forever every financial year and its corresponding date it was updated.
name
balance
financial_year
date_updated
Bob
20
2021
2021-04-03
Bob
58
2019
2019-11-13
Bob
43
2019
2022-01-24
Bob
-4
2019
2019-12-04
James
92
2021
2021-09-11
James
86
2021
2021-08-18
James
33
2019
2019-03-24
James
46
2019
2019-02-12
James
59
2019
2019-08-12
So my desired output would be:
name
balance
financial_year
date_updated
Bob
20
2021
2021-04-03
Bob
43
2019
2022-01-24
James
92
2021
2021-09-11
James
59
2019
2019-08-12
I've attempted this but found that using max() sometimes does not work since I use it across multiple columns
SELECT name, max(balance), financial_year, max(date_updated)
FROM balances
group by name, financial_year
select NAME
,BALANCE
,FINANCIAL_YEAR
,DATE_UPDATED
from (
select t.*
,row_number() over(partition by name, financial_year order by date_updated desc) as rn
from t
) t
where rn = 1
NAME
BALANCE
FINANCIAL_YEAR
DATE_UPDATED
Bob
43
2019
24-JAN-22
Bob
20
2021
03-APR-21
James
59
2019
12-AUG-19
James
92
2021
11-SEP-21
Fiddle
The problem is not that you use max() across multiple columns but the fact, that max() returns the maximum value. In your example, the highest balance of Bob in financial year 2019 was 58. The 'highest' (last) date_updated was 2022-01-24, but at this time the balance was 43.
What you're looking for is the balance at the time the balance was updated last within a financial year per user, that is something like
SELECT b.name, b.financial_year, b.balance, b.date_updated
FROM balances b
INNER JOIN (SELECT name, financial_year, max(date_updated) last_updated
FROM balances GROUP BY name, financial_year) u
ON b.name = u.name AND b.financial_year = u.financial_year AND b.date_updated = u.last_updated;

Sum and Count by month, shown with last day of that month

I have a transaction table like this:
Trandate channelID branch amount
--------- --------- ------ ------
01/05/2019 1 2 2000
11/05/2019 1 2 2200
09/03/2020 1 2 5600
15/03/2020 1 2 600
12/10/2019 2 10 12000
12/10/2019 2 10 12000
15/11/2019 4 7 4400
15/02/2020 4 2 2500
I need to sum amount and count transactions by year and month. I tried this:
select DISTINCT
DATEPART(YEAR,a.TranDate) as [YearT],
DATEPART(MONTH,a.TranDate) as [monthT],
count(*) as [countoftran],
sum(a.Amount) as [amount],
a.Name as [branch],
a.ChannelName as [channelID]
from transactions as a
where a.TranDate>'20181231'
group by a.Name, a.ChannelName, DATEPART(YEAR,a.TranDate), DATEPART(MONTH,a.TranDate)
order by a.Name, YearT, MonthT
It works like charm. However, I will use this data on PowerBI thus I cannot show these results in a "line graphic" due to the year and month info being in separate columns.
I tried changing format on SQL to 'YYYYMM' alas powerBI doesn't recognise this column as date.
So, in the end, I need a result table looks like this:
YearT channelID branch Tamount TranT
--------- --------- ------ ------- -----
31/05/2019 1 2 4400 2
30/03/2020 1 2 7800 2
31/10/2019 2 10 24000 2
30/11/2019 4 7 4400 1
29/02/2020 4 2 2500 1
I have tried several little changes with no result.
Help is much appreciated.
You may try with the following statement:
SELECT
EOMONTH(DATEFROMPARTS(YEAR(Trandate), MONTH(Trandate), 1)) AS YearT,
branch, channelID,
SUM(amount) AS TAmount,
COUNT(*) AS TranT
FROM (VALUES
('20190501', 1, 2, 2000),
('20190511', 1, 2, 2200),
('20200309', 1, 2, 5600),
('20200315', 1, 2, 600),
('20191012', 2, 10, 12000),
('20191012', 2, 10, 12000),
('20191115', 4, 7, 4400),
('20200215', 4, 2, 2500)
) v (Trandate, channelID, branch, amount)
GROUP BY DATEFROMPARTS(YEAR(Trandate), MONTH(Trandate), 1), branch, channelID
ORDER BY DATEFROMPARTS(YEAR(Trandate), MONTH(Trandate), 1)
Result:
YearT branch channelID TAmount TranT
2019-05-31 2 1 4200 2
2019-10-31 10 2 24000 2
2019-11-30 7 4 4400 1
2020-02-29 2 4 2500 1
2020-03-31 2 1 6200 2

Return value in a table based on nearest date in another SQL

I apologize if the title is ambiguous, but I couldn't think of a better way to distill down my objective.
I have two tables: AcctProdHist ph and AcctBalHist bh that I have aliased ph and bh, respectively. AcctProdHist has the product history for an account and its productdate. AcctBalHist contains a history of the account balance by date balance changed balancedate.
I am trying to find the balance in AcctBalHist for the balancedate nearest the productdate in AcctProdHist. There are two situations:
ProductDate is between 2 BalanceDates, so I need the balance for the lesser of the two dates
ProductDate is less than the min(BalanceDate)
Here is my code for combining both tables and getting a full balance history:
select
ph.acctnbr,
ph.product,
ph.productdate,
bh.balancedate,
bh.balance
from AcctProdHist ph, AcctBalHist bh
where ((ph.acctnbr = bh.acctnbr(+)))
and ph.acctnbr in (12345,67890)
Here are the results:
ACCTNBR Product ProductDate BalanceDate Balance
12345 BYBU 7/16/2018 8/1/2018 550
12345 BYBU 7/16/2018 7/31/2018 510
12345 BYBU 7/16/2018 7/12/2018 500
12345 BYBU 7/16/2018 7/11/2018 460
12345 BYBU 7/16/2018 7/2/2018 450
67890 ABAU 7/20/2018 8/5/2018 103
67890 ABAU 7/20/2018 8/1/2018 102
67890 ABAU 7/20/2018 7/31/2018 101
67890 ABAU 7/20/2018 7/22/2018 100
In this case, the Balance I want for ACCTNBR 12345 is 500. The Balance I want for ACCTNBR 67890 is 100.
I'm guessing i'll have to do a UNION query as i'm working with two different situations, but I don't even know where to start.
Thanks!
EDIT: Adding Sample Data from the individual tables.
AcctProdHist
ACCTNBR Product ProductDate InactiveDate
12345 ATRU 5/1/2016 7/16/2018
12345 BYBU 7/16/2018
67890 ABAU 7/20/2018
AcctBalHist
ACCTNBR BalanceDate Balance
12345 1/1/2018 225
12345 2/6/2018 268
12345 4/20/2018 315
12345 6/1/2018 400
12345 7/2/2018 450
12345 7/11/2018 460
12345 7/12/2018 500
12345 7/31/2018 510
12345 8/1/2018 550
67890 7/22/2018 100
67890 7/31/2018 101
67890 8/1/2018 102
You must rank your rows. Use ROW_NUMBER for this, giving the closest balance record #1:
select
acctnbr,
product,
productdate,
balancedate,
balance,
from
(
select
ph.acctnbr,
ph.product,
ph.productdate,
bh.balancedate,
bh.balance,
row_number() over (partition by ph.acctnbr
order by case when ph.productdate >= bh.balancedate then 1 else 2 end,
abs(ph.productdate - bh.balancedate)
) as rn
from AcctProdHist ph
left join AcctBalHist bh on bh.acctnbr = ph.acctnbr
where ph.acctnbr in (12345,67890)
)
where rn = 1
order by acctnbr;

Incremental count in SQL Server 2005

I am working with a Raiser's Edge database using SQL Server 2005. I have written SQL that will produce a temporary table containing details of direct debit instalments. Below is a small table containing the key variables for the question I'm going to ask, with some fictional data:
Donor_ID Instalment_ID Instalment_Date Amount
1234 1111 01/01/2011 £5.00
1234 1112 01/02/2011 £0.00
1234 1113 01/03/2011 £5.00
1234 1114 01/04/2011 £5.00
1234 1115 01/05/2011 £0.00
1234 1116 01/06/2011 £0.00
2345 2111 01/01/2011 £0.00
2345 2112 01/02/2011 £5.00
2345 2113 01/03/2011 £5.00
2345 2114 01/04/2011 £0.00
2345 2115 01/05/2011 £0.00
2345 2116 01/06/2011 £0.00
As you will see, some of the values in the Amount column are £0.00. This can occur when a donor has insufficient funds in their account, for example.
What I'd like to do is write a SQL query that will create a field containing an incremental count of consecutive £0.00 payments that resets after a non-£0.00 payment or after a change in Donor_ID. I have reproduced the above data below, with the field I'd like to see.
Donor_ID Instalment_ID Instalment_Date Amount New_Field
1234 1111 01/01/2011 £5.00
1234 1112 01/02/2011 £0.00 1
1234 1113 01/03/2011 £5.00
1234 1114 01/04/2011 £5.00
1234 1115 01/05/2011 £0.00 1
1234 1116 01/06/2011 £0.00 2
2345 2111 01/01/2011 £0.00 1
2345 2112 01/02/2011 £5.00
2345 2113 01/03/2011 £5.00
2345 2114 01/04/2011 £0.00 1
2345 2115 01/05/2011 £0.00 2
2345 2116 01/06/2011 £0.00 3
To help clarify what I'm looking for, I think what I'm looking to do would be similar to a winning streak field on a list of a football team's results. For example:
Opponent Score Winning_Streak
Arsenal 1-0 1
Liverpool 0-0
Swansea 3-1 1
Chelsea 2-1 2
Fulham 4-0 3
Stoke 0-0
Man Utd 1-3
Reading 2-1 1
I've considered various options, but have made no progress. Unless I've missed something obvious, I think that a solution more advanced than my current SQL programming level might be required.
If I am thinking about this problem correctly, I believe that you want a row number when the Amount is 0.00 pounds.
Select 0 as As InsufficientCount
, Donor_ID
, Installment_ID
, Amount
From [Table]
Where Amount > 0.00
Union
Select Row_Number() Over (Partition By Donor_ID Order By Installment_ID)
, Donor_ID
, Installment_ID
, Amount
From [Table]
Where Amount = 0.00
This union select should only give you 'ranks' where the Amount equals 0.
Am calling your new field streakAmount
ALTER TABLE instalments ADD streakAmount int NULL;
Then, to update the value:
UPDATE instalments
SET streakAmount =
(SELECT
COUNT(*)
FROM
instalments streak
WHERE
streak.donor_id = instalments.donor_id
AND
streak.instalment_date <= instalments.instalment_date
AND
(streak.instalment_date >
-- find previous instalment date, if any exists
COALESCE(
(
SELECT
MAX(instalment_date)
FROM
instalments prev
WHERE
prev.donor_id = instalments.donor_id
AND
prev.amount > 0
AND
prev.instalment_date < instalments.instalment_date
)
-- otherwise min date
, cast('1753-1-1' AS date))
)
)
WHERE
amount = 0;
http://sqlfiddle.com/#!6/a571f/18