How to get the customer info of the customer with the highest number of transactions - sql

I have an oracle sql database consisting of three tables and I was wondering,
What is the most efficient subquery that can be written to retrieve the information of the customer stored in the table customer_info who has performed the highest amount of purchases in total.(The purchase data is in the table purchase_logs). i.e the number of transactions one customer has performed NOT the quantity of the items purchased.
i.e my aim is to retrieve the customer details of the customer witht he highest amount of purchases done.
I have 3 tables one for the customer_info, one as the purchase_logs and the last one being the item_info.
My current Approach
SELECT * FROM customer_info
WHERE customer_id = (SELECT cust_id
FROM purchase_logs
GROUP BY cust_id
ORDER BY COUNT(*)
DESC LIMIT 1);
This doesn't seem to give me any results at all unfortunately.
This is my Database Schema along with the Sample Data of purchase_logs, customer_info, item_info and the Expected Output
I would really appreciate any help in understanding what the proper approach to solving this problem would be.

There is no limit 1 in Oracle SQL, use row limiting clause instead (fetch first in the example below):
SELECT *
FROM
(SELECT cust_id, count(*) cnt
FROM purchase_logs
GROUP BY cust_id
ORDER BY cnt desc
fetch first 1 row only with ties
) vc
join customer_info
on customer_id = vc.cust_id;

Related

Best approach to display all the users who have more than 1 purchases in a month in SQL

I have two tables in an Oracle Database, one of which is all the purchases done by all the customers over many years (purchase_logs). It has a unique purchase_id that is paired with a customer_id.The other table contains the user info of all the customers. Both have a common key of customer_id.
I want to display the user info of customers who have more than 1 unique item (NOT the item quantity) purchased in any month (i.e if A customer bought 4 unique items in february 2020 they would be valid as well as someone who bought 2 items in june). I was wondering what should my correct approach be and also how to correct execute that approach.
The two approaches that I can see are
Approach 1
Count the overall number of purchases done by all customers, filter the ones that are greater than 1 and then check if they any of them were done within a month.
Use this as a subquery in the where clause of the main query for retrieving the customer info for all the customer_id which match this condition.
This is what i've done so far,this retrieves the customer ids of all the customers who have more than 1 purchases in total. But I do not understand how to filter out all the purchases that did not occur in a single arbitrary month.
SELECT * FROM customer_details
WHERE customer_id IN (
SELECT cust_id from purchase_logs
group by cust_id
having count(*) >= 2);
Approach 2
Create a temporary table to Count the number of monthly purchases of a specific user_id then find the MAX() of the whole table and check if that MAX value is bigger than 1 or not. Then if it is provide it as true for the main query's where clause for the customer_info.
Approach 2 feels like the more logical option but I cannot seem to understand how to write the proper subquery for it as the command MAX(COUNT(customer_id)) from purchase_logs does not seem to be a valid query.
This is the DDL diagram.
This is the Sample Data of Purchase_logs
Customer_info
and Item_info
and the expected output for this sample data would be
It is certainly possible that there is a simpler approach that I am not seeing right now.
Would appreciate any suggestions and tips on this.
You need this query:
SELECT DISTINCT cust_id
FROM purchase_logs
GROUP BY cust_id, TO_CHAR(purchase_date, 'YYYY-MON')
HAVING COUNT(DISTINCT item_id) > 1;
to get all the cust_ids of the customers who have more than 1 unique item purchased in any month and you can use with the operator IN:
SELECT *
FROM customer_details
WHERE customer_id IN (
SELECT DISTINCT cust_id -- here DISTINCT may be removed as it does not make any difference when the result is used with IN
FROM purchase_logs
GROUP BY cust_id, TO_CHAR(purchase_date, 'YYYY-MON')
HAVING COUNT(DISTINCT item_id) > 1
);
One approach might be to try
with multiplepurchase as (
select customer_id,month(purchasedate),count(*) as order_count
from purchase_logs
group by customer_id,month(purchasedate)
having count(*)>=2)
select customer_id,username,usercategory
from mutiplepurchase a
left join userinfo b
on a.customer_id=b.customer_id
Expanding on #MT0 answer:
SELECT *
FROM customer_details CD
WHERE exists (
SELECT cust_id
FROM purchase_logs PL
where CD.customer_id = PL.customer_id
GROUP BY cust_id, item_id, to_char(purchase_date,'YYYYMM')
HAVING count(*) >= 2
);
I want to display the user info of customers who have more than 1 purchases in a single arbitrary month.
Just add a WHERE filter to your sub-query.
So assuming that you wanted the month of July 2021 and you had a purchase_date column (with a DATE or TIMESTAMP data type) in your purchase_logs table then you can use:
SELECT *
FROM customer_details
WHERE customer_id IN (
SELECT cust_id
FROM purchase_logs
WHERE DATE '2021-07-01' <= purchase_date
AND purchase_date < DATE '2021-08-01'
GROUP BY cust_id
HAVING count(*) >= 2
);
If you want the users where they have bought two-or-more items in any single calendar month then:
SELECT *
FROM customer_details c
WHERE EXISTS (
SELECT 1
FROM purchase_logs p
WHERE c.customer_id = p.cust_id
GROUP BY cust_id, TRUNC(purchase_date, 'MM')
HAVING count(*) >= 2
);

How to add a column with row number in front of my query results?

I am working with a database that contains invoice data about online music purchases. My team is only interested in invoices sent to customers located in the city of London. I want to sort the invoices by order total in ascending order. The order totals are listed in the total column.
I wrote the following SQL query:
SELECT
*
FROM
invoice
WHERE
billing_city = "London"
ORDER BY
total ASC;
This is my result:
query result
Is there a way to add a column with row number in front of my query results table?
Thank you for your input!
Use ROW_NUMBER:
SELECT *, ROW_NUMBER() OVER (ORDER BY total) rn
FROM invoice
WHERE billing_city = 'London'
ORDER BY total;

SQL - fetch records based on a condition of two columns

I need to fetch records where
Order No = ABC
has more than one tracking number in a large table
Can someone help with that?
I'll assume that you're fetching records from Orders and the "large table" is TrackingNumbers. You can group by the OrderNo in a sub-query and refine the sub-query by using a having clause. Then the sub-query will return only OrderNos that are in the table more than once. For example:
select OrderNo
from Orders
where OrderNo in (select OrderNo
from TrackingNumbers
group by OrderNo
having count(*) > 1)
To identify duplicates in a single table (as mentioned in the comments):
select *
from Orders
group by TrackingNumber
having count(*) > 1

select multiple records based on order by

i have a table with a bunch of customer IDs. in a customer table is also these IDs but each id can be on multiple records for the same customer. i want to select the most recently used record which i can get by doing order by <my_field> desc
say i have 100 customer IDs in this table and in the customers table there is 120 records with these IDs (some are duplicates). how can i apply my order by condition to only get the most recent matching records?
dbms is sql server 2000.
table is basically like this:
loc_nbr and cust_nbr are primary keys
a customer shops at location 1. they get assigned loc_nbr = 1 and cust_nbr = 1
then a customer_id of 1.
they shop again but this time at location 2. so they get assigned loc_nbr = 2 and cust_Nbr = 1. then the same customer_id of 1 based on their other attributes like name and address.
because they shopped at location 2 AFTER location 1, it will have a more recent rec_alt_ts value, which is the record i would want to retrieve.
You want to use the ROW_NUMBER() function with a Common Table Expression (CTE).
Here's a basic example. You should be able to use a similar query with your data.
;WITH TheLatest AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY group-by-fields ORDER BY sorting-fields) AS ItemCount
FROM TheTable
)
SELECT *
FROM TheLatest
WHERE ItemCount = 1
UPDATE: I just noticed that this was tagged with sql-server-2000. This will only work on SQL Server 2005 and later.
Since you didn't give real table and field names, this is just psuedo code for a solution.
select *
from customer_table t2
inner join location_table t1
on t1.some_key = t2.some_key
where t1.LocationKey = (select top 1 (LocationKey) as LatestLocationKey from location_table where cust_id = t1.cust_id order by some_field)
Use an aggregate function in the query to group by customer IDs:
SELECT cust_Nbr, MAX(rec_alt_ts) AS most_recent_transaction, other_fields
FROM tableName
GROUP BY cust_Nbr, other_fields
ORDER BY cust_Nbr DESC;
This assumes that rec_alt_ts increases every time, thus the max entry for that cust_Nbr would be the most recent entry.
By using time and date we can take out the recent detail for the customer.
use the column from where you take out the date and the time for the customer.
eg:
SQL> select ename , to_date(hiredate,'dd-mm-yyyy hh24:mi:ss') from emp order by to_date(hiredate,'dd-mm-yyyy hh24:mi:ss');

Which customer has placed most orders. SQL query

I'm trying to query my database for my class to find out which customer has placed the most orders. The table I'm searching is a three attribute table that has the customerID, orderID, and the placedDate.
The query I thought would work is:
select cid from placed order by sum(oid);
But I keep getting an error saying cid is "not a single-group group function" the oid is the primary key and is a foreign key that references another table. Is that what the issue is?
If you want to count the number of orders you should do a count instead of a SUM:
SELECT cid,COUNT(*)
FROM placed
GROUP BY cid
ORDER BY COUNT(*) DESC
This will give you the list of customers and their respective number of orders, ordered by the number of orders descendent.
If you want just the customer with most orders, you have to limit the number of records to the first one. For that, you have to tell what DBMS you use, since it varies with the DBMS the way you limit the query to the first one (ex: mysql is LIMIT 1, sql-server is TOP 1):
In Oracle, you can do:
SELECT * FROM (
SELECT cid,COUNT(*)
FROM placed
GROUP BY cid
ORDER BY COUNT(*) DESC
) a
WHERE rownum = 1
In case the there are one or more customers having maximum orders:
select * from orders o, customer c where o.cusId = c.cusId and o.cusId IN (select cusId from orders group by cusId having count(*) = (select count(*) from orders or group by or.cusId order by count(*) desc limit 1));
This solution is for MySQL, as I have used LIMIT. It can be changed as per the DBMS.
I also used = in the second query since LIMIT does not work with IN.