i'm looking for solution to check if multiple rows from one table have match in other table. In my situation i need to check if items from orders are in storage. Currently I use php to check orders - script is taking open orders and foreach one by one to check storage. It's generating quite a lot of queries and it's not efficient at all and i'm looking for solution to do this via sql query.
Desired result should be:
OrderId | Date | Products
1002/02 | 2020/08/16 | 1x Ipod; 2x battery; 9x some item;
0333/4 | 2020/06/22 | 10x shelf
Storage products table
id | id_product | quantity
Orders
id | reference | id_status | created_at
Order Products
Id | id_order | quantity | id_storage_product
I've written some code to generate table visible above but result it's not even close to desired.
select('orders.id', orders.created_at','orders.reference', 'storage_products.id as storageProductId')
->join('order_products', 'orders.id', '=', 'order_products.id_order')
->join('storage_products', 'order_products.id_product', '=', 'storage_products.id_product')
->where('storage_products.quantity', '>=', 'order_products.quantity')
->whereIn('orders.id_status', array(1, 2)) //get new orders/ open
->where('order_products.id_storage_product', null)
->groupBy('orders.id');
Clean sql:
SELECT `orders`.`id`,
`orders`.`created_at`,
`orders`.`reference`,
`storage_products`.`id` AS `storageProductId`,
`order_products`.`id_order`
FROM `orders`
INNER JOIN `order_products`
ON `orders`.`id` =
`order_products`.`id_order`
INNER JOIN `storage_products`
ON `order_products`.`id_product` =
`storage_products`.`id_product`
WHERE `storage_products`.`quantity` >=
'order_products.quantity'
AND `orders`.`id_status` IN ( 1, 2 )
AND `order_products`.`id_storage_product` IS NULL
GROUP BY `orders`.`id`
ORDER BY `orders`.`id` ASC
So code should find open orders (id_status); where storage quantity is equal or greater than product in order; where id_storage_products is null (means product bought on website but it was not in storage when ordered). Upper query result is wrong because it showed me partial match to storage - even without checking quantity (some products have 0 but still displayed).
For any help many thanks
EDIT: fiddle sample: https://www.db-fiddle.com/f/6jKvKXPYvsLeXgm3Qv1nHu/0
I tried the following query on the db-fiddle link and this works.
SELECT
orders.reference, orders.created_at, order_products.id_product
FROM
storage_products
LEFT JOIN
order_products ON storage_products.id_product = order_products.id_product
LEFT JOIN
orders ON orders.id = order_products.id_order;
What I did in the query is calling all storage_products with the same id_product
in order_products and proceed to call all orders in the called order_products.
Your query contains the condition:
AND `order_products`.`id_storage_product` IS NULL
but in your sample data all values are 0
.
So instead I use COALESCE()
to cover both cases.
Also I removed the condition:
AND `orders`.`id_status` IN ( 1, 2 )
because the column id_status
is not included in the definition of the table orders
in your sample data.
This query works:
SELECT o.id,
o.reference,
o.created_at,
GROUP_CONCAT(op.quantity, 'x', op.id_product separator ' ;') products
FROM orders o
INNER JOIN order_products op ON o.id = op.id_order
INNER JOIN storage_products sp ON op.id_product = sp.id_product
WHERE sp.quantity >= op.quantity AND COALESCE(op.id_storage_product, 0) = 0
GROUP BY o.id, o.reference, o.created_at
ORDER BY o.id ASC
See the demo .
Results:
| id | reference | created_at | products |
| --- | --------- | ------------------- | ------------- |
| 2 | 345554/02 | 2020-08-22 00:00:00 | 3x188 ; 1x155 |
If you also join the table products
(I assume there is such a table) you can get the names of the products instead of their ids.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.