I have a query like this
SELECT o.product_id,
p.name,
count(o.product_id) AS total_products_sold,
(SELECT count(o.id)
FROM ebay.`order` o) AS total_orders
FROM ebay.`order` o
INNER JOIN product p ON o.product_id = p.id
GROUP BY o.product_id
The total_orders is rerun when executed for each which not i want. I
Question:
I want the total_orders combines with every result set from the outer query.
I tried this but it only return 1 row
SELECT tps.product_id,
tps.name,
tps.total_products_sold,
count(oo.id) AS total_orders
FROM ebay.`order` oo
INNER JOIN
( SELECT o.id,
o.product_id,
p.name,
count(o.product_id) AS total_products_sold
FROM ebay.`order` o
INNER JOIN product p ON o.product_id = p.id
GROUP BY o.product_id ) AS tps ON oo.product_id = tps.product_id
Any better solution ?
Thanks.
You can use with rollup which will give you the total without changing the actual query
It wont give you the result in column of every row but you will get the result of total orders in the last row.
SELECT
o.product_id,
p.name,
count(distinct o.id) AS totalorder
FROM
ebay.`order` o
INNER JOIN
product p
ON
o.product_id = p.id
GROUP BY
o.product_id
WITH ROLLUP
For example
+-----------+------+------------+
| product_id| name | totalorder |
+-----------+------+------------+
| 2000 | A | 10 |
| 2001 | B | 20 |
| NULL | NULL | 30 | <--- Last row is having the Total order
+-----------+------+------------+
WITH ROLLUP
SELECT tps.product_id,
tps.name,
tps.total_products_sold,
s.total_orders
FROM ebay.`order` oo
INNER JOIN
(
SELECT o.id,
o.product_id,
p.name,
count(o.product_id) AS total_products_sold
FROM ebay.`order` o
INNER JOIN product p
ON o.product_id = p.id
GROUP BY o.product_id
) AS tps ON oo.product_id = tps.product_id
CROSS JOIN
(
SELECT count(id) total_orders
FROM ebay.`order`
) s
Related
First of all, apologies if this seems like a very dumb question, I have just started working with mySQL.
I have 2 tables:
1- Customer_courier_chat
2- Orders
Basically I want to do a query to count the amount of messages from a customer and the amount of messages from a courier. When I do an individual query to look for it, it works well but when I do both in the same query it returns different values.
The following query provides good results:
SELECT o.*, count(j.from_id) AS messages_courier
FROM test.orders o
INNER JOIN test.customer_courier_chat_messages j ON j.from_id = j.courier_id and o.order_id = j.order_id
Group BY o.order_id;
Results of the previous query messgaes from courier
The following one also provides good results:
SELECT o.*, count(k.from_id) AS messages_customer
FROM test.orders o
INNER JOIN test.customer_courier_chat_messages k ON k.from_id = k.customer_id and o.order_id = k.order_id
Group BY o.order_id;
Results of the previous query messages from customer
The main problem comes when I try to do both in the same query as the output is not correct.
SELECT o.*, count(j.courier_id) messages_courier, count(k.from_id) AS messages_customer
FROM test.orders o
INNER JOIN test.customer_courier_chat_messages j ON j.from_id = j.courier_id and o.order_id = j.order_id
INNER JOIN test.customer_courier_chat_messages k ON k.from_id = k.courier_id and o.order_id = k.order_id
Group BY o.order_id;
Results of previous query not working
Based on the results of the 2 invidiual queries, the previous one should provide:
order_id |city_code |messages_courier |messages_customer|
59528555 | ES | 2 | 5 |
11223344 | FR | 3 | 4 |
But, it actually provides:
order_id |city_code |messages_courier |messages_customer|
59528555 | ES | 4 | 4 |
11223344 | FR | 9 | 9 |
Am I missing something?
Thank you in advanced.
Kindly regards,
J
You can do it with conditional aggregation:
SELECT o.order_id, o.city_code,
SUM(m.from_id = m.courier_id) AS messages_courier,
SUM(m.from_id = m.customer_id) AS messages_customer
FROM test.orders o INNER JOIN test.customer_courier_chat_messages m
ON o.order_id = m.order_id
GROUP BY o.order_id, o.city_code;
You are first joining the table then using the count. You have to first pick get the count then use the join -
SELECT o.*, j.cnt messages_courier, k.cnt AS messages_customer
FROM test.orders o
INNER JOIN (SELECT order_id, COUNT(*) CNT
FROM test.customer_courier_chat_messages
WHERE from_id = courier_id
GROUP BY order_id) j ON o.order_id = j.order_id
INNER JOIN (SELECT order_id, COUNT(*) CNT
FROM test.customer_courier_chat_messages
WHERE from_id = customer_id
GROUP BY order_id) k ON o.order_id = k.order_id;
I have organizations. Each organization can have members and projects.
I want to get list of organizations with number of members and projects.
For example,
Organization | Members | Projects | Action
------------------------------------------
Org 1 | 5 | 6 | Delete - Edit
Org 2 | 2 | 9 | Delete - Edit
I am using this query,
SELECT COUNT(m.id) as members, COUNT(p.id) as projects,
o.status,o.organization_name,o.logo, o.id as id
from tbl_organizations o
LEFT JOIN tbl_organization_members m ON (o.id = m.organization_id)
LEFT JOIN tbl_projects p ON (o.id = p.organization_id)
WHERE o.status= 'active' AND o.created_by= 1
But the output of number of projects is equal to number of members.
How can I make the sample above using query?
Try this way:
SELECT o.id as id, o.organization_name, cnt_ as members, cnt_p as projects
from tbl_organizations o
LEFT JOIN (
SELECT organization_id, COUNT(id) cnt_m
FROM tbl_organization_members
GROUP BY organization_id
) m ON (o.id = m.organization_id)
LEFT JOIN (
SELECT organization_id, COUNT(id) cnt_p
FROM tbl_projects
GROUP BY organization_id
) p ON (o.id = p.organization_id)
WHERE o.status= 'active' AND o.created_by= 1
This way you JOIN to an already aggregated version of member/project tables, so as to get the count of members/projects per organization_id.
Group by the organisation columns and count distinct IDs
SELECT o.status,o.organization_name, o.logo, o.id as id,
COUNT(distinct m.id) as members, COUNT(distinct p.id) as projects,
from tbl_organizations o
LEFT JOIN tbl_organization_members m ON (o.id = m.organization_id)
LEFT JOIN tbl_projects p ON (o.id = p.organization_id)
WHERE o.status= 'active'
AND o.created_by= 1
GROUP BY o.status, o.organization_name, o.logo, o.id
You can co-related subquery:
SELECT
o.id as Organization,
(SELECT COUNT(*) FROM tbl_organization_members WHERE organization_id = o.id) as members,
(SELECT COUNT(*) FROM tbl_projects WHERE organization_id = o.id) as projects
FROM
tbl_organizations o
WHERE
o.status= 'active' AND o.created_by = 1
I have a query on 3 tables, settlement, order and passenger.
A settlement has orders, and orders has passengers.
TABLE: Settlemnt
id
TABLE: Order
id settlement_id
TABLE: passenger
id orders_id
If settlement has no orders (and then no passengers), it returns nothing.
What I want, is to return the empty settlement even if it has no orders.
It is the count(passengers) that ruins it for me and returns no settlement if empty.
This is the simplified query:
select s.id, o.id, count(distinct p.id)
from settlement s
left join orders o ON o.settlement_id = s.id
left join passenger p on p.orders_id = o.id
where s.date = '2016-02-02';
group by o.id
How can I make it return settlements with no orders?
Works for me...
SELECT s.id s_id
, o.id o_id
, p.id p_id
FROM settlement s
LEFT
JOIN orders o
ON o.sid = s.id
LEFT
JOIN passengers p
ON p.oid = o.id;
+------+------+------+
| s_id | o_id | p_id |
+------+------+------+
| 1 | NULL | NULL |
| 2 | 1 | 1 |
+------+------+------+
http://sqlfiddle.com/#!9/9a01b/4
The major problem with your query appears to be that you GROUP BY the o.id. Any settlement that has no order will have an o.id of NULL, hence all settlements with no orders will be lumped together into one row. Which s.id that is returned for this o.id is not defined (and effectively random).
Change it to GROUP BY both s.id and o.id
SELECT s.id,
o.id,
COUNT(DISTINCT p.id)
FROM settlement s
LEFT JOIN orders o ON o.settlement_id = s.id
LEFT JOIN passenger p ON p.orders_id = o.id
WHERE s.date = '2016-02-02';
GROUP BY s.id,
o.id
I have tables
table_order
product_name
Below is the SQL I have to query table_order which works perfectly in outputting the product_id but I need it to show it's name and not number. I need to modify mySQL with a LEFTJOIN to somehow connect with table product_name but I keep getting an error. So instead of
99 = 15, 99 = 16
I need
99 = name1, 99 = name2
SELECT table_order.order_id, table_order.product_id
FROM table_order
WHERE table_order.order_id=99
ORDER BY table_order.order_product_id
table table_order
_________________________
order_id | product_id |
_________________________
99 | 15 |
99 | 16 |
_________________________
table product_name
___________________________
product_id | product_name |
___________________________
15 | name1 |
16 | name2 |
___________________________
Use
SELECT a.product_id, b.product_name
FROM table_order AS a LEFT JOIN product_name AS b ON a.product_id = b.product_id
WHERE a.order_id = '99'
ORDER BY a.product_id
You need to join the tables, as you say, on product_id.
SELECT table_order.order_id, product_name.product_name
FROM table_order
INNER JOIN product_name on table_order.product_id = product_name.product_id
WHERE table_order.order_id=99
ORDER BY table_order.product_id
Select t1.product_id,t2.product_name from table_order as t1
inner join(
select * from product_name
) as t2
on t1.product_id = t2.product_name
where t1.product_id = //some Number
See if that works.
If you need to output all the orders regardless of whether the product id of that table_order has a connection to product_table, you need to use LEFT JOIN.
SELECT o.order_id, p.product_name
FROM table_order o
LEFT JOIN product_name p ON o.product_id = p.product_id
ORDER BY o.product_id
However if you just need to get all the rows that exists in both tables, you can use an INNER JOIN
SELECT o.order_id, p.product_name
FROM table_order o
INNER JOIN product_name p ON o.product_id = p.product_id
ORDER BY o.product_id
I want to find the last payment (or NULL if n/a) made for which specified product_id. Below is a representation of the tables I'm working with (simplified version).
+----------+
|Products |
|----------+
|product_id|
+----------+
+---------------+
|Orders |
+---------------+
|order_id |
|order_timestamp|
|order_status |
+---------------+
+-----------------+
|ProductsOrdersMap|
+-----------------+
|product_id |
|order_id |
+-----------------+
After JOINs, MAXs, GROUP BYs, LEFT JOINs, multiple INNER JOINs to get the greatest-n-per-group, I still can't get to the right result. Most of the times, products with multiple orders are returning multiple rows. The best results I got so far were (I was searching specific products):
product_id order_id order_timestamp order_status
8 NULL NULL NULL
9 NULL NULL NULL
10 NULL NULL NULL
12 NULL NULL NULL
13 NULL NULL NULL
14 11 2013-08-13 07:22:01 finished
15 11 2013-08-13 07:22:01 finished
15 12 2013-08-14 00:00:00 finished
32 11 2013-08-13 07:22:01 finished
83 9 2013-08-13 07:04:02 finished
83 10 2013-08-13 07:11:42 finished
Edit: After PP. anwser, I ended up with the following query:
SELECT p.product_id, o.order_id, MAX(order_timestamp) AS order_timestamp, order_status
FROM Products p LEFT JOIN (ProductsOrdersMap m, Orders o)
ON (p.product_id = m.product_id AND m.order_id = o.order_id)
WHERE p.product_id IN (8,9,10,12,13,14,15,32,83)
GROUP BY p.product_id
Which returns
product_id order_id order_timestamp order_status
8 NULL NULL NULL
9 NULL NULL NULL
10 NULL NULL NULL
12 NULL NULL NULL
13 NULL NULL NULL
14 11 2013-08-13 07:22:01 finished
15 11 2013-08-13 07:22:01 finished
32 11 2013-08-13 07:22:01 finished
83 9 2013-08-13 07:04:02 finished
At first glance, it seems correct but only the products IDs and the timestamps are right. Comparing the two queries above, you can see that, for products 15 and 83, order_id is wrong (order_status might be wrong as well).
This query should return the specified resultset (this is only desk checked, not tested)
to return ALL product_id
SELECT p.product_id
, m.order_d
, m.order_timestamp
, m.order_status
FROM products p
LEFT
JOIN ( SELECT kl.product_id
, MAX(ko.order_timestamp) AS latest_timestamp
FROM orderproductsmap kl
JOIN orders ko
ON ko.order_id = kl.order_id
GROUP
BY kl.product_id
) l
ON l.product_id = p.product_id
LEFT
JOIN ( SELECT ml.product_id
, mo.order_id
, mo.order_timestamp
, mo.order_status
FROM orderproductsmap ml
JOIN orders mo
ON mo.order_id = ml.order_id
) m
ON m.product_id = l.product_id
AND m.order_timestamp = l.latest_timestamp
GROUP
BY p.product_id
The inline view "l" gets us the latest "order_timestamp" for each "product_id". This is joined to inline view "m" to get us the whole row for the order that has the latest timestamp.
If there happens to be more than one order with the same latest "order_timestamp" (i.e. order_timestamp is not guaranteed to be unique for a given product_id) then the outermost GROUP BY ensures that only one of those order rows is returned.
If only particular product_id values need to be returned, add a WHERE clause in the outermost query. For performance, that same predicate can be repeated in the inline views.
to return only SPECIFIC product_id we add three WHERE clauses:
SELECT p.product_id
, m.order_d
, m.order_timestamp
, m.order_status
FROM products p
LEFT
JOIN ( SELECT kl.product_id
, MAX(ko.order_timestamp) AS latest_timestamp
FROM orderproductsmap kl
JOIN orders ko
ON ko.order_id = kl.order_id
WHERE kl.product_id IN (8,9,10,12,13,14,15,32,83)
GROUP
BY kl.product_id
) l
ON l.product_id = p.product_id
LEFT
JOIN ( SELECT ml.product_id
, mo.order_id
, mo.order_timestamp
, mo.order_status
FROM orderproductsmap ml
JOIN orders mo
ON mo.order_id = ml.order_id
WHERE ml.product_id IN (8,9,10,12,13,14,15,32,83)
) m
ON m.product_id = l.product_id
AND m.order_timestamp = l.latest_timestamp
WHERE p.product_id IN (8,9,10,12,13,14,15,32,83)
GROUP
BY p.product_id
Only the WHERE clause on the outermost query is required. The other two are added just to improve performance by limiting the size of each of the derived tables.
SELECT
P.product_id
,MAX(order_timestamp)
FROM
Products P
,Orders O
,ProductsOrdersMap M
WHERE
P.product_id = M.product_id
AND O.order_id = M.order_id
GROUP BY
P.product_id
To return all products, even those without orders, a LEFT JOIN is definitely the way to go. The answer from #PP above uses "old-style" inner joins and is equivalent to this:
SELECT
P.product_id
,MAX(order_timestamp)
FROM Products P
INNER JOIN ProductsOrdersMap M ON P.product_id = M.product_id
INNER JOIN Orders O ON O.order_id = M.order_id
GROUP BY
P.product_id
Starting with this syntax it's a lot easier to get to the LEFT JOIN - just replace INNER with LEFT:
SELECT
P.product_id
,MAX(order_timestamp)
FROM Products P
LEFT JOIN ProductsOrdersMap M ON P.product_id = M.product_id
LEFT JOIN Orders O ON O.order_id = M.order_id
GROUP BY
P.product_id
Addendum: Renato needed something more than just reworking the other answer as a LEFT JOIN because the order_id and order_status have to come along with the maximum timestamp. The easiest approach is to start with a list of product ID's and order ID's where the order has the maximum timestamp by order_id:
SELECT
p2.product_id,
o2.order_id
FROM Products p2
INNER JOIN ProductsOrdersMap m ON p2.product_id = m.product_id
INNER JOIN Orders o2 ON m.order_id = o2.order_id
WHERE (o2.order_id, o2.order_timestamp) IN (
SELECT order_id, MAX(order_timestamp)
FROM Orders
GROUP BY order_id)
Then, instead of using ProductsOrdersMap to resolve products to orders, use the results from the query above:
SELECT
p.product_id,
o.order_id,
o.TS,
o.order_status
FROM Products p
LEFT JOIN (
SELECT
p2.product_id,
o2.order_id
FROM Products p2
INNER JOIN ProductsOrdersMap m ON p2.product_id = m.product_id
INNER JOIN Orders o2 ON m.order_id = o2.order_id
WHERE (o2.order_id, o2.order_timestamp) IN (
SELECT order_id, MAX(order_timestamp)
FROM Orders
GROUP BY order_id)
) MaxTS ON p.product_id = MaxTS.product_id
LEFT JOIN Orders o ON MaxTS.order_id = o.order_id