query that is splitting a column into two - sql

Hello I have an ID column and an amount column at the moment.
A value is represented as a Debit if the amount is positive. A credit if the amount is negative. I'm wondering how can I "Split" my amount column.
Select * from Test.dbo.Accounts
Produces
ID | Amount
1 | 500
2 | -600
So Item 1 is a Debit, Item two is a credit. I want to query the Database so that it displays as followed
ID | Debit | Credit
1 | 500 | null
2 | null |-600

You can use a case statement to find which column the amount belongs in:
SELECT id ,
CASE WHEN amount >= 0 THEN amount
ELSE NULL
END AS debit ,
CASE WHEN amount < 0 THEN amount
ELSE NULL
END AS credit
FROM Test.dbo.Accounts
I assumed 0 should go in debits but that'd be your call.

Select ID, Amount as Debit, null as Credit
From Account
Where Amount >= 0
Union All
Select ID, null as Debit, Amount as Credit
From Account
Where Amount < 0

Related

Transforming a dataset containing bank transactions into SQL Server

I would like to transform a dataset containing some bank transactions.
The ultimate goal is to make a report in Power BI to track daily expenses.
For this, I have the following situation that gives me a headache. :)
This is an example:
Date
Transaction_Details
Debit
Credit
21 Jan 2023
Transfer HomeBank
500
NULL
NULL
Reference: 4944
NULL
NULL
NULL
Beneficiary: David John
NULL
NULL
NULL
In Bank Account: RO97INGB1111333380218
500
NULL
20 Jan 2023
POS Payment
36
NULL
NULL
Card number: xxxx xxxx xxxx 1020
NULL
NULL
NULL
Terminal: OZKARDES A/S
NULL
NULL
NULL
Date: 19-01-2023
NULL
NULL
The desired output would be to transpose all rows in Transaction_Details that have NULL values in Date column, into a new column (e.g Other_Details) and for each transaction to add another column with "Transaction_Key".
Below, I have attached an example:
Transaction_Key
Date
Transaction_Details
Other_Details
Debit
Credit
1
21 Jan 2023
Transfer HomeBank
Reference: 4944, Beneficiary: David John, In Bank Account: RO97INGB1111333380218
500
NULL
2
20 Jan 2023
POS Payment
Card number: xxxx xxxx xxxx 1020, Terminal: OZKARDES A/S, Date: 19-01-2023
36
NULL
I used some COALESCE functions but it didn't work.
If we can assume you are able to create an Id/Sequence either in the data source or when importing the data, such that you end up with an incrementing number per row, then by using a windowed aggregation as follows you can convert your data as required:
select Transaction_Key,
Max(Date) Date,
Max(case when date is not null then Transaction_Details end) Transaction_Details,
String_Agg(case when date is null then Transaction_Details end, ',') Other_details,
Max(case when date is not null then Debit end) Debit,
Max(case when date is not null then Credit end) Credit
from (
select *,
Sum(case when date is null then 0 else 1 end) over(order by id) as Transaction_Key
from t
)t
group by Transaction_Key;
See this example Fiddle

How to convert values in a field to different fields in Google Big Query?

I have two distinct values in a field and some aggregates based on that, how would I convert these values into two different fields and then have the aggregates accordingly.
What I have:
user_id status amount
101 deposit 100
101 credit 300
101 deposit 700
102 deposit 1000
102 credit 200
102 credit 500
What I want:
user_id credit deposit
101 300 800
102 700 1000
Could anyone please help me on this.
SELECT user_id,
SUM(CASE WHEN status='credit' THEN amount ELSE 0 END) credit,
SUM(CASE WHEN status='deposit' THEN amount ELSE 0 END) deposit
FROM src_table
GROUP BY user_id

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

SQL Query to get sums among multiple payments which are greater than or less than 10k

I am trying to write a query to get sums of payments from accounts for a month. I have been able to get it for the most part but I have hit a road block. My challenge is that I need a count of the amount of payments that are either < 10000 or => 10000. The business rules are that a single payment may not exceed 10000 but there can be multiple payments made that can total more than 10000. As a simple mock database it might look like
ID | AccountNo | Payment
1 | 1 | 5000
2 | 1 | 6000
3 | 2 | 5000
4 | 3 | 9000
5 | 3 | 5000
So the results I would expect would be something like
NumberOfPaymentsBelow10K | NumberOfPayments10K+
1 | 2
I would like to avoid doing a function or stored procedure and would prefer a sub query.
Any help with this query would be greatly appreciated!
I suggest avoiding sub-queries as much as possible because it hits the performance, specially if you have a huge amount of data, so, you can use something like Common Table Expression instead. You can do the same by using:
;WITH CTE
AS
(
SELECT AccountNo, SUM(Payment) AS TotalPayment
FROM Payments
GROUP BY AccountNo
)
SELECT
SUM(CASE WHEN TotalPayment < 10000 THEN 1 ELSE 0 END) AS 'NumberOfPaymentsBelow10K',
SUM(CASE WHEN TotalPayment >= 10000 THEN 1 ELSE 0 END) AS 'NumberOfPayments10K+'
FROM CTE
You can get the totals per account using SUM and GROUP BY...
SELECT AccountNo, SUM(Payment) AS TotPay
FROM payments
GROUP BY AccountNo
You can use that result to count the number over 10000
SELECT COUNT(*)
FROM (
SELECT AccountNo, SUM(Payment) AS TotPay
FROM payments
GROUP BY AccountNo
)
WHERE TotPay>10000
You can get the the number over and the number under in a single query if you want but that's a but more complicated:
SELECT
COUNT(CASE WHEN TotPay<=10000 THEN 1 END) AS Below10K,
COUNT(CASE WHEN TotPay> 10000 THEN 1 END) AS Above10K
FROM (
SELECT AccountNo, SUM(Payment) AS TotPay
FROM payments
GROUP BY AccountNo
)

create column in for each different value in the table

Let us say that I have a table structured like this(using SQL server):
empID INT
payment INT
Now, each employee only gets paid either 50.00 or 100.00. There are two employees earning 50.00 and three earning 100.00.
How would I do a select statement so that the result set was like this:
50.00 100
----- -----
2 3
Where 50.00 and 100.00 are the column headers, and the number below are the actual values. I know that I can do
SELECT payment, COUNT(*)
FROM Student
GROUP BY payment
But that returns the payment in its own column. I want each different payment value in its own column.
Here's how:
select sum(case when payment = 50.00 then 1 else 0 end) as num050,
sum(case when payment = 100.00 then 1 else 0 end) as num100
But, with floating point numbers, you should never do equal comparisons. It is better to do something like:
sum(case when abs(payment - 50) < 0.001 then 1 else 0 end)
or something like that.