Getting rows with duplicate column values - sql

I tried this with solutions avaialble online, but none worked for me.
Table :
Id rank
1 100
1 100
2 75
2 45
3 50
3 50
I want Ids 1 and 3 returned, beacuse they have duplicates.
I tried something like
select * from A where rank in (
select rank from A group by rank having count(rank) > 1
This also returned ids without any duplicates. Please help.

Try this:
select id from table
group by id, rank
having count(*) > 1

select id, rank
from
(
select id, rank, count(*) cnt
from rank_tab
group by id, rank
having count(*) > 1
) t

This general idea should work:
SELECT id
FROM your_table
GROUP BY id
HAVING COUNT(*) > 1 AND COUNT(DISTINCT rank) = 1
In plain English: get every id that exists in multiple rows, but all these rows have the same value in rank.
If you want ids that have some duplicated ranks (but not necessarily all), something like this should work:
SELECT id
FROM your_table
GROUP BY id
HAVING COUNT(*) > COUNT(DISTINCT rank)

Related

Exclude records where count > 5 and select top 1 of it

I want to exclude records where id > 5 then select the top 1 of it order by date. How can I achieve this? Each record has audit_line which is unique field for each record. Recent SQL script is on below:
SELECT *
FROM db.table
HAVING COUNT(id) > 5
If you want id > 5 then you want where:
select top (1) t.*
from db.table t
where id > 5
order by date;
You can use row-numbering for this.
Note that if you have no other column to order by, you can do ORDER BY (SELECT NULL), but then you may get different results on each run.
SELECT *
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY id ORDER BY some_other_column) rn
FROM table
) t
WHERE rn = 5;

Select row in group with largest value in particular column postgres

I have a database table which looks like this.
id account_id action time_point
3 234 delete 100
1 656 create 600
1 4435 update 900
3 645 create 50
I need to group this table by id and select particular row where time_point has a largest value.
Result table should look like this:
id account_id action time_point
3 234 delete 100
1 4435 update 900
Thanks for help,
qwew
In Postgres, I would recommend distinct on to solve this top 1 per group problem:
select distinct on (id) *
from mytable
order by id, time_point desc
However, this does not allow possible to ties. If so, rank() is a better solution:
select *
from (
select t.*, rank() over(partition by id order by time_point desc) rn
from mytable t
) t
where rn = 1
Or, if you are running Postgres 13:
select *
from mytable t
order by rank() over(partition by id order by time_point desc)
fetch first row with ties
check this.
select * from x
where exists (
select 1 from x xin
where xin.id = x.id
having max(time_point) = time_point
);

How to find duplicate in one to one mappings in oracle using sql?

I have table as:
ID PAYOR_NAME
---------- ------------
4 AETNAU
4 AETNA
2 UMR
3 CIGNA
1 METLIFE
Id needs to be one to one mapping with payor_name.But Id 4 is associated with multiple payor_name ,so it is considered as duplicate. So,I tried to find the duplicate by using:
select id, count(*) duplic_data
from (
select distinct id, payor_name
from offc.payor_collec
order by id) t1
group by id;
It is giving me the duplicate Id,But i am wondering is there any also way where we can find duplicates in one to one mappings?
There are multiple ways of finding it:
using exists
using group by and having
using analytical function, if you want all column data for that duplicate values (same as exists)
-
select id, payor_name, cnt as count_
from (
select id, payor_name,
count(1) over (partition by id) as cnt
from offc.payor_collec) t1
Where cnt > 1;
It will give you following result:
ID PAYOR_NAME COUNT_
---------- ------------ -------
4 AETNAU 2
4 AETNA 2
Cheers!!
How about simply using exists:
select pc.id, pc.payor_name, count(*)
from offc.payor_collec pc
where exists (select 1
from offc.payor_collec pc2
where pc2.id = pc.id and pc2.payor_name <> pc.payor_name
)
group by pc.id, pc.payor_name
order by pc.id, count(*) desc;
This also orders by the most frequent value, which might be helpful in figuring out the best name.
This could be a way:
select ID, count(*)
from offc.payor_collec
group by ID
having count(distinct PAYOR_NAME) > 1
Another option would be using a subquery containing having clause with having count(ID)>1
select *
from payor_collec
where ID in
( select ID
from payor_collec t
group by ID
having count(ID)>1 )

SQL change the specific row

In my table below, i want to change the placement of specific row.
For example,
ID Name Count
1 X 50
2 Y 30
3 other 25
4 Z 20
It is DESC ordered and i would like to see X,Y,Z orderly. Also, in total, 'other' should be counted. In other words, count should be 125.
You can use union all and add last row to the end.
Something like this:
select id, name,count from table where name<>other
union all
select 4 as id, "other"as name, 135 as count from table
order by 1
or if you want to sum it
select id, name,count from table where name<>other
union all
select 4 as id, 'other' as name, sum(count) as count from table
order by 1
You can put some logic in the order by clause:
select id, name, count
from table
order by case when id <> 3 then 1 else 2 end, id
This way, the first ordering criteria is "rows X, Y, Z first, then the other ones", then you order the groups the way you want, in your case either by id or by name will work.
You can find a working example here
TRY THIS :
SELECT ID,
Name,
CASE
WHEN Name = 'OTHER' THEN (SELECT SUM (COUNT) FROM YOUR_TABLE)
ELSE SUM (COUNT)
END
FROM YOUR_TABLE
GROUP BY Name
ORDER BY Name DESC
I think union all may be the simplest approach, but like this:
select id, name, count
from ((select id, name, count, 1 as ord
from t
where name in ('X', 'Y', 'Z')
) union all
(select 4, 'other', sum(count), 2 as ord
from t
)
) t
order by ord, name;

SQL MIN(value) matching row in PostgreSQL

I have a following tables:
TABLE A:
ID ID NAME PRICE CODE
00001 B 1000 1
00002 A 2000 1
00003 C 3000 1
Here is the SQL I use:
Select Min (ID),
Min (ID NAME),
Sum(PRICE)
From A
GROUP BY CODE
Here is what I get:
ID ID NAME PRICE
00001 A 6000
As you can see, ID NAME don't match up with the min row value. I need them to match up.
I would like the query to return the following
ID ID NAME PRICE
00001 B 6000
What SQL can I use to get that result?
If you want one row, use limit or fetch first 1 row only:
select a.*
from a
order by a.price asc
fetch first 1 row only;
If, for some reason, you want the sum() of all prices, then you can use window functions:
select a.*, sum(a.price) over () as sum_prices
from a
order by a.price asc
fetch first 1 row only;
You can use row_number() function :
select min(id), max(case when seq = 1 then id_name end) as id_name, sum(price) as price, code
from (select t.*, row_number() over (partition by code order by id) seq
from table t
) t
group by code;
you can also use sub-query
select t1.*,t2.* from
(select ID,Name from t where ID= (select min(ID) from t)
) as t1
cross join (select sum(Price) as total from t) as t2
https://dbfiddle.uk/?rdbms=postgres_10&fiddle=a496232b552390a641c0e5c0fae791d1
id name total
1 B 6000