I have a table with columns:
customer_id,
customer_name,
transaction_number,
transaction_date,
transaction_type,
transaction_value,
transaction_approved.
I am trying to generate a list where the columns are
customer_id,
customer_name,
total transaction value
where the transaction_type is credit and made in 2020, total transaction value where the transaction_type is debit or cash in 2019.
However, this list is only including the customer_id who made at least one transaction using credit in the year 2020. Basically, how would I use the where clause to get the criteria for the customer_id and then get the rest of the list based on those customer_ids only?
It would be returning
the customer_id where the at least one transaction was made using credit in the year 2019
and then the other columns next to it would return the values for that customer_id
Something like that should do the trick:
select customer_id, customer_name, sum(effective_value)
from (
select customer_id, customer_name,
case
when transaction_type in ('debit', 'cash')
and '2019' <= transaction_date
and transaction_date < '2020'
then transaction_value
else 0
END effective_value
from transactions as T
) as T
group by customer_id, customer_name;
You'll have to adapt the transaction_date comparision to meet your database syntax.
What I understand from above description, user needs customers which has transaction_type credit in 2020, but he wants sum of amount for year 2019 and that also for transaction type debit and cash . Please update question if its not the case
select
customer_id, customer_name,
sum(coalesce(transaction_value,0)) as total_transaction_value
from
table_T
where
customer_id in (select distinct customer_id from table_T
where transaction_type = 'credit'
and transaction_date >= '2020-01-01')
and transaction_date >= '2019-01-01'
and transaction_date < '2020-01-01'
and transaction_type in ('debit', 'cash')
group by
customer_id, customer_name
Database is not mentioned you may have to parse date field accordingly
Related
I'm just learning SQL, using Postgres. I have fruit sales data, how can I retrieve fruit that is only sold from the certain date to another date. I use a query like this but error
SELECT product_name,
min (purchase_date) AS purchase_date
FROM sales
where purchase_date not in (purchase_date <= '2021-01-01' and purchase_date >= '2021-01-10')
GROUP BY product_name
ORDER by product_name asc ;
It is BETWEEN you're looking for, I presume.
where purchase_date between '2021-01-01' and '2021-01-10'
You used negative logic (invalid, though), so I guess that you're looking for fruits sold between 1st and 10t of January 2021.
You can't do this with a simple select, as that doesn't care about what other rows are doing. But you should be able to do it in a HAVING clause to filter out based on the aggregates:
SELECT product_name,
min (purchase_date) AS purchase_date
FROM sales
GROUP BY product_name
HAVING min (purchase_date) >= '2021-01-01' and max(purchase_date) <= '2021-01-10'
ORDER by product_name asc ;
I have a table with customer_ID, date, and payment_method as 3 columns. payment_method can be 'cash', 'credit', or 'others'. I want to find out the number of customers who have used credit as a payment method more than 5 times, in the last 6 months.
I found this solution for displaying the rows where the customer used credit:
SELECT customer_ID, payment_method, COUNT(*) AS unique_pair_repeats
FROM tab1
WHERE customer_ID IS NOT NULL
GROUP BY customer_ID, payment_method
HAVING count(*) > 1;
The problem is, I don't want a list of the names/ids, I want to know how many people used their credit card for a purchase 5 times or more in the last 6 months.
This is one way you could do it:
SELECT COUNT(*)
FROM
(
SELECT customer_id
FROM tab1
WHERE
customer_ID IS NOT NULL and
payment_method = 'credit' and
tran_date > add_months(sysdate, -6)
GROUP BY customer_ID
HAVING count(*) > 5
) x
The inner query generates a list of all customer ids that have used credit more than 5 times in 6 months. The outer query counts them
You might feel it more logical to write it like this:
SELECT COUNT(*)
FROM
(
SELECT customer_id, count(*) as ctr
FROM tab1
WHERE
customer_ID IS NOT NULL and
payment_method = 'credit' and
tran_date > add_months(sysdate, -6)
GROUP BY customer_ID
) x
WHERE x.ctr > 5
So, remove customer_ID, payment_method, from select.
Though, that still doesn't answer "at least 5 times in last 6 months", so you need another condition: date (presuming you use Oracle, although you didn't tag the question but - you do use Oracle SQL Developer):
and date_column >= add_months(trunc(sysdate), -6)
Finally, something like this might help:
SELECT COUNT(*) AS unique_pair_repeats --> changes here
FROM tab1
WHERE customer_ID IS NOT NULL
and date_column >= add_months(trunc(sysdate), -6) --> here
GROUP BY customer_ID, payment_method
HAVING count(*) >= 5; --> here
I have a table with columns order_id, customer_id, order_date and Amount.
How to find the customers who have ordered at least 2 times each month of the year in SQL (from Jan to Dec)?
I think you are looking for something like this
select
order_date_year,
customer_id
from
(
select
year(order_date) as order_date_year,
month(order_date) as order_date_month,
customer_id,
count(*) as number_of_orders
from
tableName
group by
year(order_date),
month(order_date),
customer_id
having
count(*) >= 2
) as t
group by
order_date_year,
customer_id
having
count(*) = 12
I have a select that group by customers spending of the past two months by customer id and date. What I need to do is to associate for each row the total amount spent by that customer in the whole first week of the two month time period (of course it would be a repetition for each row of one customer, but for some reason that's ok ). do you know how to do that without using a sub query as a column?
I was thinking using some combination of OVER PARTITION, but could not figure out how...
Thanks a lot in advance.
Raffaele
Query:
select customer_id, date, sum(sales)
from transaction_table
group by customer_id, date
If it's a specific first week (e.g. you always want the first week of the year, and your data set normally includes January and February spending), you could use sum(case...):
select distinct customer_id, date, sum(sales) over (partition by customer_ID, date)
, sum(case when date between '1/1/15' and '1/7/15' then Sales end)
over (partition by customer_id) as FirstWeekSales
from transaction_table
In response to the comments below; I'm not sure if this is what you're looking for, since it involves a subquery, but here's my best shot:
select distinct a.customer_id, date
, sum(sales) over (partition by a.customer_ID, date)
, sum(case when date between mindate and dateadd(DD, 7, mindate)
then Sales end)
over (partition by a.customer_id) as FirstWeekSales
from transaction_table a
left join
(select customer_ID, min(date) as mindate
from transaction_table group by customer_ID) b
on a.customer_ID = b.customer_ID
I have a query similar to this, where I need to find the number of transactions a specific customer had within a time frame:
select customer_id, count(transactions)
from transactions
where customer_id = 'FKJ90838485'
and purchase_date between '01-JAN-13' and '31-AUG-13'
group by customer_id
The table transactions is not indexed on customer_id but rather another field called transaction_id. Customer_ID is character type while transaction_id is numeric.
'accounting_month' field is also indexed.. this field just stores the month that transactions occured... ie, purchase_date = '03-MAR-13' would have accounting_month = '01-MAR-13'
The transactions table has about 20 million records in the time frame from '01-JAN-13' and '31-AUG-13'
When I run the above query, it has taken more than 40 minutes to come back, any ideas or tips?
As others have already commented, the best is to add an index that will cover the query, So:
Contact the Database administrator and request that they add an index on (customer_id, purchase_date) because the query is doing a table scan otherwise.
Sidenotes:
Use date and not string literals (you may know that and do it already, still noted here for future readers)
You don't have to put the customer_id in the SELECT list and if you remove it from there, it can be removed from the GROUP BY as well so the query becomes:
select count(*) as number_of_transactions
from transactions
where customer_id = 'FKJ90838485'
and purchase_date between DATE '2013-01-01' and DATE '2013-08-31' ;
If you don't have a WHERE condition on customer_id, you can have it in the GROUP BY and the SELECT list to write a query that will count number of transactions for every customer. And the above suggested index will help this, too:
select customer_id, count(*) as number_of_transactions
from transactions
where purchase_date between DATE '2013-01-01' and DATE '2013-08-31'
group by customer_id ;
This is just an idea that came up to me. It might work, try running it and see if it is an improvement over what you currently have.
I'm trying to use the transaction_id, which you've said is indexed, as much as possible.
WITH min_transaction (tran_id)
AS (
SELECT MIN(transaction_ID)
FROM TRANSACTIONS
WHERE
CUSTOMER_ID = 'FKJ90838485'
AND purchase_date >= '01-JAN-13'
), max_transaction (tran_id)
AS (
SELECT MAX(transaction_ID)
FROM TRANSACTIONS
WHERE
CUSTOMER_ID = 'FKJ90838485'
AND purchase_date <= '31-AUG-13'
)
SELECT customer_id, count(transaction_id)
FROM transactions
WHERE
transaction_id BETWEEN min_transaction.tran_id AND max_transaction.tran_id
GROUP BY customer_ID
May be this will run faster since it look at the transaction_id for the range instead of the purchase_date. I also take in consideration that accounting_month is indexed :
select customer_id, count(*)
from transactions
where customer_id = 'FKJ90838485'
and transaction_id between (select min(transaction_id)
from transactions
where accounting_month = '01-JAN-13'
) and
(select max(transaction_id)
from transactions
where accounting_month = '01-AUG-13'
)
group by customer_id
May be you can also try :
select customer_id, count(*)
from transactions
where customer_id = 'FKJ90838485'
and accounting_month between '01-JAN-13' and '01-AUG-13'
group by customer_id