MySQL records that matches multiple criterias - mysql

There is probably a simple answer to this but I can't seem to find it anywhere..
My table looks like this:
item_id tag_id
----------------------
100 55
101 55
100 320
102 320
100 77
100 489
101 200
Asking for items with tags 55 AND 320 should return item_id = 100 (but not 101 or 102 as they don't have both tags)

You could use HAVING clause:
SELECT item_id
FROM tab_name
WHERE tag_id IN (1,2)
GROUP BY item_id
HAVING COUNT(DISTINCT tag_id) = 2;
SqlFiddleDemo
or even:
SELECT item_id
FROM tab_name
GROUP BY item_id
HAVING GROUP_CONCAT(DISTINCT tag_id ORDER BY tag_id ) = '1,2';
SqlFiddleDemo2

You can try:
SELECT item_id
FROM table_name
WHERE tag_id IN (55,320)
GROUP BY item_id
HAVING COUNT(DISTINCT tag_id) > 1;
It will return item_id that have more than one distinct tag_id.
Pass your tags in IN by comma separated as many as you want.

SELECT item_id
FROM Table1
WHERE tag_id IN (55,320)
GROUP BY item_id
HAVING COUNT(DISTINCT tag_id) > 1
Fiddle example

Related

SQL query to only yield multiple occurances

I am using mariadb and I have a table called links:
id | product_id | last_change
------------------------------
1 1 xxx
2 2 xxx
3 5 xxx
4 5 xxx
I want to find every object (3, 4 in this example) that occures more than once. Following this answer I tried:
SELECT product_id, COUNT(*) from links HAVING COUNT(*) > 1
But this results in the (adapted to this example) first row being shown and the total number of product_id occurrences:
product_id | COUNT(*)
---------------------
1 4
I wanted to achieve a list of all items occuring more than once:
id | product_id | last_change
------------------------------
3 5 xxx
4 5 xxx
An aggregation function without GROUP BY always results in only one row result as it aggregates all rows
So use a GROUP BY
SELECT product_id, COUNT(*) from links GROUP BY product_id HAVING COUNT(*) > 1
To see all entry with the count of the product_id , you can do following
SELECT l1.product_id , last_change , Count_
FROM links l1
JOIN (SELECT product_id, COUNT(*) as Count_ from links GROUP BY product_id HAVING COUNT(*) > 1) l2
ON l1.product_id = l2.product_id
Try below statement
select id, product_id, count(product_id)
from links
group by (product_id)
having count(product_id)> 1;

Get records group by multiple column mysql

Here is my table structure
comment_file_id comment_id attachement_id source created_by
33 203 42 IN 101
35 203 46 OUT 101
36 203 42 OUT 101
37 203 42 OUT 101
i want to get only 3 records only as records associated with attachment_id 42 are duplicates for source OUT , so oi have to exclude those ones.
select *
from comments
where comment_id = 203
GROUP
BY source
, created_by
, attachement_id ;
but getting errors
use min()
select min(comment_file_id) as comment_file_id,comment_id,attachement_id,source
,created_by from table
group by comment_id,attachement_id,source
,created_by
If you are using MySQL 8+, then ROW_NUMBER is helpful here. We can phrase your query as a union of all records not subject to duplicate constraints, along with the single record not deemed a duplicate:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY comment_file_id) rn
FROM comments
WHERE comment_id = 203 AND attachement_id = 42 AND source = 'OUT'
)
SELECT comment_file_id, comment_id, attachement_id, source, created_by
FROM comments
WHERE comment_id = 203 AND (attachement_id <> 42 OR source <> 'OUT')
UNION ALL
SELECT comment_file_id, comment_id, attachement_id, source, created_by
FROM cte
WHERE rn = 1;

MySQL - remove non-duplicate rows from query

I'm running a query that selects details of orders, and I want to see only the orders that have gone through multiple stages. My data looks like:
id | order_id | action
1 100 1
2 100 2
3 100 4
4 101 1
5 102 2
6 103 1
7 103 2
So that only the rows for order_id 100 and 103 will be selected. This needs to be nested in a larger query.
You can use a subquery to get the orders that had multiple stages:
SELECT order_id
FROM your_table
GROUP BY order_id
HAVING COUNT(*)>1
then you can join this result back to your table:
SELECT o.*
FROM yourtable AS o INNER JOIN (
SELECT order_id
FROM your_table
GROUP BY order_id
HAVING COUNT(*)>1
) dup ON o.order_id = dup.order_id
Use group by with count and having
select *,count(order_id) as total from table
group by order_id
having total > 1
you can try this query:
select * from your_table
where ( select count(*) from your_table internal_table
where your_table .order_id = internal_table.order_id
) > 1

SQL Query exclusion for "set-within-sets"

I have a table item_category with two columns: item_id, cat_id. Item to category is a many-to-many relationship.
If my table looks like this...
item_id | cat_id
1 | 1
1 | 2
2 | 3
2 | 4
3 | 5
3 | 6
4 | 7
4 | 8
5 | 9
5 | 10
... how can I select a distinct list of item_ids that do not have any rows where category_id is 2 or 7 (yielding item_ids of 2, 3, 5)?
I would do this using aggregation and a having clause:
select item_id
from item_category ic
group by item_id
having max(cat_id = 2) = 0 and
max(cat_id = 7) = 0
This is an example of a "set-within-sets" query. Using group by with having is the most generalizable form for such a query. For instance, if you wanted to be sure that category 3 were included, you would change the having clause to:
having max(cat_id = 2) = 0 and
max(cat_id = 7) = 0 and
max(cat_id = 3) = 1
Try something like this :
SELECT DISTINCT item_id
FROM table_category
WHERE item_id NOT IN
( select distinct item_id
from item_category
where cat_id in (2,7)
)
I'd use a nested SELECT, though there are probably ways to do this with a self join.
select item_id
from item_category t
where not exists (
select 1
from item_category
where item_id = t.item_id
and cat_id in (2,7)
)
group by item_id;
Example
You could also use a NOT IN clause instead:
SELECT DISTINCT item_id
FROM item_category
WHERE item_id NOT IN (
select distinct item_id
from item_category
where cat_id in (2,7));
Example
Both queries are probably similar in performance, but you can test if your data set is large.
Something like:
SELECT DISTINCT item_category.item_id
FROM item_category
INNER JOIN (
SELECT item_id ,SUM(CASE cat_id WHEN 2 THEN 1 WHEN 7 THEN 1 ELSE 0 END) AS catcount
FROM item_category
GROUP BY item_id
) AS exclude
ON item_category .item_id = exclude.item_id
WHERE exclude.catcount=0
Updated the answer I think this is what you meant.
One way would be
SELECT DISTINCT ITEM_ID
FROM ITEM_CATEGORY
WHERE ITEM_ID NOT IN (SELECT DISTINCT ITEM_ID
FROM ITEM_CATEGORY
WHERE CATEGORY_ID IN (2, 7))
which produces your desired results. If you want to have a bit more fun, you could do
SELECT DISTINCT ic1.ITEM_ID
FROM ITEM_CATEGORY ic1
LEFT OUTER JOIN (SELECT DISTINCT ITEM_ID
FROM ITEM_CATEGORY
WHERE CATEGORY_ID IN (2, 7)) ic2
ON ic2.ITEM_ID = ic1.ITEM_ID
WHERE ic2.ITEM_ID IS NULL
which also gets the results you're looking for and, if you're not familiar with how a LEFT OUTER JOIN works, might make for an interesting time puzzling through how and why it works.
SqlFiddle here.
Share and enjoy.
It can be done with a simple sub query:
SELECT DISTINCT item_id
FROM ic
WHERE item_id NOT IN (
SELECT DISTINCT item_id FROM ic WHERE cat_id IN (2,7)
);

Query to only retrieve records that are not duplicated

This is my table structure for product
product_id product_name
---------------------------------
100 Mouse
101 Keyboard
101 Pendrive
102 Motherboard
102 Card Reader
103 Adapter
I want the query which will give me following output by eliminating the duplicate record
OUTPUT
------------------
100
103
I have tried this query
SELECT count(product_id)
FROM product
GROUP BY product_id
Try this:
SELECT product_id
FROM product
GROUP BY product_id
HAVING COUNT(product_id) = 1;
You can try this SQL
SELECT t1.product_id FROM (SELECT product_id, COUNT(*) AS cnt FROM table GROUP BY product_id) t1 WHERE t1.cnt = 1