mySQL SQL joined table then find rows with duplicates - mysql

I have two tables:
Orders
orders_ID
orderDate
Order Details
product_ID
order_ID
quantity
Products
product_ID
productName
productDescription
I want to find all the records in the Order Details of product_ID 1 and 4 (so trying to see when one order contains both of these products). So ran this code - the INNER JOIN creates a results table that contains only orders that contain product 1, 4, or 1 and 4.
Then I want to count all of the "Order Details".order_ID duplicates - these would be all of the orders that contain 1 and 4 (note- trivial database - a given order doesn't contain more than 1 of any product).
Here is my code - doesn't quite work - any thoughts?
SELECT order_ID, COUNT(*) TotalCount
FROM
(SELECT * FROM Orders o INNER JOIN "Order Details" od ON o.order_ID = od.order_ID
WHERE od.product_ID = 1 OR od.product_ID = 4)
GROUP BY order_ID
HAVING COUNT(*) > 1
ORDER BY COUNT(*) DESC
Thanks- I looked through the forum but didn't see anything that helped me - been trying for some time.

I think what you want is a JOIN:
select prod1.order_id from `Order Details` prod1 JOIN `Order Details` prod4 on prod1.order_ID=prod2.order_ID where prod1.product_ID=1 and prod2.product_ID=4;

Related

SQL query involving comparison of sets

Background
Products can be sold as bundles. Following tables are present: products, bundles, bundles_products, orders, orders_products.
An order would be said to "contain" a bundle if it contains all the bundle's products.
Problem
How would one go about counting orders for bundles?
Example
products table
id name
1 broom
2 mug
3 spoon
4 candle
bundles table
id name
1 dining
2 witchcraft
bundles_products table
bundle_id product_id
1 2
1 3
2 1
2 4
orders_products table
order_id product_id
1000 1
1000 3
1001 1
1001 2
1001 3
The query would return the following table:
bundle orders
dining 1
witchcraft 0
Notes
The example intentionally misses the orders table as it is not relevant what it contains.
Of course, this could be approached imperatively, by writing some code and gathering the data, but I was hoping there is a declarative, SQL way of querying for this kind of things?
One idea I had was to use a GROUP_CONCAT to concatenate all the products of a bundle and somehow compare that with products of each order. Still, a long way from clear.
One way is to use two Derived Tables (subqueries). In first subquery, we will fetch the total number of unique products for every bundle. In the second subquery, we will fetch the total products in an order, for a combination of order and bundle.
We will LEFT JOIN them on bundle_id as well as matching the total count of products per bundle in them. Eventually, we will do a grouping on bundle, and count the number of orders matching successfully.
SELECT dt1.id AS bundle_id,
dt1.name AS bundle,
Count(dt2.order_id) AS orders
FROM (SELECT b.id,
b.name,
Count(DISTINCT bp.product_id) AS total_bundle_products
FROM bundles AS b
JOIN bundles_products AS bp
ON bp.bundle_id = b.id
GROUP BY b.id,
b.name) AS dt1
LEFT JOIN (SELECT op.order_id,
bp.bundle_id,
Count(DISTINCT op.product_id) AS order_bundle_products
FROM orders_products AS op
JOIN bundles_products AS bp
ON bp.product_id = op.product_id
GROUP BY bp.bundle_id,
op.order_id) AS dt2
ON dt2.bundle_id = dt1.id
AND dt2.order_bundle_products = dt1.total_bundle_products
GROUP BY dt1.id,
dt1.name
SQL Fiddle DEMO
Here's the brief example, which lacks some parts, I omitted because I don't know precise database structure. Logic is such:
Temp table is generated, which consists of 3 rows - order, count of
products related to bundle, count of products in bundle
Then we select only orders from this table in which we have those last two
variables equal
select count(order_id) from orders
left join(
select count(*) from bundles_products as bundle_amount,
sum(case when orders_products in (
select names from bundles_products where bundle_id='1') then 1 else 0) as order_total,
orders.order_id
left join product on bundle_products.product_id = products.product_id
left join orders on products.product_id = orders_products.product_id
where bundle_products.bundle_id ='1'
) as my_table
on orders.order_name = my_table.orders
where my_table.bundle_amount = my_table.order_total
Edit: I posted this as a response to previous version of the question, without detailed explanation.
Edit2: fixed query a bit. It can be starting point. Logic is still the same, you can get amount of orders for each bundle_id using it

SQL query to get results between 2 tables, and the second one has 3 possibilities of returning data

Even though my question was warned as similar title, I couldn't find here any similar problem. Let me explain in details:
I've got two tables (I'm working with MySQL) with these values inserted:
table products:
id name
1 TV
2 RADIO
3 COMPUTER
table sales (product_id is A FK which references products(id)):
id quantity product_id
1 50 2
2 100 3
3 200 3
The tv's haven't been sold, radios got 1 sale (of 50 unities) and computers got two sales (one of 100 e other of 200 unities);
Now I must create a query where I can show the products and its sales, but there are some conditions that make that task difficult:
1 - If there's no sales, show obviously NULL;
2 - If there's 1 sale, show that sale;
3 - If there's more than 1 sale, show the latest sale (which I've tried to use function MAX(id) to make it simple, and yet didn't worked);
In the tables example above, I expect to show this, after a proper SQL Query:
products.NAME sales.QUANTITY
TV NULL
RADIO 50
COMPUTER 200
I've been trying lots of joins, inner joins, etc., but couldn't find the result I expect. Which SQL query can give the answer I expect?
Any help will be very appreciated.
Thanks.
Hope the below query works.
SELECT products.name, sl.quantity
FROM products LEFT JOIN (
SELECT product_id, max(quantity) as quantity FROM sales GROUP BY product_id) sl
ON products.id = sl.product_id
In MySQL 8.0 you can do:
with m (product_id, max_id) as ( -- This is a CTE
select product_id, max(id) from sales group by product_id
)
select
p.name,
s.quantity
from products p
left join m on m.product_id = p.id
left join sales s on s.id = m.max_id
If you have an older MySQL, you can use a Table Expression:
select
p.name,
s.quantity
from products p
left join ( -- This is a table expression
select product_id, max(id) as max_id from sales group by product_id
) m on m.product_id = p.id
left join sales s on s.id = m.max_id

SQL query to get a result based on count of records in other table

I have 3 tables in MySQL DB: orders, items and item_to_orders. That last table, item_to_orders, ties orders and items together by item_id and order_id indexes.
orders:
order_id order_name order_status
1 Test 0
2 Test2 1
items:
item_id item_name
1 item1
2 item2
item_to_order
order_id item_id
1 1
2 2
I need to select one item_id from items table, that has no orders with order_status=0 assigned to it in item_to_order table. It can have any other orders (where order_status != 0) assigned to it or no orders at all.
Updated: I was trying to use this query, but it seems that it doesn't give me all the correct results (I added LIMIT because I need only 1 item of that kind).
SELECT ei.item_id from items ei
LEFT JOIN items_to_orders eio ON ei.item_id=eio.item_id
WHERE NOT EXISTS
(select * from orders o where o.order_id = eio.order_id and o.order_status=0)
ORDER BY ei.item_id LIMIT 1
You approach is already quite fine. EXISTS is the way to go. Only you don't want to see item/order combinations for which not exists a certain order type, but items. So you must put items_to_orders inside the subquery, so you select from items for which not exists the order type.
select item_id
from items i
where not exists
(
select *
from items_to_orders ito
join orders o on o.order_id = ito.order_id
where ito.item_id = i.item_id
and o.order_status = 0
);
Try this query
SELECT i.item_id, i.item_name
FROM order o
JOIN item_to_order ir ON(ir.order_id = o.order_id)
JOIN items i ON(i.item_id =ir.item_id)
WHERE o.order_status!=0
GROUP BY i.item_id

Inverse of Inner join (Intersect) with multiple foreign keys

Hi I want to get opposite of intersect from two tables.
I have a sale table and purchase table. What I want to do is get all purchases ids where not included in the sales table.
sale table
sale_id (pk)
product_id (fk)
purchase_id (fk)
purchase table
product_id (fk)
purchase_id (pk)
SELECT DISTINCT purchase_id
, product_id
FROM
purchase
INNER JOIN sale
USING (purchase_id, product_id);
Here is an example:
If I run the above code, this will be the result.
purchase_id product id
1 1
1 2
1 4
2 1
2 3
Now I want to get:
purchase_id product id
1 3
2 2
In short I want to get inverse of above code. Thanks in advance.
Okay, I think I understand better now.
This should return any entry in purchase that have no matching entry in sales.
SELECT
`purchase`.`purchase_id`, `purchase`.`product_id`
FROM `purchase`
LEFT JOIN `sale` ON `sale`.`purchase_id` = `purchase`.`purchase_id` AND `sale`.`product_id` = `purchase`.`product_id`
WHERE
`sale`.`sale_id` IS NULL
ORDER BY
`purchase`.`purchase_id`, `purchase`.`product_id`
If you want to get all the purchases that have no related values in the sales table, you can use a LEFT JOIN:
select
p.purchase_id
from
purchase as p
left join sale as s on p.purchase_id = s.purchase_id
where
s.purchase_id is null;
"Unilateral" joins (LEFT JOIN, RIGHT JOIN) are useful when you want to get data from a table even if data in another related table does not exist. Of course, that means that you can filter data from one table when there's no related data in a second table.
Hope this helps.
Looking at your updated question and your comment, I think that you want all the possible combinations not used.
You'll need to split this in two steps:
First you need all the possible combinations of purchase_id and sale_id values (the "cartesian product" of both the sets).
Then you need to get all the combinations already used.
Finally you need to exclude all the combinations already used.
This can be done using subqueries.
Step 1.
select distinct p.purchase_id, s.product_id from purchase as p, sale as s;
Step 2. (Your query)
select distinct
purchase_id, product_id
from
purchase as p
inner join sale as s
on (p.purchase_id = s.purchase_id and p.product_id = s.product_id);
Step 3. Put it all together
select
a.*
from
(select distinct p.purchase_id, s.product_id from purchase as p, sale as s) as a
left join (
select distinct
purchase_id, product_id
from
purchase as p
inner join sale as s
on (p.purchase_id = s.purchase_id and p.product_id = s.product_id)
) as e on (a.purchase_id = e.purchase_id and a.product_id = e.product_id)
where
e.purchase_id is null and e.product_id is null;

MySQL UPDATE with SELECT SUM from different table

I have two tables:
ITEMS with quantities and unit_price (id | name | order_id | qt | unit_price)
and table ORDERS.
I want to UPDATE table orders and place in orders.total_price sum of multiplications qt*unit_price for the same orders to get total price of the order.
The SELECT query on the items table is quite simple and works fine giving sums for all items within the same order_id:
SELECT SUM(items.qt*items.unit_price) from items GROUP by items.order_id
but I can't insert this value in my ORDERS table. I couldn't make this work:
UPDATE orders, items SET orders.total_price = (SELECT SUM(items.qt*items.unit_price)
FROM items GROUP BY items.order_id) WHERE orders.id = items.order_id
it returns "Subquery returns more than 1 row"
I found a very similar question here but the answer didn't work for me as well:
UPDATE orders SET orders.t_price = (SELECT SUM(items.qt*items.unit_price) from items WHERE orders.id = items.order_id)
You can UPDATE with JOINing the two tables:
UPDATE Orders o
INNER JOIN
(
SELECT order_id, SUM(qt * unit_price) 'sumu'
FROM items
GROUP BY order_id
) i ON o.id = i.order_id
SET o.total_price = i.sumu
[WHERE predicate]