Is there any way to get the inverse of a group by statement in mysql? My use case is to delete all duplicates.
Say my table looks like this:
ID | columnA | ...
1 | A
2 | A
3 | A
4 | B
5 | B
6 | C
I want my result set to look like this:
ID | columnA | ...
2 | A
3 | A
5 | B
(Essentially this finds all duplicates leaving one behind. Could be used to purge all duplicate records down to 1, or to perform other analysis later).
One way is to take all but the first id for each value of ColumnA:
select t.*
from t
where t.id > (select min(t2.id) from t t2 where t2.columnA = t.columnA);
Your result seems
select max(id), columnA group by columnA
This should perform a lot better then inner select based queries.
SELECT
*
FROM
TABLE
QUALIFY
RANK() OVER (partition by columnA order by ID ASC ) = 1
EDIT : This apparently wont work in MySQL. Guess the only answer is to by a oracle license - or use another answer. ;)
I realized my own solution based on #scaisEdge response before he edited it. In need the opposite of my group by, so using a subquery:
SELECT * FROM mytable WHERE ID NOT IN (SELECT ID FROM mytable GROUP BY columnA);
I am confident this will help.
create table test.temptable select distinct * from YourTable;
truncate YourTable;
insert into YourTable select * from test.temptable ;
Related
I need to select some data but im unable to do it in the way I need it and I cant find the issue with the query
The data is like:
user | priority | group
user-a | 5 | other
user-b | 5 | none-a
user-b | 2 | some-grp
user-c | 5 | other-a
user-d | 5 | other-b
basically a user can have many groups with a priority, and i whant to filter users which do NOT have a specific group
the query im using is:
SELECT *
FROM tableName
WHERE group LIKE "other%" OR group LIKE "none%"
AND group NOT LIKE "some%"
LIMIT 0 , 30
but this query will return all results not users a/c/d (its like ignores the AND NOT LIKE
may be you want this:
SQL Fiddle
MySQL 5.5.30 Schema Setup:
create table t (`user` varchar(20), priority int, `group` varchar(20))
;
insert t (`user`, priority, `group`)
values ('user-a', 5, 'other'),
('user-b', 5, 'none-a'),
('user-b', 2, 'some-grp'),
('user-c', 5, 'other-a'),
('user-d', 5, 'other-b')
Query 1:
SELECT `user`
FROM t
WHERE `user` in
(select `user` from t
where `group` LIKE "other%" OR `group` LIKE "none%")
and `user` not in
(select `user` from t
where `group` LIKE "some%")
Results:
| USER |
----------
| user-a |
| user-c |
| user-d |
If you want not to show users included in specific groups, you can use the NOT IN with a non-correlated subquery or the NOT EXISTS with a correlated subquery strategies.
NOT IN with a non-correlated subquery
SELECT `user`
FROM t
WHERE (`group` LIKE "other%" OR `group` LIKE "none%")
AND `user` NOT IN (SELECT `user` FROM t WHERE `group` LIKE "some%");
NOT EXISTS with a correlated subquery
SELECT t.`user`
FROM t
WHERE (t.`group` LIKE "other%" OR t.`group` LIKE "none%")
AND NOT EXISTS
(
SELECT 1 FROM t sub_t
WHERE sub_t.`user` = t.`user`
AND sub_t.`group` LIKE "some%" );
Use a left join but keep only rows that dont join:
SELECT DISTINCT t1.*
FROM tableName t1
LEFT JOIN tableName t2
ON t1.user_id = t2.user_id
AND t2.group NOT LIKE "some%"
WHERE (t1.group LIKE "other%"
OR t1.group LIKE "none%")
AND t2.user_id IS NULL -- only non-joins
LIMIT 0, 30
There was also a bug in your WHERE clause with in bracketed OK conditions (fixed here) which would have led to incorrect logic due to operator precedence.
Also had to guess what there's user id column was - you may have to adjust for that.
I think this is a "set-within-sets" query. I like to approach these using aggregation and having, because that is a very flexible approach.
select user
from t
group by user
having sum(group LIKE 'other%') > 0 or
(sum(group LIKE 'none%' > 0 and
sum(group like 'some%') = 0
)
This basically translates your where clause -- which operates on one record -- in a having clause that counts the occurrences of each pattern in the group.
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).
I have a table student like this
id | name | zip
1 | abc | 1234
2 | xyz | 4321
3 | asd | 1234
I want to get all records but zip code should not be repeated. So In case of above table records, record No 1 and 2 should be fetched. Record No. 3 will not be fetched because it has a zip code which is already in record No. 1
SELECT DISTINCT fieldName FROM tableName;
The following query will only select distinct 'zip' field.
SELECT DISTINCT zip FROM student;
SELECT * FROM tableName GROUP BY fieldName;
The following query will select all fields along with distinct zip field.
SELECT * FROM student GROUP BY zip;
TRY
SELECT DISTINCT(zip),id,name FROM student;
OR
SELECT * FROM student GROUP BY zip;
Altough in MySQL you can get away with:
SELECT *
FROM student
GROUP BY zip
I would choose:
SELECT *
FROM student t
JOIN
( SELECT MIN(id) AS minid
FROM student
GROUP BY zip
) AS grp
ON grp.minid = t.id
Since presumably the other columns are of some interest....
SELECT y.*
FROM yourTable y,
(SELECT MIN(y2.id)
FROM yourTable y2
GROUP BY y2.zip) ilv
WHERE ilv.id=y.id;
(or you could use the max-concat trick)
update
Oracle have now removed the max concat trick from the linked page - but it is described elsewhere on the internet
Try Using
Select Distinct(zip),id,name group by zip;
Is there any problem if I use as this below?
select distinct zip,name,id from student;
select id, name, distinct(zip) from student;
This is my example of my table:
id | name | foreign_id |
-------------------------
1 a 100
2 b 100
3 c 100
4 d 101
5 a 102
6 b 102
7 c 102
I would like to get the distinct file with the latest foreign_id (bigger number but not necessarily biggest).
In this example, it would be row with id 4,5,6,7. Anyone has any idea? Thank you very much!
Could you try something like below :-
SELECT Id,Table1.Name,Table1.Fid FROM Table1 INNER JOIN
(SELECT Name,Max(FId) AS FId FROM Table1 Group By Name)
Table2 ON Table1.FId=Table2.FId AND Table1.Name=table2.Name
This works in Sql Server atleast. Please check in MySQL. Sorry, I dont have MySQL to test this.
Sounds like you just want this:
SELECT name, MAX(foreign_id)
FROM table
GROUP BY name;
If you need the ID (I'm guessing you won't, since name and foreign_id should probably be unique, making the ID column unnecessary), I think MySQL will allow you to get that by just adding that column to the SELECT list - although this is non-standard SQL. If you want standard SQL, then you want something like Ashish wrote.
SELECT
*
FROM
table_name
WHERE
foreign_id > 100
You could do something like:
select *
from table_name
where max_id_you_want = (select max(id_you_want) from table_name)
SELECT * FROM table
GROUP BY name
having MAX(foreign_id);
I have database result like this
ID | NAME | TYPE
--------------------
1 | baseball | 1
2 | kickball | 1
3 | football | 1
4 | soccer | 2
How do I do a select * so get all results but also get a total count of type = 2 in the results?
Any help appreciated.
This will give you the type count for the current row's type in each row:
select t1.*, t2.TypeCount
from Table1 t1
inner join (
select TYPE, count(*) as TypeCount
from Table1
group by TYPE
) t2 on t1.TYPE = t2.TYPE
Typically we manage to get this by the way of two distinct results set. However it is possible to get them all in one with a query similar to the following
SELECT ID, Name, Type
FROM MyTable
UNION
SELECT -1, Type, COUNT(*)
FROM MyTable
WHERE Type = 2
GROUP BY Type
ORDER BY ID
The assumption is that all normal IDs are > 0 allowing to the the -1 as a marker for the row with the count. This row will be first in the resultset, thanks to the ORDER BY.
Note that we could complicate things a bit and get a count for all types (or for several), by simply removing (or changing) the WHERE clause in the second query.