SQL: how to aggregate value with conditions (CASE WHEN???) - sql

My data has 3 variables, User ID, Transaction Amount, and Transaction Date,
I want to aggregate 2 day transaction amount for each user ID, but with conditions.
The condition is, for example, I want to aggregate 8/31 and 8/30 transaction amount for an ID 12345, if the transaction amount is 0 on 8/31 for this ID, which means this ID does not have any transactions on 8/31, then just ignore this user ID, I'm not going to aggregate amount for this user ID.
If another ID 23456 has transactions on 8/31 and does not have transaction on 8/30, then I will aggregate the transactions on 8/31 for this ID.
If one ID 34567 has transactions on both 8/30 and 8/31, then I will have aggregate the transactions for both 8/30 and 8/31.
How can I do this? I've been struggling for the whole afternoon. Thanks in advance for any suggestions and idea!

Based on your question should be
select user_id, sum(a.transaction_amount + b.transaction_amount).
from my_table as a
inner join my_table as b on date_add(b.transaction_date, interval 1 day) = a.transaction_date
where date(a.transaction_date) = STR_TO_DATE('31,8,2016','%d,%m,%Y')
and a.transaction_amount > 0
group by user_id

SELECT User_ID, SUM(Transaction_Amount)
FROM yourTable
WHERE DATE(Transaction_Date) = '2016-08-30'
OR (DATE(Transaction_Date) = '2016-08-31' AND Transaction_Amount > 0)
GROUP BY User_ID

Just use conditional aggregation:
select userid,
sum(case when date = '2016-08-30' then amount else 0 end) as amt_20160830,
sum(case when date = '2016-08-31' then amount else 0 end) as amt_20160831
from t
group by userid
having sum(case when date = '2016-08-31' then amount else 0 end) > 0;
Exactly what the code looks like might vary by databases, but this is fairly standard SQL.

Seems like you want to return only users which had a transaction on Aug. 31.:
select userid,
sum(trans_amount)
from t
where trans_date between date '2016-08-30' and date '2016-08-31'
group by userid
having max(trans_date) = date '2016-08-31'

Related

Conditional CASE WHEN select snowflake SQL

I am stuck on a conditional snowflake select sql. I am trying to count the IDs when they have the corresponding categorial value. I would appreciate some help.
Thanks
SELECT
YEAR(DATETIME) AS YEAR,
WEEKOVERYEAR(DATETIME) AS WEEK,
COUNT(CASE WHEN ID THEN CATEGORY = 'A')
from table
group by week, year;
Here is one method:
SELECT YEAR(DATETIME) AS YEAR,
WEEKOVERYEAR(DATETIME) AS WEEK,
SUM(CASE WHEN CATEGORY = 'A' THEN 1 ELSE 0 END) as num_a
FROM table
GROUP BY week, year;
Snowflake supports COUNT_IF:
Returns the number of records that satisfy a condition.
Aggregate function
COUNT_IF( <condition> )
SELECT YEAR(DATETIME) AS YEAR,
WEEKOVERYEAR(DATETIME) AS WEEK,
COUNT_IF(CATEGORY = 'A') AS num_a
FROM tab
GROUP BY week, year;
You should / can use IFF() since case when is more suitable when there are multiple conditions.
SELECT
YEAR(DATETIME) AS YEAR,
WEEKOVERYEAR(DATETIME) AS WEEK,
COUNT(IFF(CATEGORY = 'A',ID,NULL)) as count
from table
group by week, year;
COUNT() counts the number of rows that are not null.
If you are want when ID is not null AND CATEGORY = 'A' then
COUNT(CASE WHEN ID IS NOT NULL AND CATEGORY = 'A' THEN TRUE ELSE NULL END)
will give you that, or you can use a SUM like in Gordon's answer
SUM(CASE WHEN ID IS NOT NULL AND CATEGORY = 'A' THEN 1 ELSE 0 END)
or you can use the snowflake IFF as a shorter form for the same thing, which is how I do it
SUM( IFF( ID IS NOT NULL AND CATEGORY = 'A', 1, 0))

SQL - Dividing aggregated fields, very new to SQL

I have list of line items from invoices with a field that indicates if a line was delivered or picked up. I need to find a percentage of delivered items from the total number of lines.
SALES_NBR | Total | Deliveryrate
1 = Delivered 0 = picked up from FULFILLMENT.
SELECT SALES_NBR,
COUNT (ITEMS) as Total,
SUM (case when FULFILLMENT = '1' then 1 else 0 end) as delivered,
(SELECT delivered/total) as Deliveryrate
FROM Invoice_table
WHERE STORE IN '0123'
And SALE_DATE >='2020-02-01'
And SALE_DATE <='2020-02-07'
Group By SALES_NBR, Deliveryrate;
My query executes but never finishes for some reason. Is there any easier way to do this? Fulfillment field does not contain any NULL values.
Any help would be appreciated.
I need to find a percentage of delivered items from the total number of lines.
The simplest method is to use avg():
select SALES_NBR,
avg(fulfillment) as delivered_ratio
from Invoice_table
where STORE = '0123' and
SALE_DATE >='2020-02-01' and
SALE_DATE <='2020-02-07'
group by SALES_NBR;
I'm not sure if the group by sales_nbr is needed.
If you want to get a "nice" query, you can use subqueries like this:
select
qry.*,
qry.delivered/qry.total as Deliveryrate
from (
select
SALES_NBR,
count(ITEMS) as Total,
sum(case when FULFILLMENT = '1' then 1 else 0 end) as delivered
from Invoice_table
where STORE IN '0123'
and SALE_DATE >='2020-02-01'
and SALE_DATE <='2020-02-07'
group by SALES_NBR
) qry;
But I think this one, even being ugglier, could perform faster:
select
SALES_NBR,
count(ITEMS) as Total,
sum(case when FULFILLMENT = '1' then 1 else 0 end) as delivered,
sum(case when FULFILLMENT = '1' then 1 else 0 end)/count(ITEMS) as Deliveryrate
from Invoice_table
where STORE IN '0123'
and SALE_DATE >='2020-02-01'
and SALE_DATE <='2020-02-07'
group by SALES_NBR

MSSQL Group by and Select rows from grouping

I'm trying to figure out if what I'm trying to do is possible. Instead of resorting to multiple queries on a table, I wanted to group the records by business date and id then group by the id and select one date for a field and another date for the other field.
SELECT
*
{AMOUNT FROM DATE}
{AMOUNT FROM OTHER DATE}
FROM (
SELECT
date,
id,
SUM(amount) AS amount
FROM
table
GROUP BY id, date
AS subquery
GROUP BY id
It seems that you're looking to do a pivot query. I usually use cross tabs for this. Based on the query you posted, it could look like:
SELECT
id,
SUM(CASE WHEN date = '20190901' THEN amount ELSE 0 END) AmountFromSept01,
SUM(CASE WHEN date = '20191001' THEN amount ELSE 0 END) AmountFromOct01
FROM (
SELECT
date,
id,
SUM(amount) AS amount
FROM
table
GROUP BY id, date
)AS subquery
GROUP BY id;
You could also use a CTE.
WITH CTE AS(
SELECT
date,
id,
SUM(amount) AS amount
FROM
table
GROUP BY id, date
)
SELECT
id,
SUM(CASE WHEN date = '20190901' THEN amount ELSE 0 END) AmountFromSept01,
SUM(CASE WHEN date = '20191001' THEN amount ELSE 0 END) AmountFromOct01
FROM CTE
GROUP BY id;
Or even be a rebel and do the operation directly.
SELECT
id,
SUM(CASE WHEN date = '20190901' THEN amount ELSE 0 END) AmountFromSept01,
SUM(CASE WHEN date = '20191001' THEN amount ELSE 0 END) AmountFromOct01
FROM CTE
GROUP BY id;
However, some people have tested for performance and found that pre-aggregating can improve performance.
If I understand you correctly, then you're just trying to pivot, but only with two particular dates:
select id,
date1 = sum(iif(date = '2000-01-01', amount, null)),
date2 = sum(iif(date = '2000-01-02', amount, null))
from [table]
group by id

How to write this SQL query to find each account balance?

I have a transaction table (shown in picture)
https://i.ibb.co/7pdYxxm/hhhhhh.jpg
There's the transaction type (debit/credit)
I need a SQL query that calculates the balance of each account (sum of credits - sum of debts)
So we group by account_id ... but how can we sum the credits alone and the debits alone?
I am on PostgreSQL! Thank you!
This is an easy method to for you to achieve this:
select account_id, sum((case when transaction_type = 'C' then 1 else 0 end)*transaction_amount) as sum_of_credit,sum((case when transaction_type = 'D'then 1 else 0 end) * transaction_amount) as sum_of_debit from YourTableNameHere group by account_id;
Sample Data
Sample Output for the query
I assume the amount must be substracted when the type = 'C'.
select account_id, sum((case when transaction_type = 'C' then -1 else 1 end) * transaction_amount)
from trans
group by account_id
base on the transaction type the amount is multiplied by 1 or -1.
Try This:
Select sum(Transaction_Amount),
Account_Id,
Transaction_Type
From Table_Name
Group By
Account_Id,
Transaction_Type

Subtract two value by difference criteria in same row

In this table we see different transaction in same date some of Transaction Dr and some transaction Cr. I need Cr - Dr as Transaction Amount per date.
Please see screenshot 1st Table
Result will be-
Result
you could use a case when and group by
select date, sum(case when drcr = 'CR' then amount
when drcr = 'DR' then -amount
else 0 end)
from my_table
group by date
as #scaisEdge but you need a sum.
select date, sum(case when drcr = 'CR' then amuont else (-1 * amount) end) as tran_amt
from my_table
group by date
This should be clear, but the way it works is to add credits and substract debits to the total for each date.