Get the max column value for each unique ID - mysql

I have two tables, a customers and orders table.
The customers table contains a unique ID for each customer. It contains 1141 entries.
The orders table contains many entries with a customerID and a date.
I am trying to query my database and return a list of customers and the max(date) from the orders list.
SELECT *
FROM customers
INNER JOIN
(
SELECT CustomerID, max(date) as date
FROM orders
GROUP BY CustomerID
) Sub1
ON customers.id = Sub1.CustomerID
INNER JOIN orders
ON orders.CustomerID = Sub1.CustomerID
AND orders.date = Sub1.Date
However this query is returning 1726 rows instead of 1141 rows. Where is this getting extra from?

I think it's beacause ORDERS table contains same customerID multiple times, so when you join the table with CUSTOMERS, each CUSTOMER.id matches multiple rows of ORDERS.

The problem is that there are ties.
For a given customer, some place more than one order per day. So there's a possibility that occasionally some may have placed more than one order on the date that is their max date.
To fix this, you need to use MAX() or some column that is always unique in the Orders table (or at least unique within a given date). This is easy if you can depend on an auto-increment primary key in the Orders table:
SELECT *
FROM customers
INNER JOIN
(
SELECT CustomerID, max(orderid) as orderid as date
FROM orders
GROUP BY CustomerID
) Sub1
ON customers.id = Sub1.CustomerID
INNER JOIN orders
ON orders.CustomerID = Sub1.CustomerID
AND orders.orderid = Sub1.orderid
This assumes that orderid increases in lock-step with increasing dates. That is, you'll never have an order with a greater auto-inc id but an earlier date. That might happen if you allow data to be entered out of chronological order, e.g. back-dating orders.

;with cte as
(
select CustomerID, orderdate
, rn = row_number() over (partition by customerID order by orderdate desc)
from orders
)
select c.*, cte.orderdate
from customer c
join cte on cte.customerID = c.customerid
where rn =1 -- This will limit to latest orderdate

Related

Creating a percentage column on a table made from an inner join

I have two tables Orders and RMA. I wrote this command to return an inner join between the two tables. OrderID is the primary key of Orders and foreign key of RMA.
SELECT Orders.SKU, COUNT(*) AS Frequency
FROM Orders
INNER JOIN RMA ON Orders.OrderID = RMA.OrderID
GROUP BY Orders.SKU
ORDER BY COUNT(*) DESC;
This select statement returns a table with one column containing SKU values and one column containing the number of times each SKU value appears in the data. My goal is to create a third column that includes a percent that represents the frequency of each SKU value.
(disclaimer: I'm new to mysql, so if there's more information needed for this question, I am happy to provide it. Thanks!)
You must divide COUNT(*) with the total number of rows in RMA:
SELECT Orders.SKU,
COUNT(*) AS Frequency,
COUNT(*) / (SELECT COUNT(*) FROM RMA) AS percent
FROM Orders INNER JOIN RMA
ON Orders.OrderID = RMA.OrderID
GROUP BY Orders.SKU
ORDER BY Frequency DESC;

Select data from specific row of grouped and joined table in MySQL

I have two tables, customers and orders which are inner joined. A customer can have several orders associated with them. In my selection, I then group by customers.id. I need to select the most recent order of each customer, but also the amount of money spent in that order. Currently, I can select the most recent order_date but do not know how to select the amount in the same row as the order_date.
This is my current query:
SELECT
first_name,
last_name,
email,
MAX(order_date) AS recent_order,
amount -- this needs to select amount associated with recent_order
FROM customers
JOIN orders
ON customers.id = orders.customer_id
GROUP BY customers.id;
The query selects the most recent date, but does not select the amount associated with the most recent order_date.
Table declarations:
CREATE TABLE customers (
id INT AUTO_INCREMENT PRIMARY KEY,
first_name VARCHAR(100),
last_name VARCHAR(100),
email VARCHAR(100)
);
CREATE TABLE orders (
id INT AUTO_INCREMENT PRIMARY KEY,
order_date DATE,
amount DECIMAL(8,2),
customer_id INT,
FOREIGN KEY(customer_id) REFERENCES customers(id)
);
I would recommend a correlated subquery in the where clause:
SELECT c.*, o.* -- or whatever columns you want
FROM customers c JOIN
orders o
ON c.id = o.customer_id
WHERE o.order_date = (SELECT max(o2.order_date)
FROM orders o2
WHERE o2.customer_id = o.customer_id
);
For performance, you want an index on orders(customer_id, order_date).
SELECT
first_name,
last_name,
email,
MAX(order_date) AS recent_order,
(SELECT amount FROM orders WHERE order_date = MAX(order_date) AND customers.id = orders.customer_id) as amount
FROM customers
JOIN orders
ON customers.id = orders.customer_id
GROUP BY customers.id;
OR
SELECT
first_name,
last_name,
email,
order_date AS recent_order,
amount AS recent_order_amount
FROM customers
JOIN orders
ON customers.id = orders.customer_id
GROUP BY customers.id
ORDER BY orders.order_date DESC;
Use this:
SELECT TOP 1
t1.first_name,
t1.last_name,
t1.email,
t2.order_date,
t2.amount
FROM customers t1
JOIN orders t2
ON t1.id = t2.customer_id
ORDER BY
t2.order_date
Add a GROUP BY t1.id if the intent is to return all rows with the most recent order_date. Omit this if every order is resented by a single row in orders. Note this will not sum the amounts. You will have to do that in code or else use a different query. Also note that performance of this query will be affected by configuration of indexes. This query may not be performant if order_date is not part of an index and the table contains a large data set.

How to match up dates on 2 different tables and join to an ID table?

I have a table full of product ids and their attributes. I want to join sales data and receipt data from 2 different tables and a different row for each id and date combo. So I want the output to look like this:
I tried joining the product id table and sales table to the receipt table but I'm not sure how to get the dates from the sales and receipts table to match up. Not sure of how to approach this. Thanks!
Calculate the counts for each table and combine them usung UNION ALL
select
product_id
,sales_date
-- combine the counts from both tables
,sum(sales_count)
,sum(receipt_count)
from
(
-- get the counts for the sales table
select
product_id
,sales_date
,count(*) as sales_count
-- UNION needs the same number of columns in both Select -> adding a dummy column
-- 1st Select determines the datatype
,cast(0 as int) as receipt_count
from sales
group by product_id, sales_date
UNION ALL
-- get the counts for the receipts table
select
product_id
,receipt_date
,0
,count(*)
from receipts
group by product_id, receipt_date
) as dt
group by product_id, receipt_date
select p.product_id, s.sales_date, s.sales_count, r.receipt_count
from
products p,
(select count(*) sales_count, sales_date, product_id from sales group by 2,3) s
(select count(*) receipt_count, receipt_date, product_id from receipts group by 2,3) r
where
p.product_id = s.product_id
and p.product_id = r.product_id
and s.sales_date=r.receipt_date
;

Use mysql joins to count no of invoices of customers

My invoices table has orderId column which is a foreign key referencing orderId primary key column of orders table and orders table has customerId column which references to customerId primary key column of customers table.
A customer can have multiple orders but an order has only one invoice.
I want to count the no of invoices of each customer. Below is the query I tried:
SELECT customers.name, COUNT(*) as number_of_invoices
FROM invoices
JOIN orders
ON invoices.orderId = orders.orderId
JOIN customers
ON orders.customerId = customers.customerId;
But it is only returning me one customer and the count is of total count not invoices count of that customer.
Here is a solution for your problem:
SELECT customers.name, COUNT(*) as number_of_invoices
FROM invoices
INNER JOIN orders
ON invoices.orderId = orders.orderId
INNER JOIN customers
ON orders.customerId = customers.customerId
GROUP BY Customers.name;
Just add GROUP BY in your query in last to group count of invoices for each Customer.
If you just need to know the count of invoice for each customer. It can be done without JOIN. Since order and invoice has one-to-one mapping you can use below sql queries
select customerId ,count(orderId) as invoice_count from orders group by customerId

How can I write an SQL query to show the latest transaction in one table?

I have 2 DB tables that both share an Order Number column.
One table is "orders" and the Order Number is the unique key.
The second table is my "transactions" table that has one row, per transaction made for each order number. Based on the fact we take monthly payments, the "transactions" table obviously has multiple rows with a unique date but many repeats of a each Order Number.
How can I run a query which has a list of unique OrderNumbers in one column, and the latest "TransDate" (Transaction Date) in the second column.
I tried the below but its pulling back the first TransDate that exists for each ordernumber, not the latest one. I think I need a sub query of some sort:
select orders.ordernumber, transdate from orders
join transactions on transactions.ordernumber = orders.ordernumber
where status = 'booking'
group by ordernumber
order by orders.ordernumber, TransDate DESC
You should just use MAX() function along with grouping on order number. There also doesn't seem to be any reason to do a join here.
SELECT
ordernumber,
MAX(transdate) AS maxtransdate
FROM transactions
WHERE status = 'booking'
GROUP BY ordernumber
ORDER BY ordernumber ASC
Use aggregate functions, specifically max():
select o.ordernumber, max(transdate) as last_transdate
from orders as o
inner join transactions as t on o.ordernumber = t.ordernumber
-- where conditions go here
group by ordernumber
If you need to pull the details of the last transaction for each order, you can use the above query as a data source of another query and join it with the transactions table:
select a.*, t.*
from (
select o.ordernumber, max(transdate) as last_transdate
from orders as o
inner join transactions as t on o.ordernumber = t.ordernumber
-- where conditions go here
group by ordernumber
) as a
inner join transactions as t on a.ordernumber = t.ordernumber and a.last_transdate = t.transdate
Change the order by line to
order by Transdate DESC, orders.ordernumber
Here's the full query with the change
select orders.ordernumber, transdate from orders
join transactions on transactions.ordernumber = orders.ordernumber
where status = 'booking'
group by ordernumber
order by Transdate DESC, orders.ordernumber