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
Related
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.
This is a MySQL question. I have three tables with the following columns:
transactions (table): transact_id, customer_id, transact_amt, product_id,
products (table): product_id, product_cost, product_name, product_category
customers (table): customer_id, joined_at, last_login_at, state, name, email
I'd like a query that finds out the most popular item in every state and the state. One of the tricky parts is that some product_name have multiple product_id. Therefore I though joining the three tables that generate an output with two columns: state and product_name. Until here that worked fine doing this:
SELECT p.product_name, c.state
FROM products p
INNER JOIN transactions t
ON p.product_id = t.product_id
INNER JOIN customers c
ON c.customer_id = t.customer_id
This selects all the products, and the states from where the customer is. The problem is that I can't find the way to rank the mos popular product per state. I tried different group by, order by and using subqueries without success. I suspect I need to do subqueries, but I can't find the way to resolve it. The expected outcome should look like this:
most_popular_product | state
Bamboo | WA
Walnut | MO
Any help will be greatly appreciated.
Thank you!
You need a subquery that gets the count of transactions for each product in each state.
SELECT p.product_name, c.state, COUNT(*) AS count
FROM products p
INNER JOIN transactions t
ON p.product_id = t.product_id
INNER JOIN customers c
ON c.customer_id = t.customer_id
GROUP BY p.product_name, c.state
Then write another query that has this as a subquery, and gets the highest count for each state.
SELECT state, MAX(count) AS maxcount
FROM (
SELECT p.product_name, c.state, COUNT(*) AS count
FROM products p
INNER JOIN transactions t
ON p.product_id = t.product_id
INNER JOIN customers c
ON c.customer_id = t.customer_id
GROUP BY p.product_name, c.state
) AS t
GROUP BY state
Finally, join them together:
SELECT t1.product_name AS most_popular_product, t1.state
FROM (
SELECT p.product_name, c.state, COUNT(*) AS count
FROM products p
INNER JOIN transactions t
ON p.product_id = t.product_id
INNER JOIN customers c
ON c.customer_id = t.customer_id
GROUP BY p.product_name, c.state
) AS t1
JOIN (
SELECT state, MAX(count) AS maxcount
FROM (
SELECT p.product_name, c.state, COUNT(*) AS count
FROM products p
INNER JOIN transactions t
ON p.product_id = t.product_id
INNER JOIN customers c
ON c.customer_id = t.customer_id
GROUP BY p.product_name, c.state
) AS t
GROUP BY state
) AS t2 ON t1.state = t2.state AND t1.count = t2.maxcount
This is basically the same pattern as SQL select only rows with max value on a column, just using the first grouped query as the table you're trying to group.
I'm pretty new with SQL, and this is giving me trouble. The idea is that I have several tables. Here are the relevant tables and columns:
customers:
customer_id, customer_name
orders:
order_id, customer_id
orderline:
order_id, item_id, order_qty
items:
item_id, unit_price
I need to return customer_name as well as total revenue from that customer (calculated as item_price * order_qty * 2).
Here's what I have written:
SELECT customers.customer_name, sum(revenue)
FROM SELECT orderline.order_qty * items.unit_value * 2 AS revenue
FROM orderline
INNER JOIN orders
ON orderline.order_id = orders.order_id
INNER JOIN customers
ON revenue.customer_id = customers.customer_id;
This throws a syntax error and I'm not really sure how to proceed.
This is only one example of this type of problem that I need to work out, so more generalized answers would be helpful.
Thanks in advance!
EDIT:
With help from answers I ended up with this code, which just gets total revenue and puts it next to the first person in the DB's name. What did I get wrong here?
SELECT customers.customer_name, sum(revenue)
FROM(SELECT orderline.order_qty * items.unit_price * 2 AS revenue, orders.customer_id AS CustomerID
FROM( orderline
INNER JOIN orders
ON orderline.order_id = orders.order_id
INNER JOIN items
ON orderline.item_id = items.item_id)) CustomerOrders
INNER JOIN customers
ON CustomerOrders.CustomerID = customers.customer_id;
A couple issues with your query.
First, you need to scope your subquery and alias it:
(SELECT orderline.order_qty * items.unit_value * 2 AS revenue
FROM orderline
INNER JOIN orders
ON orderline.order_id = orders.order_id) CustomerOrders
Secondly, you need to select more than the revenue in the subquery since you are joining it to your customers table
(SELECT
orderline.order_qty * items.unit_value * 2 AS revenue,
orders.customer_id AS CustomerId
FROM
orderline
INNER JOIN orders ON orderline.order_id = orders.order_id) CustomerOrders
Then you need to use the subquery alias in the join to the customers table and wrap it all up in a group by customer_id and CustomerOrders.Revenue
I would tend to do it differently. I'd start with selecting from the customer table, because that is the base of what you are looking for. Then I'd do a cross apply on the orders that would all aggregating the order revenue in the subquery. It would look like this (tsql, you could do the same in mysql with a join with some aggregation):
SELECT
customers.customer_name,
ISNULL(customerOrders.Revenue, 0) AS Revenue
FROM
customers
OUTER APPLY (
SELECT
SUM (orderline.order_qty * items.unit_value * 2) AS Revenue
FROM
orders
INNER JOIN
orderline ON orders.order_id = orderline.order_id
INNER JOIN
items on orderline.item_id = items.item_id
WHERE
orders.customer_id = customers.customer_id
) CustomerOrders
In this case, the subquery aggregates all your orders for you and only returns one row per customer, so no extraneous returned data. Since it's an outer apply, it will also return null for customers with no orders. You could change it to a CROSS APPLY and it will filter out customers with no orders (like an INNER JOIN).
SELECT c.customer_name,
sum(COALESCE(ol.order_qty,0) * COALESCE(i.unit_value,0) * 2)
FROM customers c
INNER JOIN orders o
ON o.customer_id = c.customer_id;
INNER JOIN orderline ol
ON ol.order_id = o.order_id
INNER JOIN items i
ON i.item_id = ol.item_id
GROUP BY c.customer_id
select customer_name, sum(item_price * order_qty * 2) as total_revenue
from (
select * from customers
inner join orders using(customer_id)
inner join orderline using(order_id)
inner join items using(item_id)
)
group by customer_name
select
c.customer_name,
r.revenue
from
customers c
inner join
orders ord on
ord.customer_id = c.customer_id
inner join
(select i.item_id, o.order_id, sum(o.order_qty * items.unit_value * 2) as revenue
from orderline o
inner join items i on
i.item_id = o.item_id
group by o.order_id, i.item_id) as r on r.order_id = o.order_id
I have a database structure with the following setup:
po: id, stockNumber, factoryId, other columns
order: id, stockNumber, factoryId, other columns
stock_number: id, stockNumber, groupId
factory: id, name, groupId
The important part here is the stock_number/factory tables. The groupId column is just an integer and if two or more rows in the table have the same value then their stock numbers/factory are considered the same. Typically this is used for different sizes of the same product.
What I'd like to do is write a query that will join "order" to "po" through the group of stock_number and factory so I can find orders with no matching po. Also the factory has to match the same way.
I have this query if I have a specific stock number/factory in mind but I'd like to update it to query the whole orders table for me:
SELECT id
FROM order
WHERE
styleNumber IN (SELECT a.stockNumber FROM stock_number a INNER JOIN stock_number b ON a.groupId = b.groupId or a.id = b.id WHERE b.stockNumber = '123')
AND factoryId IN (SELECT a.submitter_id FROM submitter a INNER JOIN submitter b ON a.groupId = b.groupId OR a.submitter_id = b.submitter_id WHERE b.SUBMITTER_ID = 'alpha');
EDIT: I came up with this query which I think might be on the right track. It only joins in the stock number so it doesn't do factory yet. Can anyone confirm if I'm going in the correct direction:
SELECT *
FROM order o
LEFT JOIN stock_number s_o ON o.stockNumber = s_o.stockNumber
LEFT JOIN stock_number s_p ON s_o.groupId = s_p.groupId
LEFT JOIN po p ON s_p.stockNumber = p.stockNumber
WHERE p.id IS NULL;
Just join all the tables.
select o.id
FROM order AS o
JOIN stock_number AS sn ON sn.stockNumber = o.stockNumber
JOIN submitter AS su ON ON o.factoryId = su.submitter_id
You could use an anti-join pattern. In this example, it looks complicated because of the two relationship tables. But a query something like this:
SELECT o.id
, o.stockNumber
, o.factoryId
FROM `order` o
LEFT
JOIN `stock_number` s
ON s.stockNumber = o.stockNumber
LEFT
JOIN `factory` f
ON f.id = o.factoryId
AND f.groupId = s.groupId
LEFT
JOIN `po` p
ON p.stockNumber = s.stockNumber
AND p.factoryId = f.id
WHERE p.id IS NULL
The anti-join pattern is easier to visualize with a simpler example. Say you had the order table (as in your example), and an order_line table, with rows related to the order table by the order_id column.
order_line: id, order_id, othercolumns
To get order along with matching order_line rows:
SELECT o.id AS order_id
, l.id AS line_id
FROM `order` o
JOIN `order_line` l
ON l.order_id = o.id
To include rows from order that don't have any matching rows in order_line, we can use an outer join. We add the LEFT keyword:
SELECT o.id AS order_id
, l.id AS line_id
FROM `order` o
LEFT
JOIN `order_line` l
ON l.order_id = o.id
That gets all rows from order, including rows that don't have a matching row in order_line. The trick now is to exclude all the rows that have a matching row. For any rows that didn't have a match, the columns from order_line will be NULL. So we can add a test in the WHERE clause, to exclude rows that had a match.
SELECT o.id AS order_id
, l.id AS line_id
FROM `order` o
LEFT
JOIN `order_line` l
ON l.order_id = o.id
WHERE l.order_id IS NULL
That gets us rows from order that don't have a matching row in order_line.
We can use this same pattern in a more complicated query. We use outer join operations, and rows from order that don't have a matching row in po will have NULL values for the columns from po.
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