I have two tables: orders and order_items.I need to update the column xpto_spent on orders table with the sum of the total spent with items of the brand XPTO (items described in order_items table).
My current query is returning timeout from mysql server. The timetou is set to 28800 seconds.
UPDATE orders
SET orders.xpto_spent = (
select
format( sum(total), 2) as xpto_spent
from order_items
where order_items.brand = "XPTO"
AND orders.order_id = order_items.order_id
group by order_items.order_id
);
Any help will be appreciated! Thank you!
You can join the table orders to the query that returns all the sums from order_items:
UPDATE orders o
INNER JOIN (
SELECT order_id, FORMAT(SUM(total), 2) AS xpto_spent
FROM order_items
WHERE brand = 'XPTO'
GROUP BY order_id
) t ON o.order_id = t.order_id
SET o.xpto_spent = t.xpto_spent
You would generally do this using join, but you can use a correlated subquery:
UPDATE orders o
SET o.xpto_spent = (SELECT SUM(oi.total)
FROM order_items oi
WHERE oi.brand = 'XPTO' AND
oi.order_id = o.order_id
);
For this query, you want an index on order_items(order_id, brand, total). That will probably speed your query.
Related
I'm trying to make this MySQL code more readable:
UPDATE customers
SET last_order_date = (SELECT MAX(date) FROM orders WHERE customers.customer_id = orders.customer_id),
added_note = (SELECT note FROM orders WHERE customers.customer_id = orders.customer_id
AND date = (SELECT MAX(date) FROM orders WHERE customers.customer_id = orders.customer_id));
The example code adds the date and note of the most recent order of each customer to the corresponding row in the customer table, but it has to SELECT the most recent order date for any given customer twice.
I tried the alias syntax suggested here:
UPDATE customers
SET last_order_date = (SELECT MAX(date) AS `maxdate` FROM orders WHERE customers.customer_id = orders.customer_id),
added_note = (SELECT note FROM orders WHERE customers.customer_id = orders.customer_id
AND date = `maxdate`);
I also tried without the AS keyword:
UPDATE customers
SET last_order_date = (SELECT MAX(date) maxdate FROM orders WHERE customers.customer_id = orders.customer_id),
added_note = (SELECT note FROM orders WHERE customers.customer_id = orders.customer_id
AND date = maxdate);
But in neither cases the alias is recognized.
Is there a way I can assign an intermediate result to a name and refer to it later?
With MySQL 8.0, you can use a CTE:
WITH o AS (
SELECT date, note, customer_id,
ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY date DESC) AS rownum
FROM orders
)
UPDATE customers AS c
INNER JOIN o USING (customer_id)
SET c.last_order_date = o.date,
c.added_note = o.note
WHERE o.rownum = 1;
With older versions of MySQL that don't support CTE, here's how I would code it:
UPDATE customers AS c
INNER JOIN orders AS o1
ON c.customer_id=o1.customer_id
LEFT OUTER JOIN orders AS o2
ON o1.customer_id=o2.customer_id AND o1.date < o2.date
SET c.last_order_date = o1.date,
c.added_note = o1.note
WHERE o2.customer_id IS NULL;
The outer join returns NULL for all columns of the joined table when there is no match. If there's no row o2 with a greater date than row o1, then o1 must be the row with the greatest date for the respective customer_id.
The latter solution may result in ties. That is, there may be more than one row tied for the greatest date for a given customer. The CTE solution won't have that issue.
I'm using MySQL, and I have an orders table and an order_items table. An order can have many order_items. The foreign key in order_items is orderId. In my database there are 26 orders and 69 order_items. I want to get all orders, while joining to the order_items table - but only joining to one order_item for each order. So the result should be 26 rows.
select o.*, oi.amount from orders o
JOIN order_items oi on o.id = (select orderId from order_items where orderId =
o.id group by orderId);
orders Table:
id
email
total
createdTimestamp
order_items table:
id
orderId
amount
status
Somehow, this is giving me 1794 rows back when I expect 26, and I am drawing a complete blank at to what is going on.
It does not mater which order_item row is joined to for each order.
EDIT
This will work:
select o.*, oi.amount from order_items oi
join orders o on o.id = oi.orderId
group by oi.orderId;
But how can it be done by using the orders table in the from and joining to order_items?
If you want one item per order, then use window functions:
select o.*, ol.*
from orders o join
(select ol.*,
row_number() over (partition by orderId order by rand()) as seqnum
from order_items oi
) oi
on o.id = oi.orderId and seqnum = 1;
I have 2 table - orders and orderdetail.
I need to join them together and show the total. I can join them but how do I calculate the total?
SELECT *
FROM Orders as o
INNER JOIN OrderDetails as od on o.order_id = od.order_id
WHERE o.table_id = 1
select a.order_id,
order_date,
order_status,
table_id,
item_id,
item_price,
quantity,
b.item_price*b.quantity as total
from dbo.orders as a inner join dbo.orderdetails as b
on a.order_id=b.order_id
WHERE table_id = 1
Update : as you mentioned in comment if you want a computed column which automatically multiply quantity and item_price, then you need
execute this query :
ALTER TABLE dbo.orderdetails ADD Total AS (quantity* item_price);
I need help writing a MySQL query. So far, none of the questions out there seem to fit my needs.
I have an order table and an order_log table. In the order_log table I make a record every time an order's status is changed. I need to display a list of the most recent status changes from the order_log table. The query I'm currently using does a JOIN on the two tables and grabs everything where order.status = order_log.status.
The problem with this is that some times an order will pass through the same status more than once. When that occurs, my query grabs every entry in the order_log table for that order and that status, but I only want the most recent log.
I tried writing a new JOIN query to grab the Max of the order_log date entry, but it's only returning 1 entry. This is what I have.
SELECT *
FROM order_status_log AS l
JOIN orders AS o ON ( l.order_id = o.id )
WHERE l.status = o.status
AND l.date = (
SELECT MAX( date )
FROM order_status_log l2
JOIN orders AS o2 ON ( l2.order_id = o2.id )
)
Any ideas?
there are many ways to do it, one is to have a separate subquery the gets the latest entry of each record: order_ID.
The result of the subquery is then joined back with the original table but has multiple conditions: that it matches the order_ID and also the latest date.
SELECT a.*, b.*
FROM `order` a
INNER JOIN order_log b
ON a.id = b.order_ID
INNER JOIN
(
SELECT order_ID, MAX(date) max_date
FROM order_log
GROUP BY order_ID
) c on b.order_ID = c.order_ID AND
b.date = c.max_date
That may help;
select olg.column1,o.column2,max(olg.date) from --You can add other columns as well
order_status_log olg
join orders o
on olg.id = o.order_id
group by olg.column1,o.column2
I have 3 tables as follows
item{id, name, price}
customer{id, name, tel_no}
order{id, time, customer_id}
order_item{id, item_id, price, order_id}
process{id, order_item_id, status}
I need to get order_items which are not processed for a particular customer. I tried with the following query. But it doesn't help. Please correct me some one.
SELECT *
FROM order_item`
INNER JOIN `order` ON `order`.id = order_item.order_id
WHERE `order`.customer_id=1 AND NOT EXISTS (
SELECT *
FROM process
WHERE process.order_item_id=order_item.id
)
I'm using mysql as my server
Select *
from order_item OI
INNER JOIN ORDER O on O.ID=OI.Order_Id
LEFT JOIN Process P ON P.Order_item_ID = OI.Item_ID
where O.Customer_ID = 1 and P.ID is null
LEFT JOin gives you all the ORDER_Items and only those records with a matching process record so P.ID will be null thus the item has not been processed