Finding duplicate rows in a MySQL table - mysql

I have a table in which I link items to types where each type can have multiple categories. For each combination of type and category, only one item should be linked. However, through some past error of mine, some duplicates have slipped through. I am now trying to write a query that will give me the duplicates but I am not doing a great job or I wouldn't be posting here obviously.
SELECT
item_id,
type_id,
category
FROM itemTypes
WHERE category = 'cat1'
GROUP BY type_id
HAVING COUNT(*) >= 2;
This is what I tried. It does work and gives me the type_ids that are linked to different items. But each type_id should be linked to only one item. This list doesn't show me the items that are linked. And that is just the thing I would like to know.
Can someone help me out?
Update
Below is a data sample. As you can see type_id 5 and 6 are linked multiple times. What I would like to get as a result is only these records.
| id | item_id | type_id | cat |
+-------+-----------+-----------+-----------+
| 1 | 100 | 5 | cat1 |
| 2 | 110 | 5 | cat1 |
| 3 | 115 | 6 | cat1 |
| 4 | 120 | 7 | cat1 |
| 5 | 125 | 5 | cat1 |
| 6 | 130 | 6 | cat1 |
| 7 | 135 | 4 | cat1 |
| 8 | 140 | 8 | cat1 |

You need to join your itemTypes table to the query you currently have, rephrased as a subquery:
SELECT t1.*
FROM itemTypes t1
INNER JOIN
(
SELECT item_id
FROM itemTypes
WHERE category = 'cat1'
GROUP BY item_id
HAVING COUNT(*) > 1
) t2
ON t1.item_id = t2.item_id;
The logical problem with your current query is that it can only find item_id values which meet your criteria, but not the other column values.

Related

SQL group by on mutiple columns - MySQL

+----+----------+-------------+-----------+---------------------+---------+---------------------------+
| id | action | object_type | object_id | created_at | user_id | object_title |
+----+----------+-------------+-----------+---------------------+---------+---------------------------+
| 1 | shared | 0 | 1 | 2016-04-22 06:13:16 | 1 | 5 highest buildings |
| 2 | liked | 0 | 1 | 2016-04-22 06:15:02 | 1 | 5 highest buildings |
| 3 | liked | 0 | 1 | 2016-05-21 19:02:18 | 2 | 5 highest buildings |
| 4 | liked | 1 | 3 | 2016-05-21 19:02:21 | 3 | 5 largest bridges |
+----+----------+-------------+-----------+---------------------+---------+---------------------------+
I'm trying to build some thing similar to Facebook's news feed. I mean when multiple users in my friend list like same post, we will show only single result in th news feed saying that friend1, friend2, frnd3, etc., like this xyz post.
From this table I would like to group by on these three columns (action, object_type, object_id) and a list of users for this object.
SELECT *
FROM mytable
GROUP BY action, object_type, object_id
But this gave me some weird results, and I was expecting a list of users. I' really don't have any clue how to do that in this query.
Any help or lead will be appreciated.
Try this query
SELECT action, object_title,count(user_id) as user_count, group_concat(user_id) as user_ids
FROM mytable GROUP BY action, object_type, object_id;

Group by two values

I have the following query:
SELECT
items.*
FROM
`items`
INNER JOIN
`users` ON `items`.`owner` = `users`.`id`
GROUP BY
`items`.`owner`
LIMIT
10
I ensures it is grouped by the user (only one item fetched per user), but I also wish ensure that items with the category, say, "1" only appears once.
But that does not work. Well, query succeeds, but it does not group by category. Multiple categories is still shown. Any ideas?
I have created a SQLFiddle here: http://sqlfiddle.com/#!2/0a4bad/1
Instead of outputting:
+----+----------+-------+
| ID | CATEGORY | OWNER |
+----+----------+-------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 2 | 4 |
| 5 | 2 | 5 |
+----+----------+-------+
It should be outputting:
+----+----------+-------+
| ID | CATEGORY | OWNER |
+----+----------+-------+
| 1 | 1 | 1 |
| 4 | 2 | 2 |
| 5 | 2 | 4 |
| 5 | 2 | 5 |
| 8 | 3 | 3 |
+----+----------+-------+
(notice category 1 is only shown ONCE).
I want to ensure that only one item per owner is shown, and then adtionally ensure that a specific category (say 1 and 5) is only shown once. The category 1 and 5 are overpopulated, and if they are not limited, they will be 90% of the output.
You can use DISTINCT to retrieve unique data:
SELECT DISTINCT items.category
select * from items t1
where category not in (1,2)
or not exists (
select 1 from items t2
where t2.id < t1.id
and t2.category = t1.category
)
group by owner
http://sqlfiddle.com/#!2/0a4bad/27

mysql return count = 0 without joins using group by

I have a table
Image
| ImageId | UserId | SourceId |
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 1 |
| 4 | 2 | 2 |
| 5 | 3 | 1 |
| 6 | 3 | 1 |
| 7 | 3 | 1 |
| 8 | 3 | 1 |
| 9 | 3 | 1 |
I then have a query:
SELECT UserId, IFNULL( COUNT( ImageId ) , 0 ) AS ImageCount, SourceId
FROM Image
GROUP BY UserId, SourceId
When I do the query, I get
| UserId | SourceId | ImageCount
| 1 | 1 | 1
| 1 | 2 | 1
| 2 | 1 | 1
| 1 | 2 | 1
| 3 | 1 | 5
However, the one row that I do NOT get back (which I want) is:
| 3 | 1 | 0
How do I go about fetching the row, even if the count is 0?
All of the questions I've seen have had to deal with joins (usually left joins) but as this doesn't require a join I'm a little confused as to how to go about this.
This does require a left join and a bit more. You need to start with all possible combinations, then use left join to bring in the existing values:
SELECT u.UserId, COUNT(i.ImageId ) AS ImageCount, s.SourceId
FROM (select distinct UserId from Image) u cross join
(select distinct SourceId from Image) s left join
Image i
on i.UserId = u.UserId and i.SourceId = s.SourceId
GROUP BY u.UserId, s.SourceId;
The count() will return 0 if there are no matches. There is no need for an if, coalesce, or case statement.
What this does is create every possible combination of UserId and SourceId (based on the values in the Image table). It then uses a left outer join to connect back to the image. What does this do? Well, for existing records, it actually does nothing. But for combinations that don't appear in the table, it will add a new row with u.UserId, s.SourceId, and NULL in the other fields. This is the basis for the final aggregation.

Mysql select row based on multiple rows in same table

I have the following table structure:
item_id | value |
==================
1 | 1 |
1 | 3 |
1 | 4 |
2 | 2 |
2 | 3 |
2 | 4 |
2 | 5 |
3 | 1 |
3 | 5 |
3 | 6 |
4 | 1 |
4 | 3 |
4 | 4 |
4 | 5 |
I have a query that returns those item_id whose value matches with 1, 3 and 4.
So here, the item_ids that should be returned are 1 and 4.
My query:
select item_id from table t
where exists (select item_id from table t1 where value = 1 and t1.item_id = t.item_id)
and exists (select item_id from table t1 where value = 2 and t1.item_id = t.item_id) group by item_id
This query is working fine. Here i am matching only 3 values. What if i want to match 50 such values from the table? (all the 50 values are stored in a php array) The query will be huge and also i want to do the same thing from two different tables in the same query. So, this will double the size of an already huge query. Please suggest me some other way around.
Edited::
table 2
--------
item_id | user_id |
==================
1 | 1 |
1 | 5 |
1 | 7 |
2 | 2 |
2 | 3 |
2 | 4 |
2 | 5 |
3 | 1 |
3 | 5 |
3 | 6 |
4 | 1 |
4 | 3 |
4 | 4 |
4 | 5 |
Now, i want item_id where values from table1 are 1,3,4 and user_id from table2 are 1,5,7
This problem is called Relational Division.
SELECT item_ID
FROM tableName
WHERE value IN (1,3,4)
GROUP BY item_ID
HAVING COUNT(*) = 3
if uniqueness was not enforce on column value for every item_id, DISTINCT is required to count only unique values,
SELECT item_ID
FROM tableName
WHERE value IN (1,3,4)
GROUP BY item_ID
HAVING COUNT(DISTINCT value) = 3
SQLFiddle Demo (both query included)
SQL of Relational Division

Join top 3 interest fields along with each user row

I'm trying to get the top 3 interests of each user, probably as a LEFT JOIN query.
The way the app is designed, each user has a set of interests which are no other than 'childs' (rows without parent) of the categories table.
Here are some simplified table schemas w/mock data (see SQL Fiddle demo)
-- Users table
| ID | NAME |
--------------
| 1 | John |
| 2 | Mary |
| 3 | Chris |
-- Categories table -- Interests table
| ID | NAME | PARENT | | ID | USER_ID | CATEGORY_ID |
-------------------------------------- ------------------------------
| 1 | Web Development | (null) | | 1 | 1 | 1 |
| 2 | Mobile Apps | (null) | | 2 | 1 | 1 |
| 3 | Software Development | (null) | | 3 | 1 | 1 |
| 4 | Marketing & Sales | (null) | | 4 | 2 | 1 |
| 5 | Web Apps | 1 | | 5 | 2 | 1 |
| 6 | CSS | 1 | | 6 | 3 | 1 |
| 7 | iOS | 2 | | 7 | 3 | 1 |
| 8 | Streaming Media | 3 | | 8 | 3 | 1 |
| 9 | SEO | 4 |
| 10 | SEM | 4 |
To get the top 3 interests of a given user, I've usually performed this query:
SELECT `c`.`parent` as `category_id`
FROM `interests` `i` LEFT JOIN `categories` `c` ON `c`.`id` = `i`.`category_id`
WHERE `i`.`user_id` = '2'
GROUP BY `c`.`parent`
ORDER BY count(`c`.`parent`) DESC LIMIT 3
This query returns the top 3 categories (parents) of user with id = 2
I would like to find out how I can query the users table and get their top 3 categories either in 3 different fields (preferred) or as a group_concat(..) in one field
SELECT id, name, top_categories FROM users, (...) WHERE id IN ('1', '2', '3');
Any ideas how I should go about doing this?
Thanks!
First build a groped query that lists on distinct rows, the top three skills for each user. Then pivot that into to pull the three skills for eah user out to the right. You will need to use the Max(isnull(skill,'')) expression on the skills in each skill column.
It is very crude way of doing it in MYSQL to get top 3 records for each user
SELECT u.id, c.name
FROM
users u,
categories c,
(SELECT i.id,
i.user_id,
i.category_id,
#running:=if(#previous=i.user_id,#running,0) + 1 as rId,
#previous:=i.user_id
FROM
(SELECT * FROM intersect ORDER BY user_id) i JOIN
(SELECT #running=0, #previous=0 ) r) i
WHERE
u.id = i.USER_ID AND
i.CATEGORY_ID = c.id AND
i.rId <= 3
group by u.id, c.name ;
Hope it helps
FIDDLE