id class count day
1 2 5 5
2 2 4 5
3 2 4 5
3 2 4 5
4 2 5 3
4 1 5 3
4 2 5 3
So I have a query for finding all duplicates based on multiple columns, however, this also returns id's where not all entries are duplicate.
In above example, the query should only show/count id 3, as all the entries with id 3 are duplicate. Even though id 4 also has a duplicate, it should not show as it has another entry that is unique.
Any idea how to do this?
If you need rows with id where there is no row with the same id and unique row values then use NOT IN and HAVING
select *
from your_table t1
where t1.id not in(
select id
from your_table
group by id, class, count, day
having count(*) = 1
)
You can use this query : http://sqlfiddle.com/#!9/1a2536/8
select id
from test
group by id
having count(distinct id,class,count,day) = 1 and count(*)>1
you group each rows by id and count how many different row the group has, if the distinct total is 1 and the total row is > 1 , there is only duplicate rows for this id.
It's quite easy, a quick note it's a very bad idea to name a column count :
SELECT id, class, `count`,day, COUNT(*)
FROM myTable
GROUP BY id, class, `count`,day
HAVING COUNT(*) > 1
edit : I misread the question so here is my solution :
SELECT test.id, test.class, test.count, test.day , count(*), t.countID
FROM (SELECT id, Count(id) AS countID FROM test GROUP BY id ) t
INNER JOIN test on t.id = test.id
GROUP BY test.id, test.class, test.count, test.day
HAVING Count(*) > 1 AND t.countID = count(*)
I came up with this :
SELECT *
FROM (SELECT id,
Count(id) AS matched
FROM test
GROUP BY id,
class,
count,
day) t
GROUP BY id , matched
HAVING Count(id) = 1
AND matched >= 2
There is maybe a more efficient way to do it but it is easier to understand this way, first we group by every column to find duplicate data. Then the first part of the having eliminates the entries that actually have different variants by id and then we keep only the lines that actually only have duplicates.
Edit : compatible with "only_full_group_by" mode
Related
I am doing a selection using GROUP BY, so I get a lot of different rows. What I need is to UPDATE the status field of each row affected by the SELECT query, but it is grouped... so I don't know all the ids, just the MAX(id).
This is the select query:
SELECT d.*, n.* FROM
(SELECT MAX(id) as id, MAX(datetime) as datetime, COUNT(DISTINCT content) as total FROM user_notifications
WHERE id_user
GROUP BY id_ref, type
ORDER BY datetime DESC) d
JOIN user_notifications n USING (id)
Edit:
Simple example, this is the table
id user content status
1 1 aaa 0
2 1 aaa 0
3 1 bbb 0
4 2 aaa 0
5 3 bbb 0
this is the query
select max(id), user, content from table where user=1 group by content
this is the result
id user content
2 1 aaa
3 1 bbb
in this query in fact sql internally select all user=1 (id= 1, 2, 3) and then the query is grouped, showing just two rows.
So, I want to update all ids involved in the query (id= 1 , 2 and 3)
Based on your example, you need the result exact to this query:
select id from `table` where user = 1;
But by using the query you provided which groups record by content
select max(id), user, content from `table` where user = 1 group by content
So, in such case you can join same table with derived table:
select id from `table` as t
join (select max(id), user, content from `table` where user = 1 group by content) as dt
on dt.content = t.content and dt.user = t.user;
This query is now equivalent to first straight forward query.
I am super new to access and having difficulty with a query. My table (tblpacks) is the following:
id user_id group_id quota_id
1 1 1 1
2 1 2 1
3 2 1 1
4 3 1 1
Ideally, what I now is to get hte number of unique users and groups for quota_id=1
The result will be:
total_users = 3
total_groups = 2
If you only wanted to count one field, there would by a simple solution, but since you want to count 2 separate fields, you in fact need at least 2 separate queries.
My answer is to use a UNION query as the source for counting. This UNION query returns the distinct user_id values (with Null as group_id) and the distinct group_id values (with Null as user_id). I omitted the DISTINCT keyword, because UNION (without ALL) does a DISTINCT query automatically. As the datatypes where not recognized correctly when using a constant Null field in the first SELECT statement of the UNION query, I added a third SELECT statement as the first one, which selects both fields from the table but returns no records:
SELECT Count(user_id) AS total_users, Count(group_id) AS total_groups
FROM (
SELECT user_id, group_id FROM tblpacks WHERE Yes=No
UNION
SELECT user_id, Null FROM tblpacks WHERE quota_id=1
UNION
SELECT Null, group_id FROM tblpacks WHERE quota_id=1
) AS qsub;
I would like to select multiple values from a single column in a database table that equal to a number of values. I want all these values to match otherwise it should return no rows. I do not want to use "IN" as that is equal to "OR".
The following is a basic mockup of what it should do but it needs to be dynamic as I wish to use it with a PDO statement. If the database only contains id's 1 and 2 it should fail ie return no rows.
SELECT
id
FROM
reports
WHERE
id=1 AND id=2 AND id=3
I have the current code as follow which is incorrectly returning zero rows:
SELECT id,title
FROM reports
WHERE id IN (1,2)
GROUP BY title
HAVING COUNT(DISTINCT id) = 2
My current table structure is as follows:
http://www.sqlfiddle.com/#!2/ce4aa/1
You have to use HAVING COUNT(id) = 3 to ensure that the selected rows have all the three id's. Something like:
SELECT *
FROM reports
WHERE id = 1 OR id = 2 OR id = 3 -- Or id IN(1, 2, 3)
GROUP BY SomeOtherField
HAVING COUNT(DISTINCT id) = 3;
Or:
SELECT *
FROM reports
WHERE SomeOtherField IN (SELECT SomeOtherField
FROM reports
WHERE id = 1 or id = 2 -- Or id IN(1, 2, 3)
GROUP BY SomeOtherField
HAVING COUNT(DISTINCT id) = 3
);
Note that: You have to GROUP BY SomeOtherField where SomeOtherField is other field than id because if you GROUP BY id with HAVING COUNT(id) you won't get any records, since COUNT(id) will be always = 1.
Edit: fixed WHERE clause, OR's instead of AND's.
SQL Fiddle Demo
I have table with, folowing structure.
tbl
id name
1 AAA
2 BBB
3 BBB
4 BBB
5 AAA
6 CCC
select count(name) c from tbl
group by name having c >1
The query returning this result:
AAA(2) duplicate
BBB(3) duplicate
CCC(1) not duplicate
The names who are duplicates as AAA and BBB. The final result, who I want is count of this duplicate records.
Result should be like this:
Total duplicate products (2)
The approach is to have a nested query that has one line per duplicate, and an outer query returning just the count of the results of the inner query.
SELECT count(*) AS duplicate_count
FROM (
SELECT name FROM tbl
GROUP BY name HAVING COUNT(name) > 1
) AS t
Use IF statement to get your desired output:
SELECT name, COUNT(*) AS times, IF (COUNT(*)>1,"duplicated", "not duplicated") AS duplicated FROM <MY_TABLE> GROUP BY name
Output:
AAA 2 duplicated
BBB 3 duplicated
CCC 1 not duplicated
For List:
SELECT COUNT(`name`) AS adet, name
FROM `tbl` WHERE `status`=1 GROUP BY `name`
ORDER BY `adet` DESC
For Total Count:
SELECT COUNT(*) AS Total
FROM (SELECT COUNT(name) AS cou FROM tbl GROUP BY name HAVING cou>1 ) AS virtual_tbl
// Total: 5
why not just wrap this in a sub-query:
SELECT Count(*) TotalDups
FROM
(
select Name, Count(*)
from yourTable
group by name
having Count(*) > 1
) x
See SQL Fiddle with Demo
The accepted answer counts the number of rows that have duplicates, not the amount of duplicates. If you want to count the actual number of duplicates, use this:
SELECT COALESCE(SUM(rows) - count(1), 0) as dupes FROM(
SELECT COUNT(1) as rows
FROM `yourtable`
GROUP BY `name`
HAVING rows > 1
) x
What this does is total the duplicates in the group by, but then subtracts the amount of records that have duplicates. The reason is the group by total is not all duplicates, one record of each of those groupings is the unique row.
Fiddle: http://sqlfiddle.com/#!2/29639a/3
SQL code is:
SELECT VERSION_ID, PROJECT_ID, VERSION_NO, COUNT(VERSION_NO) AS dup_cnt
FROM MOVEMENTS
GROUP BY VERSION_NO
HAVING (dup_cnt > 1 && PROJECT_ID = 11660)
I'm using this query for my own table in PHP, but it only gives me one result whereas I'd like to the amount of duplicate per username, is that possible?
SELECT count(*) AS duplicate_count
FROM (
SELECT username FROM login_history
GROUP BY username HAVING COUNT(time) > 1
) AS t;
I have a MySQL table like this
id Name count
1 ABC 1
2 CDF 3
3 FGH 4
using simply select query I get the values as
1 ABC 1
2 CDF 3
3 FGH 4
How I can get the result like this
1 ABC 1
2 CDF 3
3 FGH 4
4 NULL 0
You can see Last row. When Records are finished an extra row in this format
last_id+1, Null ,0 should be added. You can see above. Even I have no such row in my original table. There may be N rows not fixed 3,4
The answer is very simple
select (select max(id) from mytable)+1 as id, NULL as Name, 0 as count union all select id,Name,count from mytable;
This looks a little messy but it should work.
SELECT a.id, b.name, coalesce(b.`count`) as `count`
FROM
(
SELECT 1 as ID
UNION
SELECT 2 as ID
UNION
SELECT 3 as ID
UNION
SELECT 4 as ID
) a LEFT JOIN table1 b
ON a.id = b.id
WHERE a.ID IN (1,2,3,4)
UPDATE 1
You could simply generate a table that have 1 column preferably with name (ID) that has records maybe up 10,000 or more. Then you could simply join it with your table that has the original record. For Example, assuming that you have a table named DummyRecord with 1 column and has 10,000 rows on it
SELECT a.id, b.name, coalesce(b.`count`) as `count`
FROM DummyRecord a LEFT JOIN table1 b
ON a.id = b.id
WHERE a.ID >= 1 AND
a.ID <= 4
that's it. Or if you want to have from 10 to 100, then you could use this condition
...
WHERE a.ID >= 10 AND
a.ID <= 100
To clarify this is how one can append an extra row to the result set
select * from table union select 123 as id,'abc' as name
results
id | name
------------
*** | ***
*** | ***
123 | abc
Simply use mysql ROLLUP.
SELECT * FROM your_table
GROUP BY Name WITH ROLLUP;
select
x.id,
t.name,
ifnull(t.count, 0) as count
from
(SELECT 1 AS id
-- Part of the query below, you will need to generate dynamically,
-- just as you would otherwise need to generate 'in (1,2,3,4)'
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
) x
LEFT JOIN YourTable t
ON t.id = x.id
If the id does not exist in the table you're selecting from, you'll need to LEFT JOIN against a list of every id you want returned - this way, it will return the null values for ones that don't exist and the true values for those that do.
I would suggest creating a numbers table that is a single-columned table filled with numbers:
CREATE TABLE `numbers` (
id int(11) unsigned NOT NULL
);
And then inserting a large amount of numbers, starting at 1 and going up to what you think the highest id you'll ever see plus a thousand or so. Maybe go from 1 to 1000000 to be on the safe side. Regardless, you just need to make sure it's more-than-high enough to cover any possible id you'll run into.
After that, your query can look like:
SELECT n.id, a.*
FROM
`numbers` n
LEFT JOIN table t
ON t.id = n.id
WHERE n.id IN (1,2,3,4);
This solution will allow for a dynamically growing list of ids without the need for a sub-query with a list of unions; though, the other solutions provided will equally work for a small known list too (and could also be dynamically generated).