Sql Case Column 1 and Column same value then apply calculation - sql

I would like apply calculation in CASE Statement, but the result is not I'm expected and I'm not sure how to apply the query to filter date(depend on month). What is the problem with my query?? Please help... Thank you
this is my query
SELECT DISTINCT a.SERVICE_CODE,
CASE WHEN
b.SERVICE_CODE IS NULL THEN a.AMT ELSE SUM (a.AMT) - SUM(b.AMT) END AS TOTAL_AMT
FROM Table a
LEFT OUTER JOIN Table b ON (a.SERVICE_CODE = b.SERVICE_CODE)
WHERE b.SERVICE_CODE >='3000' AND c.SERVICE_CODE >='3000'
Table a
Invoice_No date Service_code Amt
001 1/7/2014 6000 300
002 1/8/2014 6003 700
003 5/8/2014 6003 100
004 10/8/2014 6005 1000
Table b
Credit_No date Service_code Amt
c100 1/7/2014 6000 300
c200 13/8/2014 6003 700
Desired output
Service_code Total_Amt
6003 100
6005 1000
Thank you

try like this
In MYSQL
select t1.SERVICE_CODE,(t1.amt- case when c.amt is null then 0 else c.amt end)
as AMT from t1 c right outer join (select t.Invoice_No,SERVICE_CODE,
sum(amt) as amt from t group by SERVICE_CODE) as t1
on c.SERVICE_CODE=t1.SERVICE_CODE
inner join tablea a on a.invoice_no=t1.Invoice_No
Fiddle

Try this:
select
bcode,
case
when ccode is null then bamt
else bamt - camt
end as amt
from
(select service_code bcode, sum(amt) bamt
from b
where service_code >= 3000
group by service_code) b
left join
(select service_code ccode, sum(amt) camt
from c
where service_code >= 3000
group by service_code) c on b.bcode = c.ccode
order by bcode
Going by sample data, table b may have values for service_code that table c may not. Therefore, use a left outer join to link b and c. Also, since invoice_no does not need to appear in the output, you do not need to join to a at all.
Demo

Related

SQL query to select columns from multiple tables with conditions on Group By

I have 3 Tables with relationships:
TableA:
Party_Number Account_Number Email_Code Relation_Code
1111 A00071 null B
1111 A00071 null C
1111 A00071 null D
1111 A00072 140 D
1111 A00073 140 C
1111 A00074 140 C
1111 A00075 null B
TableB:
Account_Number Date
A00071 8/8/2020
A00072 null
A00073 null
A00074 null
A00075 null
TableC:
Party_Number Email
1111 abc#gmail.com
I need to join 3 tables to get the following result (only records where "Relation_Code" is 'C' or 'D'):
Party_Number Account_Number Email_Code Relation_Code Date Email
1111 A00071 null C 8/8/2020 abc#gmail.com
1111 A00071 null D 8/8/2020 abc#gmail.com
1111 A00072 140 D null abc#gmail.com
1111 A00073 140 C null abc#gmail.com
1111 A00074 140 C null abc#gmail.com
I wrote this query to get the result:
Select A.Party_Number, A.Account_Number, A.Relation_Code, A.Email_Code,
B.Date, C.Email
from TableA A, TableB B, TableC C
Where A.Account_Number= B.Account_Number
AND A.Party_Number = C.Party_Number
AND A.Relation_Code in ('C','D')
Order By A.Account_Number
But there can be rows with same Account_Number, but different Relation_Code ('C' and 'D'). For ex (A00071).
If there are duplicate Account_Number, I need to select only Account_Number where Relation_Code is 'D'.
How do I write a SQL query to join multiple tables and group by a condition?
Use standard joins! This helps formulating the logic and separating the joining conditions from other filtering predicates.
Here, it seems like, starting from a filtered on column relation_code, you want to allow "missing" relationships in b and c. We would phrase it with left joins:
select a.party_number, a.account_number, a.relation_code, a.email_code,
b.date, c.email
from tablea a
left join tableb b on b.account_number = a.account_number
left join tablec c on c.party_number = a.party_number
where a.relation_code in ('C','D')
order by a.account_number
If there are duplicate Account_Number, I need to select only Account_Number where Relation_Code is 'D'.
For this, we could use window functions to pre-filter a:
select a.party_number, a.account_number, a.relation_code, a.email_code,
b.date, c.email
from (
select a.*,
row_number() over(partition by account_number order by relation_code desc) rn
from tablea a
where relation_code in ('C','D')
) a
left join tableb b on b.account_number = a.account_number
left join tablec c on c.party_number = a.party_number
where a.rn = 1
order by a.account_number

SQL Select Distinct Records From Two Tables

I am trying to write a SQL statement that will return a set of Distinct set of CompanyNames from a table based on the most recent SaleDate withing a specified date range from another table.
T01 = Account
T02 = TransHeader
The fields of importance are:
T01.ID, T01.CompanyName
T02.AccountID, T02.SaleDate
T01.ID = T02.AccountID
What I want to return is the Max SaleDate for each CompanyName without any duplicate CompanyNames and only the Max(SaleDate) as LastSale. I will be using a Where Clause to limit the SaleDate range.
I tried the following but it returns all the records for all SalesDates in the range. This results in the same company being listed multiple times.
Current MS-SQL Query
SELECT T01.CompanyName, T02.LastSale
FROM
(SELECT DISTINCT ID, IsActive, ClassTypeID, CompanyName FROM Account) T01
FULL OUTER JOIN
(SELECT DISTINCT AccountID, TransactionType, MAX(SaleDate) LastSale FROM TransHeader group by AccountID, TransactionType, SaleDate) T02
ON T01.ID = T02.AccountID
WHERE ( ( T01.IsActive = 1 )AND
( (Select Max(SaleDate)From TransHeader Where AccountID = T01.ID AND TransactionType in (1,6) AND SaleDate is NOT NULL)
BETWEEN '01/01/2016' AND '12/31/2018 23:59:00' AND (Select Max(SaleDate)From TransHeader Where AccountID = T01.ID AND TransactionType in (1,6) AND SaleDate is NOT NULL) IS NOT NULL
)
)
ORDER BY T01.CompanyName
I thought the FULL OUTER JOIN was the ticket but it did not work and I am stuck.
Sample data Account Table (T01)
ID CompanyName IsActive ClassTypeID
1 ABC123 1 1
2 CDE456 1 1
3 EFG789 1 1
4 Test123 0 1
5 Test456 1 1
6 Test789 0 1
Sample data Transheader table (T02)
AccountID TransactionType SaleDate
1 1 02/03/2012
2 1 03/04/2013
3 1 04/05/2014
4 1 05/06/2014
5 1 06/07/2014
6 1 07/08/2015
1 1 08/09/2016
1 1 01/15/2016
2 1 03/20/2017
2 1 03/21/2017
3 1 03/04/2017
3 1 04/05/2018
3 1 05/27/2018
4 1 06/01/2018
5 1 07/08/2018
5 1 08/01/2018
5 1 10/11/2018
6 1 11/30/2018
Desired Results
CompanyName LastSale (Notes note returned in the result)
ABC123 01/15/2016 (Max(SaleDate) LastSale for ID=1)
CDE456 03/21/2017 (Max(SaleDate) LastSale for ID=2)
EFG789 05/27/2018 (Max(SaleDate) LastSale for ID=3)
Testing456 10/11/2018 (Max(SaleDate) LastSale for ID=5)
ID=4 & ID=6 are note returned because IsActive = 0 for these records.
One option is to select the maximum date in the select clause.
select
a.*,
(
select max(th.saledate)
from transheader th
where th.accountid = a.id
and th.saledate >= '2016-01-01'
and th.saledate < '2019-01-01'
) as max_date
from account a
where a.isactive = 1
order by a.id;
If you only want to show transaction headers with sales dates in the given date range, then you can just inner join the maximum dates with the accounts. In order to do so, you must group your date aggregation per account:
select a.*, th.max_date
from account a
join
(
select accountid, max(saledate) as max_date
from transheader
and saledate >= '2016-01-01'
and saledate < '2019-01-01'
group by accountid
) th on th.accountid = a.id
where a.isactive = 1
order by a.id;
select CompanyName,MAX(SaleDate) SaleDate from Account a
inner join Transheader b on a.id = b.accountid
group by CompanyName
order by 1

How to Sum previos rows summatory to find a balance in SQL Server

I'm working on a service that needs to calculate how much a customer owes, according to a total invoice value and the partial payments that the customer has made.
So, in a tableA I have a row with the invoice total value:
[dbo].[TableA]
ID CustomerId InvoiceVal
1 12 1000
2 11 2000
3 10 5000
4 14 15000
5 12 100
6 16 8000
7 18 3200
In a TableB I have the record of each customer's partial payments they have made to each invoice:
[dbo].[TableB]
ID InvoiceId Payment
1 1 150
2 3 50
3 1 120
4 1 100
5 5 90
6 4 7500
So, as you can see, the customer 12 has an invoice for $1000 and has made 3 payment that sum $370
I need to be able to se the partial total owed in each row, this is the expected result:
No. InoviceId CustomerId Payment Owed
1 1 12 150 850
2 1 12 120 730
3 1 12 100 630
So far, this is my code:
DECLARE #invid int = '1'
DECLARE #invoicetotal numeric(18,2)
SET #invoicetotal =
(
SELECT
[dbo].[TableA].[InvoiceVal]
FROM [dbo].[TableA]
WHERE
([dbo].[TableA].[ID] = #invid)
)
SELECT
*,
SUM(#invoicetotal - [dbo].[TableB].[Payment]) OVER(ORDER BY [dbo].[TableB].[ID] ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) AS [Owed]
FROM [dbo].[TableB]
WHERE
([dbo].[TableB].[InvoiceId] = #invid)
But this is what I get:
ID InvoiceId Payment Owed
1 1 150.00 NULL
3 1 120.00 850.00
4 1 100.00 1730.00
I need to sum the previous payment on each row.
Thanks!
Something like this would help
SELECT
ROW_NUMBER() OVER (ORDER BY TableB.ID ASC) NO,
CustomerId,
Payment,
InvoiceVal - SUM(Payment) OVER (PARTITION BY TableA.ID ORDER BY TableB.Id ASC) Owed
FROM TableA
INNER JOIN TableB
ON TableA.Id = TableB.InvoiceId
WHERE
CustomerId = 12
Working Fiddle
Your query will depend on what you are trying to make as your final output.
If you want just ONE CustomerID, go with:
SELECT a.ID AS InvoiceID, a.CustomerID, a.InvoiceVal AS StartInvoice
, b.ID AS bid, b.Payment
, a.InvoiceVal - ISNULL(SUM(b.Payment) OVER (PARTITION BY a.ID ORDER BY b.id),0) AS owed
FROM TableA a
LEFT OUTER JOIN TableB b ON a.ID = b.InvoiceID
WHERE a.CustomerID = 12
And if that CustomerID doesn't have any payments, you want to use a LEFT JOIN so that you don't eliminate an amount owed.
SELECT a.ID AS aid, a.CustomerID, a.InvoiceVal AS StartInvoice
, b.ID AS bid, b.Payment
, a.InvoiceVal - ISNULL(SUM(b.Payment) OVER (PARTITION BY a.ID ORDER BY b.id),0) AS owed
FROM TableA a
LEFT OUTER JOIN TableB b ON a.ID = b.InvoiceID
WHERE a.CustomerID = 11
I also added an ISNULL() around Payment to keep from nulling out your owed amount. It could also be added to the InvoiceVal to account for a CustomerID who hasn't been invoiced yet, if that was needed (or possible from other tables).
IF you want to get ALL CustomerIDs, you'll have to account for that in your partition.
SELECT s1.CustomerID, aid AS InvoiceID, s1.bid, s1.Payment
, (s1.StartInvoice - s1.runningPayment) AS Owed
FROM (
SELECT a.ID AS aid, a.CustomerID, a.InvoiceVal AS StartInvoice
, b.ID AS bid, b.Payment
, ISNULL(SUM(b.Payment) OVER (PARTITION BY a.CustomerID, a.ID ORDER BY b.id),0) AS runningPayment
FROM TableA a
LEFT OUTER JOIN TableB b ON a.ID = b.InvoiceID
) s1
ORDER BY s1.CustomerID, s1.aid, s1.bid
Fiddle demonstrates overpayment or paying total balance for 0 owed.

Calculate the sum of group in a table and joining on other table sql

i have two tables in sql.
table_team
t_id team_name
1 ABC
2 XYZ
3 PQR
i have another table_player
p_id t_id player_name payment
10 1 Sam 1000
20 1 jon 500
30 2 will 680
40 1 bob 700
50 3 rob 890
i want to get the team's total payment from these two tables.
i'e sum of payemnt of each player in a particular team, and for all teams.
i thought of trying
select t_id,team_name,sum(b.payment) as total_payment from table_team a
left join table_player b on a.t_id = b.t_id
Join to a subquery which computes the total payment for each team:
SELECT t1.t_id, t1.team_name, t2.total_payment
FROM table_team t1
INNER JOIN
(
SELECT t_id, SUM(payment) AS total_payment
FROM table_player
GROUP BY t_id
) t2
ON t1.t_id = t2.t_id
-- WHERE t1.team_name IN ('ABC', 'XYZ')
select t_id,team_name,sum(b.payment) as total_payment
from table_team a
left join table_player b on a.t_id = b.t_id
group by t_id,team_name
select t_id,team_name,sum(isnull(b.payment,0)) as total_payment from table_team a
left join table_player b on a.t_id = b.t_id
group by t_id, team_name
Just add a group by and it should work

How to SUM Only One Time Per UniqueId in SQL?

I have two tables that look roughly like this:
Table A
DocumentId (*is unique) DocumentDate
1 2016-01-01
2 2016-01-01
3 2016-02-01
4 2016-03-01
and Table B
ContractId SnapshotTimeId NetFinanced
1 20160231 300
1 20160331 300
1 20160431 300
2 20160231 450
2 20160331 450
2 20160431 450
3 20160331 500
3 20160431 500
4 20160431 150
I would like the final table to look something like this:
DocumentDate NetFinanced
2016-01-01 750
2016-02-01 500
2016-03-01 150
I have tried the following and it doesn't work:
SELECT A.DocumentDate, SUM(B.NetFinanced)
FROM A
JOIN B on B.ContractId=A.DocumentId
GROUP BY A.DocumentDate
Any ideas? Thanks in advance
you can use distinct
SELECT A.DocumentDate,
SUM(B.NetFinanced)
FROM A
JOIN (SELECT DISTINCT
ContractId,
NetFinanced
FROM B
) B ON B.ContractId = A.DocumentId
GROUP BY A.DocumentDate
the result of this will be different if the NetFinanced amount changes per SnapshotTimeId
if you want the most recent NetFinanced amount, you can use Row_number() to order the values.
SELECT A.DocumentDate,
SUM(B.NetFinanced)
FROM A
JOIN (SELECT ROW_NUMBER() OVER (PARTITION BY ContractId ORDER BY SnapshotTimeId DESC) Rn,
ContractId,
NetFinanced
FROM B
) B ON B.ContractId = A.DocumentId AND B.Rn = 1
GROUP BY A.DocumentDate
You have duplicate values for NetFinanced in TableB, of course the results won't give you what you want. You need to join TableA with the unique values (I assume) of ContractId and NetFinanced columns from TableB:
SELECT A.DocumentDate,
SUM(B.NetFinanced) NetFinanced
FROM dbo.TableA A
INNER JOIN (SELECT DISTINCT ContractId, NetFinanced
FROM dbo.TableB) B
ON A.DocumentId = B.ContractId
GROUP BY A.DocumentDate;
Try Like this
SELECT A.DocumentDate, SUM(B.NetFinanced)
FROM A
JOIN (SELECT MAX(ContractId) ContractId, MAX(SnapshotTimeId)SnapshotTimeId,
MAX(NetFinanced)NetFinanced
FROM B GROUP BY ContractId) B ON B.ContractId = A.DocumentId
GROUP BY A.DocumentDate