Limiting results to a distinct column with SQL - mysql

I am attempting to get a list of items along with the order information for each item. An order always has at least 1 item associated with it. I want to limit this list to all of the items from 10 orders. As my query stands below, it gets 10 items. What is the best way to LIMIT this to 10 orders, while grabbing all of the items associated with these orders (be it 10 rows or 200 rows)?
SELECT o.*, i.*
FROM orders o, items i
WHERE i.order_id = o.id
LIMIT 0, 10
Much thanks!

Try using a subselect where you limit the orders first. In the outer select you then can fetch all items to these 10 orders.
SELECT o.*, i.*
FROM items i, (SELECT * FROM orders LIMIT 0, 10) o
WHERE i.order_id = o.id

SELECT oo.*, i.*
FROM (
SELECT *
FROM orders o
LIMIT 10
) oo , items i
WHERE i.order_id = oo.id

I don't know mysql but to take a guess
SELECT o.*, i.*
FROM orders o, items i
WHERE i.order_id = o.id and
o.id in (select o.id from orders o limit 0, 10)

Something like this should work:
SELECT o.*, i.*
FROM items i INNER JOIN orders o ON o.id = i.order_id
WHERE o.order_id IN (
SELECT o.id
FROM orders
LIMIT 0, 10
)

SELECT orders1.*, items.*
FROM
(select * from orders
LIMIT 10) AS orders1
LEFT JOIN items ON orders1.id = items.order_id;

Related

mysql "distinct query" from 3 table performs slow on big data

Here is three table, order, order_record, pay, with near 2300000 records.
there will be more than 1 record in pay table when giving 1 order_id, so I need to use DISTINCT to remove repeated result
now I need to get distinct data from those three table join on order_id, the example query sql below:
SELECT
DISTINCT (a.order_id)
a.order_id,a.user_id
b.boss_order_id,
c.pay_id,
FROM order a
LEFT JOIN order_record b ON a.order_id = b.order_id AND b.is_delete IN (0,1)
LEFT JOIN pay c ON a.order_id = c.order_id AND c.is_delete =0 WHERE 1=1 AND a.is_delete IN (0,1)
ORDER BY a.id DESC LIMIT 0, 10
this query will takes plenty of time.
then I change to use "GROUP BY":
SELECT
a.order_id,a.user_id
b.boss_order_id,
c.pay_id,
FROM order a
LEFT JOIN order_record b ON a.order_id = b.order_id AND b.is_delete IN (0,1)
LEFT JOIN pay c ON a.order_id = c.order_id AND c.is_delete =0 WHERE 1=1 AND a.is_delete IN (0,1)
GROUP BY a.order_id
ORDER BY a.id DESC LIMIT 0, 10
this time the query takes 122 seconds.
Is there any faster way to implement?
You are using a left join. Hence, you can do:
SELECT o.order_id, o.user_id, orr.boss_order_id, p.pay_id,
FROM (SELECT o.*
FROM order o
WHERE o.is_delete IN (0, 1)
ORDER BY o.id DESC
LIMIT 10
) o LEFT JOIN
order_record orr
ON o.order_id = orr.order_id AND
orr.is_delete IN (0, 1) LEFT JOIN
pay p
ON o.order_id = p.order_id AND
p.is_delete = 0
WHERE 1=1 AND o.is_delete IN (0, 1)
GROUP BY o.order_id
ORDER BY o.id DESC
LIMIT 0, 10
You are using GROUP BY incorrectly, because you have unaggregated columns in the SELECT that are not in the GROUP BY.
Another approach let a where clause do most the work:
select ...
from order
left join order_using using (order_id)
...
where
order.order_id < (select max(order_id) from orders order by order_id limit 10) ...
limit 10
The final limit 10 is weird though as you may get partial records from an order if you drop the group by. I.e. you probably want to drop it and and just put a limit orders table. With the group by means you will a random data from table b and c unless you use aggregate function to tell mysql which of the row values you want.

AS in multiple Select

Is it possible to use AS within multiple selects?
something like:
SELECT O.order_id, Sum(Order_Tot) FROM
(SELECT P.price * O.qty as Order_Tot FROM crOrdersToProducts O
JOIN tblProducts P ON O.style_id = P.id)
GROUP BY O.order_id
Trying to use one query to display order totals by order id.
//try this query
SELECT OT.order_id, Sum(OT.Order_Tot) FROM
(SELECT O.order_id,P.price * O.qty as Order_Tot FROM crOrdersToProducts O
JOIN tblProducts P ON O.style_id = P.id) as OT
GROUP BY OT.order_id

LIMIT by GROUPED field instead of all rows returned

I'm using this (simplified):
SELECT
o.order,
GROUP_CONCAT(oi.article)
FROM orders o
JOIN order_items oi
ON o.order = oi.order
GROUP BY o.order
LIMIT 50
to get the last 50 orders with all order items.
But I need the order items to be in their own rows (veritcally returned) instead of GROUP_CONCAT horizontally returned.
How can I return all order items of the last 50 orders with a single order item in each row?
Use a subquery to select the last 50 orders, and then join this with the items.
select o.order, oi.article
from (SELECT order
FROM orders
ORDER BY order_date DESC
LIMIT 50) o
JOIN order_items oi
ON o.order = oi.order
You talk about the last 50 items, but you don't mention a date_field to ORDER BY. Having that date_field in orders table you can do:
SELECT o.order, oi.article
FROM (SELECT order
FROM orders
ORDER BY date_field DESC
LIMIT 50 ) o
INNER JOIN order_items oi ON o.order = oi.order

Select where number of results is above x

I have a query like this:
SELECT
oh.date_added AS date_shipped,
o.date_added
FROM
".DB_PREFIX."order o , ".DB_PREFIX."order_history oh
WHERE
o.order_id = oh.order_id
AND oh.order_status_id = 3
What I want to do is only show results if there are X or more rows with a particular date.
So if X=5 there are three entries from the 2013-04-01, then they won't show, but if there are nine entries (or anything >= 5) from 2013-04-02 then these results will be included in the query.
Once the requirements are met I would like the query to limit to that one group of rows from the matching date.
Does anyone know how I can achieve this?
You can add nested SELECT to count these:
SELECT
oh.date_added AS date_shipped,
o.date_added
FROM
".DB_PREFIX."order o , ".DB_PREFIX."order_history oh
WHERE
o.order_id = oh.order_id
AND oh.order_status_id = 3
AND (SELECT COUNT(*) FROM ".DB_PREFIX."order o2
WHERE o2.date_added>"2013-04-01") > 5
Or join a table on itself, along the lines
SELECT
o.date,
COUNT(*) cnt
FROM
order o
JOIN order o2 ON o2.date = o.date AND o2.id != o.id
WHERE
your conditions
GROUP BY o2.id
HAVING cnt > 5

Can I execute a COUNT() before GROUP BY

I am working on an mySQL assignment for school and I am stuck on a question. I am still new to mySQL. COUNT(o.customer_id) is not working the way I want. I want it to count the number of orders but it is counting all items. i.e. Customer 1 has 2 orders but it is returning 3 because one order has two items. I have three tables one with customers, another with orders than another with each item on each order. Ive posed my query below. Any help would be great.
SELECT email_address, COUNT(o.order_id) AS num_of_orders,
SUM(((item_price - discount_amount) * quantity)) AS total
FROM customers c JOIN orders o
ON c.customer_id = o.customer_id
JOIN order_items ot
ON o.order_id = ot.order_id
GROUP BY o.customer_id
HAVING num_of_orders > 1
ORDER BY total DESC;
As simple as use Distinct reserved word:
SELECT email_address, COUNT(distinct o.order_id) AS num_of_orders
Looks like you want to count the DISTINCT number of orders. Add a DISTINCT into the COUNT. Although MySQL allows you to use the SELECT expression in the HAVING clause, it's not good practice to do so.
SELECT email_address, COUNT(DISTINCT o.order_id) AS num_of_orders,
SUM(((item_price - discount_amount) * quantity)) AS total
FROM customers c JOIN orders o
ON c.customer_id = o.customer_id
JOIN order_items ot
ON o.order_id = ot.order_id
GROUP BY o.customer_id
HAVING COUNT(DISTINCT o.order_id) > 1
ORDER BY total DESC;
Just take out the join to items. All it is doing is duplicating rows when there are multiple items.
SELECT email_address, COUNT(o.order_id) AS num_of_orders,
SUM(((item_price - discount_amount) * quantity)) AS total
FROM customers c JOIN orders o
ON c.customer_id = o.customer_id
GROUP BY o.customer_id
HAVING COUNT(o.order_id) > 1
ORDER BY total DESC;