Find an exact duplicate by join table field - mysql

I'm writing a query to find an exact duplicate of the order by its pruducts IDs.
The conditions to find a duplicate are:
1) Order has the same product count.
2) All product IDs are the same.
Tried something like this, but it didn't work:
SELECT
order.*,
count(same_products.id),
count(all_products.id)
FROM orders
LEFT JOIN products AS all_products ON all_products.order_id = orders.id
LEFT JOIN products AS same_products
ON same_products.order_id = orders.id AND same_products.id IN (30868, 30862)
GROUP BY orders.id
HAVING count(same_products.id) = 4 AND count(all_products.id = 4)

if you want count duplicated rows you should avoid the all columns (*) selector because if you have incremental values in your columns this don't let you find the duplicated .
SELECT
order.id
count(same_products.id),
count(all_products.id)
FROM orders
LEFT JOIN products AS all_products ON all_products.order_id = orders.id
LEFT JOIN products AS same_products
ON same_products.order_id = orders.id AND same_products.id IN (30868, 30862)
GROUP BY orders.id
HAVING count(same_products.id) >1 OR count(all_products.id )> 1
and for duplicated row you should check for count> 1 (for both the count)
and be careful with count(all_products.id =4) if you need to filter for this value you should add this to the on condition for the related table eg:
SELECT
order.id
count(same_products.id),
count(all_products.id)
FROM orders
LEFT JOIN products AS all_products ON all_products.order_id = orders.id and all_products.id =4
LEFT JOIN products AS same_products
ON same_products.order_id = orders.id AND same_products.id IN (30868, 30862)
GROUP BY orders.id
HAVING count(same_products.id) >1

I am not clear what you really mean by duplicate, I assume from your description that it's 2 orders with the same products. This seems a little simplistic for example given
MariaDB [sandbox]> select * from orders;
+------+---------------------+-------------+
| id | order_created | customer_id |
+------+---------------------+-------------+
| 1 | 2016-01-01 00:00:00 | 1 |
| 2 | 2016-02-01 00:00:00 | 1 |
| 3 | 2016-03-01 00:00:00 | 1 |
| 4 | 2016-01-01 00:00:00 | 2 |
| 5 | 2016-02-01 00:00:00 | 2 |
| 6 | 2016-01-01 00:00:00 | 3 |
| 10 | 2016-12-01 00:00:00 | 4 |
+------+---------------------+-------------+
7 rows in set (0.00 sec)
MariaDB [sandbox]> select * from order_details;
+----+---------+-----------+------+
| id | orderid | productid | qty |
+----+---------+-----------+------+
| 1 | 1 | 1213 | 10 |
| 2 | 1 | 9999 | 10 |
| 3 | 2 | 8888 | 10 |
| 4 | 3 | 1213 | 10 |
| 5 | 4 | 2222 | 10 |
| 6 | 5 | 9999 | 30 |
| 7 | 5 | 1213 | 30 |
| 8 | 6 | 9999 | 30 |
| 9 | 6 | 1213 | 30 |
+----+---------+-----------+------+
9 rows in set (0.00 sec)
select orders1.*,orders2.*,t.*
from
(select * from
(
select orderid o1orderid,group_concat(productid order by productid) o1grp,sum(qty) qty1
from order_details
group by orderid
) o1
join
(select orderid o2orderid,group_concat(productid order by productid) o2grp, sum(qty) qty2
from order_details
group by orderid
) o2
on o2grp = o1grp and qty2 = qty1 and o2orderid > o1orderid
) t
join orders orders1 on t.o1orderid = orders1.id
join orders orders2 on t.o2orderid = orders2.id
returns
+------+---------------------+-------------+------+---------------------+-------------+-----------+-----------+-------+-----------+-----------+-------+
| id | order_created | customer_id | id | order_created | customer_id | o1orderid | o1grp | qty1 | o2orderid | o2grp | qty2 |
+------+---------------------+-------------+------+---------------------+-------------+-----------+-----------+-------+-----------+-----------+-------+
| 5 | 2016-02-01 00:00:00 | 2 | 6 | 2016-01-01 00:00:00 | 3 | 5 | 1213,9999 | 30,30 | 6 | 1213,9999 | 30,30 |
+------+---------------------+-------------+------+---------------------+-------------+-----------+-----------+-------+-----------+-----------+-------+
1 row in set (0.03 sec)
But customer number is different.

Related

SQL Query: join with condition

I have the following tables:
Customer
| c_id | name |
| -------- | -------------- |
| 1 | Adam |
| 2 | Bradley |
| 3 | Chandler |
| 4 | Damian |
| 5 | Eric |
| 6 | Frank |
orders
| order_id | c_id | amount
| -------- | -------------- | -------------- |
| 1 | 1 | 50
| 2 | 1 | 2
| 3 | 2 | 15
| 4 | 2 | 22
| 5 | 2 | 10
| 6 | 2 | 7
| 7 | 3 | 7
| 8 | 3 | 2
| 9 | 5 | 18
| 10 | 5 | 24
| 11 | 6 | 60
| 12 | 6 | 1
I want to create a list of users who have order amounts over 50.
This list should include c_id, name and the sum of all their orders including those under 50.
so it should look like this:
| c_id | name | amount
| -------- | -------------- | -------------- |
| 1 |Adam | 52
| 6 | Frank | 61
You can use group by and having:
select c.c_id, c.name, sum(o.amount)
from orders o join
customers c
on o.c_id = c.c_id
group by c.c_id, c.name
having max(o.amount) > 50;
SELECT
c_id
, name
, SUM(amount) AS total_amount
FROM
orders a
INNER JOIN customer b
ON b.c_id = a.user_id
WHERE
c_id IN (
SELECT
user_id
FROM
orders
WHERE
amount >= 50)
GROUP BY c_id, name
Best to break this down into chunks:
Customers who have a total amount over 50:
SELECT user_id FROM orders GROUP BY user_id HAVING sum(amount) >= 50;
Sum of the amounts for each order for customers that meet the criteria above:
SELECT user_id, sum(amount) as order_total
FROM orders
WHERE user_id IN (SELECT user_id FROM orders HAVING sum(amount) >= 50 GROUP BY user_id)
GROUP BY user_id;
You can just join over to your customer table to grab the name. Didn't include since that is the more straightforward ask here.

Update several records with the sum of several records from another table - mysql

I have the following table:
product
+-------------+------------+
| id_product | quantity |
+-------------+------------+
| 15 | 0 |
| 16 | 1 |
| 17 | 3 |
| 18 | 1 |
+-------------+------------+
And the other table is a subquery
+------------+-----------+
| id_product | total |
+------------+-----------+
| 15 | 1 |
| 17 | 1 |
| 18 | 4 |
+------------+-----------+
And I want to do is in a single update query, update the table products with the records returned by the subquery, making a sum, I can get one or many records from the subquery.
+-------------+------------+
| id_product | quantity |
+-------------+------------+
| 15 | 1 |
| 16 | 1 |
| 17 | 4 |
| 18 | 5 |
+-------------+------------+
I tried to make this update query, but it does not do what I want.
UPDATE product p
INNER JOIN (
SELECT id_product, count(*) as total
FROM othertable
GROUP BY id_product
) c ON p.id_product = c.id_product
SET p.quantity = c.total;
______EDIT______
UPDATE product p
INNER JOIN (
SELECT id_product, count(*) as total
FROM othertable
GROUP BY id_product
) c ON p.id_product = c.id_product
SET p.quantity = p.quantity + c.total

mysql group by keeping the more recent date

I have the following table:
+------------+--------+-----+
| reg_dat | status | id |
+------------+--------+-----+
| 2016-01-31 | 10 | 1 |
| 2017-06-31 | 12 | 1 |
| 2015-01-31 | 12 | 4 |
| 2017-01-25 | 5 | 4 |
| 2017-01-11 | 3 | 2 |
+------------+--------+-----+
I would like to do a mysql query to group the rows by id and keeping only the more recent date... so the output should be the following:
+------------+--------+-----+
| reg_dat | status | id |
+------------+--------+-----+
| 2017-06-31 | 12 | 1 |
| 2017-01-25 | 5 | 4 |
| 2017-01-11 | 3 | 2 |
+------------+--------+-----+
Unfortunately my code doesn't work...
select *
from table
group by id
order by id, reg_dat DESC
Have you some suggestions?
You can do that using a JOIN and a subquery
SELECT t.reg_dat, t.status, t.id
FROM table t
JOIN (SELECT max(reg_dat) max_date, id FROM table GROUP BY id) t1
ON t.reg_dat = t1.max_date AND t.id = t1.id

sql Select Orders with multiple addresses

I'm trying to select orders, which are send at least two times with the same addressId to a customer.
This is my table structure:
Customer Table:
+------------+-----------+
| customerId | addressId |
+------------+-----------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
+------------+-----------+
Relation for Addresses to Orders
+---------+-----------+
| orderId | addressId |
+---------+-----------+
| 1 | 1 |
| 2 | 2 |
| 3 | 2 |
| 4 | 3 |
| 5 | 4 |
| 6 | 4 |
+---------+-----------+
Order Table
+----+------------+-------+
| id | orderEntry | total |
+----+------------+-------+
| 1 | timestamp | 4711 |
| 2 | timestamp | 0815 |
| 3 | timestamp | 1337 |
+----+------------+-------+
Now I want a output like this:
+------------+---------+-----------+
| customerId | orderId | addressId |
+------------+---------+-----------+
| 2 | 2 | 2 |
| 2 | 3 | 2 |
| 4 | 5 | 4 |
| 4 | 6 | 4 |
+------------+---------+-----------+
I've tried to get the right result with these Query, but I think I can't count the addresses this way.
SELECT C.`customerId`, AO.`orderId`, AO`addressId`
FROM customer AS C
JOIN address_order AS AO ON AO.addressId = C.addressId
JOIN order AS O ON O.id = AO.orderId
GROUP BY AO.`orderId`
HAVING (COUNT(AO.`addressId`) > 1);
With these Query I only get a result like this:
+------------+---------+-----------+
| customerId | orderId | addressId |
+------------+---------+-----------+
| 2 | 2 | 2 |
| 4 | 5 | 4 |
+------------+---------+-----------+
I don't see the usage of order table here. However you can use the order table into the consideration if you want to make sure that the order table data and address_order should have data. You can write the query as
select
c.customerId,
ao.orderId,
ao.addressId
from customer c
join address_order ao on ao.addressId = c.addressId
join (
select addressId, count(*) as tot from address_order
group by addressId having tot = 2
)x on x.addressId = ao.addressId
If you want to make sure all the orderId from customer_order are in the order table then you can add another join at the end as
join `order` o on o.id = ao.orderId
Try this
SELECT customerId FROM customer INNER JOIN (SELECT * FROM address_order GROUP BY addressId
HAVING (COUNT(addressId) > 1)) AS t1 ON customer.addressId=t1.addressId

Return distinct and null records from a mysql join query

Is there any way to return distinct values with blank/null data from a table join. Best to explain with my example below.
Table "orders"
order_id | order_total
1 | 10
2 | 20
3 | 50
Table "order_items"
item_id | order_id | name | qty_ordered | base_price | row_total
1 | 1 | Product | 1 | 10 | 10
2 | 2 | Product | 1 | 10 | 10
3 | 2 | Product2 | 1 | 10 | 10
4 | 3 | Product | 2 | 10 | 20
5 | 3 | Product2 | 3 | 10 | 30
I'm trying to produce a result set that looks like this.
order_id | item_id | name | qty_ordered | base_price | row_total | order_total
1 | 1 | Product | 1 | 10 | 10 | 10
2 | 2 | Product | 1 | 10 | 10 | 20
null | 3 | Product2 | 1 | 10 | 10 | null
3 | 4 | Product | 2 | 10 | 20 | 50
null | 5 | Product2 | 3 | 10 | 30 | null
I only want the order_id and order_total once per order. I figure this is possible with some sort of join/distinct/sub query but alas nothing I've tried has worked so far.
Use:
SELECT x.order_id,
x.item_id,
x.name,
x.qty_ordered,
x.base_price,
x.row_total,
x.order_total
FROM (SELECT CASE
WHEN #order = o.order_id THEN NULL
ELSE o.order_id
END AS order_id,
oi.item_id,
oi.name,
oi.qty_ordered,
oi.base_price,
oi.row_total,
o.order_total,
CASE
WHEN #order = o.order_id THEN NULL
ELSE o.order_total
END AS order_total,
#order := o.order_id
FROM ORDER_ITEMS oi
JOIN ORDERS o ON o.order_id = oi.order_id
JOIN (SELECT #order := -1) r
ORDER BY o.order_id, oi.item_id) x
SELECT * FROM order_items
LEFT JOIN orders
ON (
order_items.order_id=orders.order_id
AND
order_items.item_id=(
SELECT MIN(item_id)
FROM order_items a
WHERE a.order_id=order_items.order_id
)
)
This should work because the nested query always returns the same MIN(item_id) for each order, and it only joins for that item.
But this is a very, very ugly piece of sql. Don't do this.