MySQL Query. Give closest date to present day - mysql

I have this query that gives me back more than one result. I would like to edit it so that it only will give me one result per o.Customer_ID and then have that be the order that would be closest to today with o.OrderPlaceServerTime.
Here's the Query I have:
SELECT
o.Order_ID,
o.Customer_ID,
o.OrderPlaceServerTime,
o.CustomerOrderTotal
FROM
Orders o
LEFT JOIN Order_LineDetails oln
ON oln.Order_ID = o.Order_ID
WHERE
o.OrderPlaceServerTime >= '2012-09-01 00:00:00'
AND o.OrderPlaceServerTime <= '2012-12-01 00:00:00'
AND o.CustomerOrderTotal >= '50'
AND oln.Product_ID = '75'
What would I need to change to achieve this?

I would like to edit it so that it only will give me one result per o.Customer_ID
So, first you should get the latest order for the qualifying Customer IDs, by grouping the qualifying order by customer ID and picking the max or OrderPlaceServerTime. Then you would join those records with the Orders on customer ID and the OrderPlaceServerTime to pick the other two attributes of interest.
SELECT
o.Order_ID,
o.Customer_ID,
o.OrderPlaceServerTime,
o.CustomerOrderTotal
FROM
Orders o
JOIN (
SELECT
o.Customer_ID,
MAX(o.OrderPlaceServiceTime) 'MaxOrderPlaceServiceTime'
FROM
Orders o
LEFT JOIN Order_LineDetails oln
ON oln.Order_ID = o.Order_ID
WHERE
o.OrderPlaceServerTime >= '2012-09-01 00:00:00'
AND o.OrderPlaceServerTime <= '2012-12-01 00:00:00'
AND o.CustomerOrderTotal >= '50'
AND oln.Product_ID = '75'
GROUP BY o.Customer_ID
) AS A
ON
o.Customer_ID = A.Customer_ID AND
o.OrderPlaceServiceTime = A.MaxOrderPlaceServiceTime

If I understood correctly what you need, this should be the query :
SELECT * FROM
( SELECT
o.Order_ID,
o.Customer_ID,
o.OrderPlaceServerTime,
o.CustomerOrderTotal
FROM
Orders o
LEFT JOIN Order_LineDetails oln
ON oln.Order_ID = o.Order_ID
WHERE
o.OrderPlaceServerTime >= '2012-09-01 00:00:00'
AND o.OrderPlaceServerTime <= '2012-12-01 00:00:00'
AND o.CustomerOrderTotal >= '50'
AND oln.Product_ID = '75'
ORDER BY o.Customer_ID, o.OrderPlaceServerTime DESC ) AS tab1
GROUP BY o.Customer_ID;

Related

How to obtain records with a higher amount only in cases where there is duplication in the code field?

I have the following mysql query:
SELECT pagos.id, codigo_factura as code, pagos.importe as amount
FROM pagos INNER JOIN m_labores p ON (pagos.id_producto = p.id)
INNER JOIN maquinas m ON (pagos.id_maquina = m.id)
WHERE m.id = 561 AND fecha_registro BETWEEN '2022-10-11 00:00:00' AND '2022-10-18 23:59:59'
ORDER BY pagos.id DESC
LIMIT 10 OFFSET 0
The query returns the following data:
The result I want:
I would like that if there are 2 records with the same code, the query would return only the record whose amount is greater.
I have tried the following:
SELECT pagos.id, codigo_factura as code, pagos.importe as amount
FROM pagos INNER JOIN m_labores p ON (pagos.id_producto = p.id)
INNER JOIN maquinas m ON (pagos.id_maquina = m.id)
WHERE m.id = 561 AND fecha_registro BETWEEN '2022-10-11 00:00:00' AND '2022-10-18 23:59:59'
GROUP BY codigo_factura
HAVING pagos.importe > 0
ORDER BY pagos.id DESC
LIMIT 10 OFFSET 0
This does not work for me because I want the records with a null amount to continue to appear in cases where code is not duplicated.
Is there any way to do it?
SELECT codigo_factura as code, MAX(pagos.importe) as amount
FROM pagos
INNER JOIN m_labores p ON (pagos.id_producto = p.id)
INNER JOIN maquinas m ON (pagos.id_maquina = m.id)
WHERE m.id = 561 AND fecha_registro BETWEEN '2022-10-11 00:00:00' AND '2022-10-18 23:59:59'
GROUP BY code
will return maximal amount per codigo_factura. These data may be used for to select according id value from another copy of the tables pack:
SELECT MAX(pagos.id) id, codigo_factura as code, pagos.importe as amount
FROM pagos
INNER JOIN m_labores p ON (pagos.id_producto = p.id)
INNER JOIN maquinas m ON (pagos.id_maquina = m.id)
WHERE m.id = 561 AND fecha_registro BETWEEN '2022-10-11 00:00:00' AND '2022-10-18 23:59:59'
AND (codigo_factura, pagos.importe) IN (
SELECT codigo_factura as code, MAX(pagos.importe) as amount
FROM pagos
INNER JOIN m_labores p ON (pagos.id_producto = p.id)
INNER JOIN maquinas m ON (pagos.id_maquina = m.id)
WHERE m.id = 561 AND fecha_registro BETWEEN '2022-10-11 00:00:00' AND '2022-10-18 23:59:59'
GROUP BY code
)
GROUP BY code, amount;
MAX() and GROUP BY in outer query allows to fix the situation when the same and at the same time maximal amount value matches more than one id for the same codigo_factura. May be MIN() is more safe for you - edit in this case.
PS. A half of the columns in your code have not table alias, and you have no provided tables structures.. maybe some tables are excess, and the above query can be simplified.
In MySQL 8.0 you can use the ROW_NUMBER window function as follows:
WITH cte AS (
SELECT pagos.id, codigo_factura as code, pagos.importe as amount,
ROW_NUMBER() OVER(PARTITION BY codigo_factura ORDER BY pagos.importe DESC) AS rn
FROM pagos INNER JOIN m_labores p ON (pagos.id_producto = p.id)
INNER JOIN maquinas m ON (pagos.id_maquina = m.id)
WHERE m.id = 561 AND fecha_registro BETWEEN '2022-10-11 00:00:00' AND '2022-10-18 23:59:59'
)
SELECT id, code, amount
FROM cte
WHERE rn = 1
ORDER BY pagos.id DESC
LIMIT 10 OFFSET 0
It will assign a ranking value to each "codigo_factura" by ordering on "pagos.importe" descendently (NULL values come first). Then filtering out all rows whose ranking differs from 1 will remove smaller values for matching "codigo_factura".

insert a where condition in an aggregated sql statement

I've been trying to put a "where" clause in my aggregated sql statement,
what I want is to get the sum of qty and only display those who have a 30 or less (including zero) quantities sold.
I tried putting it in the "on" part but to no avail
SELECT p.id, p.names,p.image, coalesce(sum(o.qty), 0) as sum_product_qty
from products p left join orders_item o on p.id = o.product_id
and date(o.datesales) <= curdate() and date(o.datesales) >= curdate() - interval 6 day and
sum_product_qty <= 30 group by p.id, p.names order by sum_product_qty desc
this is my sql statement
SELECT p.id, p.names,p.image, coalesce(sum(o.qty), 0) as sum_product_qty
from products p left join orders_item o on p.id = o.product_id
and date(o.datesales) <= curdate() and date(o.datesales) >= curdate() - interval 6 day
group by p.id, p.names order by sum_product_qty desc
Use Having to filter your aggregated groups.
SELECT p.id,
p.names,
p.image,
COALESCE(SUM(o.qty), 0) AS sum_product_qty
FROM products p
LEFT JOIN orders_item o
ON p.id = o.product_id
AND date(o.datesales) <= curdate()
AND date(o.datesales) >= curdate() - interval 6 DAY
GROUP BY p.id,
p.names,
p.image
HAVING COALESCE(SUM(o.qty), 0) <= 30
ORDER BY COALESCE(SUM(o.qty), 0) DESC
Try using a having clause instead.
SELECT p.id, p.names,p.image, coalesce(sum(o.qty), 0) as sum_product_qty
from products p left join orders_item o on p.id = o.product_id
and date(o.datesales) <= curdate() and date(o.datesales) >= curdate() - interval 6 day
group by p.id, p.names order by sum_product_qty desc HAVING sum_product_qty <= 30;
A HAVING clause in SQL specifies that an SQL SELECT statement should only return rows where aggregate values meet the specified conditions. It was added to the SQL language because the WHERE keyword could not be used with aggregate functions.
The aggregated SQL statement groups the data, but the WHERE clause operates on the data row-wise, hence throwing an error.
The HAVING clause filters the data on the group row but not on the individual row.

Order by on datetime field is not working - mysql

I want to get the date of last order placed and mobile# for all the customers.
This is my query.
SELECT c.customer_id, c.mobile, COALESCE( MAX( o.order_datetime ) , '0000-00-00 00:00:00' ) AS last_order_date
FROM table_orders AS o
RIGHT JOIN table_customers AS c ON o.customer_id = c.customer_id
GROUP BY c.customer_id
ORDER BY DATE( o.order_datetime )
It works fine. But not giving me data in asc order of o.order_datetime?
What is the error in query?
Try this
ORDER BY DATE( o.order_datetime ) DESC

Mysql - Join query no common column [duplicate]

This question already has an answer here:
MySQL pivot row into dynamic number of columns
(1 answer)
Closed 6 years ago.
I have statement like this one :
SELECT
COUNT(*)AS will
FROM
ae_orders o
LEFT JOIN
ae_orders_items oi ON oi.order_uid = o.uid
WHERE
po_date >= '2016-01-01' AND po_date <= '2016-01-31' AND status_text LIKE '%wil%'
This query is a count(*) so the result is only one field.
But i would like to execute this query 6-7 time in one time changing only the (like '%will%') part of this statement and get the result of each count side by side.
Wanted result :
I try left join, full join like this
(
SELECT
COUNT(*) AS will
FROM
ae_orders o
LEFT JOIN
ae_orders_items oi ON oi.order_uid = o.uid
WHERE
po_date >= '2016-01-01' AND po_date <= '2016-01-31' AND status_text LIKE '%wil%'
) AS will
LEFT JOIN
(
SELECT
COUNT(*) AS will
FROM
ae_orders o
LEFT JOIN
ae_orders_items oi ON oi.order_uid = o.uid
WHERE
po_date >= '2016-01-01' AND po_date <= '2016-01-31' AND status_text LIKE '%phi%'
) AS phil
I'm not really sure this is possible. If someone have a solution.
Solution
After reading some of your comments i found an other way to get and display my data.
Here is the statement to get my solution.
SELECT
'Will' AS USER,
COUNT(*) AS TOTAL
FROM
ae_orders o
LEFT JOIN
ae_orders_items oi ON oi.order_uid = o.uid
WHERE
po_date >= '2016-01-01' AND po_date <= '2016-01-31' AND status_text LIKE '%wil%'
UNION
SELECT
'Phil' AS USER,
COUNT(*) AS TOTAL
FROM
ae_orders o
LEFT JOIN
ae_orders_items oi ON oi.order_uid = o.uid
WHERE
po_date >= '2016-01-01' AND po_date <= '2016-01-31' AND status_text LIKE '%phi%'
UNION
SELECT
'Peter' AS USER,
COUNT(*) AS TOTAL
FROM
ae_orders o
LEFT JOIN
ae_orders_items oi ON oi.order_uid = o.uid
WHERE
po_date >= '2016-01-01' AND po_date <= '2016-01-31' AND status_text LIKE '%Pet%'
Instead of getting result side by side i get result one above the other.
As noted, your scenario is trying to pivot on a condition. Since all 3 queries are the same date range, just change to SUM( CASE/WHEN ) and you will have 1 row with all 3 counts.
SELECT
SUM( case when status_text LIKE '%wil%' then 1 else 0 end ) as CountWill,
SUM( case when status_text LIKE '%phi%' then 1 else 0 end ) as CountPhil,
SUM( case when status_text LIKE '%Pet%' then 1 else 0 end ) as CountPeter
from
ae_orders o
LEFT JOIN ae_orders_items oi
ON oi.order_uid = o.uid
WHERE
po_date >= '2016-01-01'
AND po_date <= '2016-01-31'

Getting order totals and sorting them using 1 query

I have the following but I am not getting the correct totals because GROUP BY does not add the group user id's total revenue.
SELECT
users.id,
Count(orders.id) AS total_orders,
SUM(item_orders.item_price * item_orders.quantity) AS total_rev
FROM
orders
LEFT JOIN
users ON orders.user_id = users.id
LEFT JOIN
item_orders ON item_orders.order_id = orders.id
WHERE
orders.date >= '2015-10-06 00:00:00' AND orders.date <= '2016-03-23 23:59:59'
GROUP BY
users.id -- ignores duplicate ids, doesn't sum total_rev for those
ORDER BY
total_rev DESC
LIMIT 0,25
I would like to use WITH ROLLUP to solve this but when I use WITH ROLLUP I can not use ORDER BY and I can't order with GROUP BY with an alias which contains my total per user id.
SELECT
users.id,
Count(orders.id) AS total_orders,
SUM(item_orders.item_price * item_orders.quantity) AS total_rev
FROM
orders
LEFT JOIN
users ON orders.user_id = users.id
LEFT JOIN
item_orders ON item_orders.order_id = orders.id
WHERE
orders.date >= '2015-10-06 00:00:00' AND orders.date <= '2016-03-23 23:59:59'
GROUP BY
users.id, total_rev DESC WITH ROLLUP -- does not work because total_rev is an alias!
LIMIT 0,25
Any suggestions on how I can get this to work? Does it make sense I do this in the DB? I am trying to save resources by letting the DB presort so I can do the paging in my application.
EDIT: As xjstratedgebx mentioned in the comments below the first query works fine and there is no reason for using WITH ROLLUP. The first query can also be shortened like so:
SELECT
orders.user_id,
Count(orders.id) AS total_orders,
SUM(item_orders.item_price * item_orders.quantity) AS total_rev
FROM
orders
LEFT JOIN
item_orders ON item_orders.order_id = orders.id
WHERE
orders.date >= '2015-10-06 00:00:00' AND orders.date <= '2016-03-23 23:59:59'
GROUP BY
orders.user_id
ORDER BY
total_rev DESC
LIMIT 0,25