Group by id having max(date_field) - mysql

To build a report, I must select some information on the last transaction status of all my customers. Until now, this is what I got:
SELECT c.firstname, c.lastname, d.product_name, o.payment, s.name, h.date_add
FROM ps_orders o
INNER JOIN ps_order_detail d ON d.id_order = o.id_order
INNER JOIN ps_customer c ON c.id_customer = o.id_customer
INNER JOIN ps_order_history h ON o.id_order = h.id_order
INNER JOIN ps_order_state_lang s ON s.id_order_state = h.id_order_state
WHERE s.id_lang =6
GROUP BY c.id_customer
HAVING MAX(h.date_add)
For each customer, this query is selecting the first date (the field h.date_add) when I need of the last one. It seems the MySQL is ignoring the HAVING.
I tried to make a sub-select, but it doesn't work too.
Thanks any answer.

Here, you need to have a subquery which gets the latest date_add for every id_order on table ps_order_history. The result of the subquery is then joined back on the original table ps_order_history provided that it macth on two columns: date_add and id_order.
SELECT c.firstname,
c.lastname,
d.product_name,
o.payment,
s.name,
h.date_add
FROM ps_orders o
INNER JOIN ps_order_detail d ON d.id_order = o.id_order
INNER JOIN ps_customer c ON c.id_customer = o.id_customer
INNER JOIN ps_order_history h ON o.id_order = h.id_order
INNER JOIN
(
SELECT id_order, MAX(date_add) max_date
FROM ps_order_history
GROUP BY id_order
) x ON h.id_order = x.id_order AND
h.date_add = x.max_date
INNER JOIN ps_order_state_lang s ON s.id_order_state = h.id_order_state
WHERE s.id_lang =6
GROUP BY c.id_customer

To get the last date, you need to join it in:
SELECT c.firstname, c.lastname, d.product_name, o.payment, s.name, h.date_add
FROM ps_orders o
INNER JOIN ps_order_detail d ON d.id_order = o.id_order
INNER JOIN ps_customer c ON c.id_customer = o.id_customer
INNER JOIN ps_order_history h ON o.id_order = h.id_order
INNER JOIN ps_order_state_lang s ON s.id_order_state = h.id_order_state
inner join (select o.id_customer, max(oh.date_add) as maxdate from ps_order_history h join ps_order o on h.id_order = o.id_order group by o.id_customer) omax on omax.id_customer = o.id_customer and o.date_add = omax.maxdate
WHERE s.id_lang =6
GROUP BY c.id_customer
Your having clause calculates the maximum date and then succeeds when it is not equal to 0 (which would be most of the time).

Related

Prestashop / SQL Query from SQL Database

I am trying to create a query that returns the firstname, lastname, email and key_value for each order of a certain product (id 49) but I can't quite configure the SQL query correctly to get each key for each customer.
SELECT C.email,
C.firstname,
C.lastname,
K.key_value
FROM ps_customer C
INNER JOIN ps_orders O on C.id_customer = O.id_customer
INNER JOIN ps_order_detail OD on O.id_order = OD.id_order
INNER JOIN ps_keymanager OD on O.id_order = OD.id_order
WHERE OD.product_id =49
you could try this.. But!.
I've no idea what the ps_keymanager is, but if your using it
im sure you can fit into the query below.. ;)
SELECT O.reference AS ORDERREF, C.firstname, C.lastname, C.email AS Email
FROM ps_customer C
INNER JOIN ps_orders O on C.id_customer = O.id_customer
INNER JOIN ps_order_detail OD on O.id_order = OD.id_order
WHERE OD.product_id = 846
This will list
Order Reference | Firstname | Surname | Email
WHERE product_id = (in my case 846)
I share the consultation that I use to obtain different information from the client, by order id :
SELECT pod.id_order, c.id_customer,
CONCAT(c.firstname, c.lastname) AS client,
c.firstname, c.lastname, pa.address1, pa.address2,
pa.city, pa.id_country,c.email, pa.postcode, pa.phone_mobile,
pa.phone, pc.iso_code AS country
FROM ps_orders po
LEFT JOIN ps_order_detail pod ON (po.id_order = pod.id_order)
LEFT JOIN ps_product pp ON (pod.product_id = pp.id_product)
LEFT JOIN ps_customer c ON (c.id_customer = po.id_customer)
LEFT JOIN ps_address pa ON (pa.id_customer = c.id_customer)
LEFT JOIN ps_country pc ON (pc.id_country = pa.id_country)
WHERE pod.id_order = 34549
You can add or remove the columns you need in your sql query.

Remove duplication in SQL query

SQL Practice from W3Schools
SELECT C.country,
Round(Sum(P.price * OD.quantity), 2) AS Revenue
FROM [orders] AS O
INNER JOIN [orderdetails] AS OD
ON O.orderid = OD.orderid
INNER JOIN [products] AS P
ON OD.productid = P.productid
INNER JOIN [customers] AS C
ON O.customerid = C.customerid
WHERE C.country = (SELECT C.country
FROM [orders] AS O
INNER JOIN [orderdetails] AS OD
ON O.orderid = OD.orderid
INNER JOIN [products] AS P
ON OD.productid = P.productid
INNER JOIN [customers] AS C
ON O.customerid = C.customerid
GROUP BY C.customerid
ORDER BY Round(Sum(P.price * OD.quantity), 2) DESC
LIMIT 1)
My joins are duplicated from main to sub-query.
Is there anyway to reduce code replication in this query?

Retrieve customer who bought more than 13 different products who never purchased same product

I tried this. But I feel this gives people who ordered same product
SELECT DISTINCT Count(od.orderqty) OrderQty,
c.customerid,
od.productid
FROM sales.customer c
INNER JOIN sales.salesorderheader oh
ON c.customerid = oh.customerid
INNER JOIN sales.salesorderdetail od
ON oh.salesorderid = od.salesorderid
GROUP BY od.productid,
c.customerid
HAVING Count(od.productid) > 10
ORDER BY c.customerid
Not sure what flavor of SQL you're using but try this:
select t.CustomerID
from (
select c.CustomerID
, count(distinct od.ProductID) as DistinctCount
, count(od.ProductID) as Count
from Sales.Customer c
join Sales.SalesOrderHeader oh
on c.customerid = oh.customerid
join Sales.SalesOrderDetail od
on oh.SalesOrderID = od.SalesOrderID
group
by c.CustomerID
) as t
where t.DistinctCount = t.Count
and t.DistinctCount > 13
order
by t.CustomerID

Optimizing query to show repeat customer

I am working with prestashop 1.5 and have the following query that shows repeat customer (previous year vs next year).
SELECT prev.id_customer, prev.name, prev.email, prev.count AS 'prev', next.count AS 'next'
FROM(
SELECT o.id_customer, CONCAT(c.firstname, ' ', c.lastname) AS name, c.email, COUNT(1) AS 'count'
FROM ps_orders AS o
LEFT JOIN ps_order_history AS h ON o.id_order = h.id_order
LEFT JOIN ps_customer AS c on o.id_customer = c.id_customer
WHERE o.invoice_date BETWEEN '2014-01-01' AND '2014-12-31'
AND h.id_order_state = 2
GROUP BY o.id_customer
ORDER BY count DESC
) AS prev,
(
SELECT o.id_customer, CONCAT(c.firstname, ' ', c.lastname) AS name, c.email, COUNT(1) AS 'count'
FROM ps_orders AS o
LEFT JOIN ps_order_history AS h ON o.id_order = h.id_order
LEFT JOIN ps_customer AS c on o.id_customer = c.id_customer
WHERE o.invoice_date BETWEEN '2015-01-01' AND '2015-12-31'
AND h.id_order_state = 2
GROUP BY o.id_customer
ORDER BY count DESC
) AS next
WHERE prev.id_customer = next.id_customer
ORDER BY prev.name ASC;
I would like to know whether there is better way to optimize this query ? I am thinking of creating a VIEW for each year thus minimizing the number of lines. But i am not sure whether it is better (performance wise).
Can anyone give me a better solution to this?
EDIT 1
I think you can use conditional aggregation:
SELECT o.id_customer, CONCAT(c.firstname, ' ', c.lastname) AS name, c.email,
SUM(o.invoice_date BETWEEN '2014-01-01' AND '2014-12-31') as cnt_2014,
SUM(o.invoice_date BETWEEN '2015-01-01' AND '2015-12-31') as cnt_2015
FROM ps_orders o LEFT JOIN
ps_order_history h
ON o.id_order = h.id_order LEFT JOIN
ps_customer c
on o.id_customer = c.id_customer
WHERE h.id_order_state = 2
GROUP BY o.id_customer;

Multiple inner joins to get a complex report, not working

For the schema below, I need to get this report
This is what I have
select c.name, sr.name, count(o.order_id)
from contact c
INNER JOIN accounts a
ON c.account_id=a.account_id
INNER JOIN sales_reps sr
ON a.sales_rep_id =sr.sales_rep_id
INNER JOIN orders o
ON a.account_id =o.account_id
where o.order_id in (
select SUM(oi.quantity*p.price) from
order_items oi INNER JOIN parts p
on oi.part_id =p.part_id
)
group by a.account_id, c.name
But this does not give any results.
Please help.
Your where condition is not right, how should be a order_id equal a sum?
Try the below:
select
c.name, sr.name, COUNT(o.order_id), SUM(op.order_total)
FROM
contact c
INNER JOIN
accounts a ON c.account_id = a.account_id
INNER JOIN
sales_reps sr ON a.sales_rep_id = sr.sales_rep_id
INNER JOIN
orders o ON a.account_id = o.account_id
INNER JOIN
(SELECT
oi.order_id, SUM(oi.quantity * p.price) AS order_total
FROM
order_items oi
INNER JOIN
parts p ON oi.part_id = p.part_id
GROUP BY
oi.order_id
) op ON o.order_id = op.order_id
WHERE o.delivery_data >= CURDATE()
GROUP by c.contact_id
It won't give results as your WHERE ... IN SELECT is based on a query returning a sum() value which will not equal a key (most likely), or incorrect at best... and since you are dealing with a quantity and price which will have decimal precision (typically), you won't even get that to match even LESS likely...
I would swap the query around to pre-qualify the orders within a given date in question and sum that... THEN join to rest...
select
c.name,
sr.name,
PreQualified.NumberOrders,
PreQualified.OrderTotal
from
( select
o.Account_ID,
count( distinct o.order_id ) as NumberOrders,
sum( oi.quantity * p.price ) as OrderTotal
from
orders o
join order_items oi
on o.order_id = oi.order_id
join parts p
on oi.part_id = p.part_id
where
o.Delivery_Date >= CURDATE()
group by
o.Account_ID ) as PreQualified
JOIN Accounts a
on PreQualified.Account_ID = a.Account_ID
Join Contact C
on a.Account_ID = c.Account_ID
JOIN Sales_Reps sr
ON a.sales_rep_id = sr.sales_rep_id
If you want to count records use
count(*)
Instead of
count(o.order_id)