Show account balance from multiple tables - sql

I am having following two table which stores information about Credit and Debit records.
voucherCr table contains
voucherType voucherPrefix voucherNo crparty cramount
SALES S 1 1 43000
SALES S 2 1 10000
voucherDr table contains
voucherType voucherPrefix voucherNo drparty dramount
SALES S 1 5 43000
SALES S 2 5 10000
Now here, in SALES voucher S/1, party 1 has been credit with 43000 amount agains party 5 of same amount. Same is with SALES voucher S/2, where party 1 has been credited with 10000 amount against party 5 of same amount.
Now I want to display results as follows If i query about party 1
PARTY CREDIT DEBIT DEBITPARTY voucherType voucherPrefix voucherNo
1 43000 5 SALES S 1
1 10000 5 SALES S 2
Please help

Try to use this query. Is it possible in your case that one dramount is divided to many rows in voucherDr? For example 43000->40000+3000
select
vc.Party,vc.CrAmount, vd.drAmount, vd.drparty,
vc.voucherType, vc.voucherPrefix, vc.voucherNo
from voucherCr vc
left join voucherDr vd on (vc.voucherType=vd.voucherType)
and (vc.voucherPrefix=vd.voucherPrefix)
and (vc.voucherNo=vd.voucherNo)
where vc.PARTY=1

If i have understood your question properly then this is what you are looking for
Select c.crParty as Party, d.dramount as credit , null as debit,
d.drParty as DEBITPARTY,c.voucherType as voucherType,
d.voucherPrefix,d.voucherNo
from VoucherCr as c inner join VoucherDr as d
on c.voucherNo=d.VoucherNo and c.voucherPrefix=d.voucherPrefix
where c.crparty=1
group by d.dramount,c.cramount,d.voucherPrefix,d.voucherNo,c.crParty,
c.voucherType,d.drParty
order by d.dramount desc
Try SQLFIDDLE

Related

Joining tables and aggregation/sub queries

I have 2 tables as show below.
Table1
Order ID
Item_code
Sales_Price
Qty_ordered
Total
Qty shipped
1000
111
10
5
$50
1
1000
222
20
10
$200
2
1000
333
30
15
$450
0
I have another table that stores only the details of how much was invoiced (i.e. how much we shipped)
Table2 (because we shipped only 10x1 and 20x2 = $50)
Order ID
Invoice_total
1000
$50
I wrote the following query,
select T1.Order_ID,
sum(T1.Qty_Ordered) as Qty_Ordered,
sum(T1.Total) as Total_Amt_ordered,
sum(T1.Qty_shipped) as Qty_Shipped,
sum(T2.Invoice_total)
from T1 join
T2 on T1.Order_ID = T2.Order_ID
This query gives me the following output, (It is adding $50 to all the rows of T1 Orders).
Order ID
Qty_ordered
Total
Qty shipped
Invoice_total
1000
30
$700
3
$150
Whereas now, I want my output to be as:
Order ID
Qty_ordered
Total
Qty shipped
Invoice_total
1000
30
$700
3
$50
(because we shipped only $50)
What changes should I make to my query?
I know I can just hard code it but my database has 1000's of orders and 1000's of Half shipped Orders. I want to keep track of Shipped $ (Invoiced $) for all the orders.
If I understand correctly, you want:
select T2.Order_ID, T2.Invoice_total,
sum(T1.Qty_Ordered) as Qty_Ordered,
sum(T1.Total) as Total_Amt_ordered,
sum(T1.Qty_shipped) as Qty_Shipped,
from T2 join
T1
on T1.Order_ID = T2.Order_ID
group by T2.Order_ID, T2.Invoice_total;
That is, you don't want to aggregate Invoice_total. You just want it to be a group by key.

Fetch all the rows without having a duplicate value in a particular field

id
ticket_number
payment_status
1
100
paid
2
121
paid
3
132
paid
4
100
refund
5
141
paid
The above is a sample database table. I want to fetch all id and ticket number without having payment_status == refund. What is the SQL query for this. I want to show only the ticket number without having refund.
output should be:
id
ticket_number
payment_status
2
121
paid
3
132
paid
5
141
paid
One method is not exists:
select t.*
from t
where not exists (select 1
from t t2
where t2.ticket_number = t.ticket_number and
t2.status = 'refund'
);
The best way is you can take the count of each unique ticket_number, and select all the ticket number whose count is less than 2.

What is the most appropriate logic to add rows in table

I have following table structure (simplified to make essential things clear), which lists Top 3 bank customers in each category of loan and branch of the bank. SNO column is rank of the customer, value of which is up to 3.
Loan Category
SNO
Branch
Customer Name
Amount
Home Loan
1
abc
Piyush
10000
Home Loan
2
abc
Shyam
5000
Home Loan
3
abc
Kamal
2000
Home Loan
1
xyz
Xman
50000
Home Loan
2
xyz
Shyam
20000
Auto Loan
1
abc
Birendra
10000
Personal Loan
1
xyz
Gyan
5000
Personal Loan
2
xyz
Prakash
2000
I am trying to make another table such that, If there are less than 3 customers in each loan category and branch, Insert a dummy row for each branch and category with values of customer name and amount as NULL.
Essentially, I am trying to get following table.
Loan Category
SNO
Branch
Customer Name
Amount
Home Loan
1
abc
Piyush
10000
Home Loan
2
abc
Shyam
5000
Home Loan
3
abc
Kamal
2000
Home Loan
1
xyz
Xman
50000
Home Loan
2
xyz
Shyam
20000
Home Loan
3
xyz
added row
Auto Loan
1
abc
Birendra
10000
Auto Loan
2
abc
added row
Auto Loan
3
abc
added row
Auto Loan
1
xyz
added row
Auto Loan
2
xyz
added row
Auto Loan
3
xyz
added row
Personal Loan
1
xyz
Gyan
5000
Personal Loan
2
xyz
Prakash
2000
Personal Loan
3
xyz
added row
Personal Loan
1
abc
added row
Personal Loan
2
abc
added row
Personal Loan
3
abc
added row
I have solved this problem by using Loop iterating over all category and branch and inserting dummy row, if max(sno) < 3 for each category/branch. But, I am looking for appropriate logic without iterating over all category and branch. In my actual table, there are thousands of branch values and more than 100 categories. So, iterating over all combination of category and branch is very expensive in terms of performance.
I need to write some good logic preferably using SQL constructs only or not using any loop.
Ok. So you must have some tables where branch and category is listed in single or multiple tables. Lets take it as your branch and category tables and you must have some query which produced the result mentioned in the question. Lets call it your_query.
You need to generate 3 records per branch per category.
Select c.category as loan_category,
L.lvl as sno,
B.branch,
Q.cutomername,
Q.amount
From category c
Cross join branch b
Cross Join (select level lvl from dual connect by level <= 3) l
Left Join your_query q on q.branch = c.branch
and q.category = c.category
and l.lvl = q.sno
Ordet by c.category, B.branch, L.lvl

Need to group records based on matching reversal in sql

I have a tricky scenario to aggregate the data.
Data in my source table is as follows.
CustomerId Transaction Type Transaction Amount
1 Payment 100
1 ReversePayment -100
1 payment 100
1 ReversePayment -100
1 Payment 100
1 Payment 100
Requirement is as follows:
If the payment as a assoociated Reversepayment with matched amount, sum these two records.
If the payment does not have an associated Reverse payment, consider it as orphan(dont sum it).
I want output to be like this.
CustomerId Transaction Type Transaction Amount
1 Payment,ReversePayment 0
1 payment,ReversePayment 0
1 payment 100
1 Payment 100
In this scenario,
First record which is payment has an associated reverse payment (2nd record), Hence the sum becomes 0
Third record which is payment has an associated reverse payment (4th record), then the sum becomes 0
Fifth and sixth does not have associated reversals. dont sum these records.
Second Example:
Data in the source as follows:
CustomerId Transaction Type Transaction Amount
1 Payment 100
1 ReversePayment -100
1 payment 300
1 ReversePayment -300
1 Payment 400
1 Payment 500
Expected Output
CustomerId Transaction Type Transaction Amount
1 Payment,ReversePayment 0
1 payment,ReversePayment 0
1 payment 400
1 Payment 500
Second example requirement:
-As first and second records (payment and its associated reverse payment got
matched) ,sum these two records, output is 0.
- As third and fourth records (payment and its associated reverse payment got
matched), sum these two records, output is 0.
- Fifth and sixth does not have associated reversals. don't sum these records.
I got solutions in group, but data is not always guaranteed to have orphan records as 'payments'. Some times they are 'Payments' and some times they are 'ReversePayments'. Can some help me get ouptut like the below (using rank or rownumber functions ) so that i can group by using RRR column.
CustomerId Transaction Type Transaction Amount RRR
1 Payment 100 1
1 ReversePayment -100 1
1 payment 100 2
1 ReversePayment -100 2
1 Payment 100 3
1 Payment 100 4
CustomerId Transaction Type Transaction Amount RRR
1 Payment 100 1
1 ReversePayment -100 1
1 payment 300 2
1 ReversePayment -300 2
1 Payment 400 3
1 Payment 500 4
You can enumerate the different types and then aggregate:
select customerid,
listagg(ttype, ',') within group (order by ttype) as types,
sum(amount) as amount
from (select t.*,
row_number() over (partition by customerid, ttype, amount order by customerid) as seqnum
from t
) t
group by customerid, seqnum;
Edited to include your second scenario:
Using rownum to enforce inherent ordering (i.e. transactions happened in the order you've listed ), since your example is missing a transaction id or transaction time
SQL> select * from trans_data2;
CUSTOMER_ID TRANSACTION_TY TRANSACTION_AMOUNT
----------- -------------- ------------------
1 Payment 100
1 ReversePayment -100
1 payment 300
1 ReversePayment -300
1 Payment 400
1 Payment 500
6 rows selected.
SQL> select customer_id,
2 case
3 when upper(next_transaction) = 'REVERSEPAYMENT' then transaction_type||','||next_transaction
4 else transaction_type
5 end transaction_type,
6 case
7 when upper(next_transaction) = 'REVERSEPAYMENT' then transaction_amount + next_transaction_amount
8 else transaction_amount
9 end transaction_amount
10 from (
11 select customer_id, transaction_type, transaction_amount,
12 lead (transaction_type) over ( partition by customer_id order by transaction_id ) next_transaction,
13 nvl(lead (transaction_amount) over ( partition by customer_id order by transaction_id),0) next_transaction_amount
14 from ( select rownum transaction_id, t.* from trans_data2 t )
15 ) where upper(transaction_type) = 'PAYMENT'
16 ;
CUSTOMER_ID TRANSACTION_TYPE TRANSACTION_AMOUNT
----------- ----------------------------- ------------------
1 Payment,ReversePayment 0
1 payment,ReversePayment 0
1 Payment 400
1 Payment 500

Performing calculations based on dates in oracle

I have the following tables.
Accounts(account_number*,balance)
Transactions(account_number*,transaction_number*,date,amount,type)
Date is the date that the transaction happened. Amount is the amount of the transaction
and it can have a positive or a negative value, dependent of the type(Withdrawal -,Deposit +). I think the type is irrelevant here as the amount is already given in the proper way.
I need to write a query which points out the account_number of the accounts that have at least once had negative balance.
Here's some sample data from the Transactions table, ordered by account_number and date.
account_number transaction_number date amount type
--------------------------------------------------------------------
1 2 02/03/2013 -20000 withdrawal
1 3 03/15/2013 300 deposit
1 1 01/01/2013 100 deposit
2 1 04/15/2013 235236 deposit
3 1 06/15/2013 500 deposit
4 1 03/01/2013 10 deposit
4 2 04/01/2013 80 deposit
5 1 11/11/2013 10000 deposit
5 2 12/11/2013 20000 deposit
5 3 12/13/2013 -10002 withdrawal
6 1 03/15/2013 102300 deposit
7 1 03/15/2013 100 deposit
8 1 08/08/2013 133990 deposit
9 1 05/09/2013 10000 deposit
9 2 06/01/2013 300 deposit
9 3 10/11/2013 23 deposit
Something like this with an analytic to keep a running balance for an account:
SELECT DISTINCT account_number
FROM ( SELECT account_number
,SUM(amount)
OVER (PARTITION BY account_number ORDER BY date) AS running_balance
FROM transactions
) x
WHERE running_balance < 0
Explanation:
It is using an analytic function: the PARTITION BY breaks the table into groups identified by the account number. Within each group, the data is ordered by date. Then there is a walk through each element in the ordered group and the SUM function is applied (by default summing everything from the beginning of the group to the current row). This gives you a running balance. Just run the inner query on its own and take a look at the output, then read a bit about analytic queries. They are pretty cool.