Showing only duplicate rows from table in postgres - sql

I have table like this:
--------------------------------------
| id | name | phone_number | address |
--------------------------------------
| 1 | Ram | 9090909090 | Delhi |
| 2 | Shyam| 9865444456 | Mumbai |
| 3 | Mohan| 9756543455 | Chennai |
| 4 | Ram | 9090909090 | Delhi |
--------------------------------------
I want to return the rows having same column data. The result will be like this:
--------------------------------------
| id | name | phone_number | address |
--------------------------------------
| 1 | Ram | 9090909090 | Delhi |
| 4 | Ram | 9090909090 | Delhi |
--------------------------------------

This can be done using window functions which avoids the join on the aggregated data and is usually the faster way:
select *
from (
select id,name,phone_number,address
count(*) over (partition by name,phone_number,address) as cnt
from the_table
) t
where cnt > 1;

SELECT t2.id,t2.name,t2.phone_number,t2.address
FROM
(
SELECT name,phone_number,address
FROM tableName
GROUP BY name,phone_number,address
HAVING COUNT(*) > 1
) AS t1
INNER JOIN tableName t2
ON t1.name=t2.name AND t1.phone_number=t2.phone_number AND t1.address=t2.address

Please run the below query, (consider table name to be "data"), to get the desired result as follows:
SELECT * FROM data where name IN (SELECT name FROM data GROUP BY name HAVING COUNT(*) > 1);

SELECT T1.*
FROM
table_name T1
INNER JOIN table_name T2 ON
T1.name= T2.nam` AND
T1.phone_number= T2.phone_number AND T1.address= T2.address
WHERE T2.id <> T1.id

Related

How can I subtract two row's values within same column using sql query in access?

(query access)
This is the table structure:
+-----+--------+--------+
| id | name | sub1 |
+-----+--------+--------+
| 1 | ABC | 6.27% |
| 2 | ABC | 7.47% |
| 3 | PQR | 3.39% |
| 4 | PQR | 2.21% |
+-----+--------+--------+
I want to subtract Sub1
Output should be:
+-----+--------+---------+------------------------------------+
| id | name | sub1 | |
+-----+--------+---------+------------------------------------+
| 1 | ABC | 6.27% | 0 First Rec no need Subtract |
| 2 | ABC | 7.47% | 1.2% <=(7.47-6.27) |
| 3 | PQR | 3.39% | 0 First Rec no need Subtract |
| 4 | PQR | 2.21% | -1.18% <=(2.21-3.39) |
+-----+--------+---------+------------------------------------+
Thank you so much.
If you can guarantee consecutive id values, then the following presents an alternative:
select t.*, nz(t.sub1-u.sub1,0) as sub2
from YourTable t left join YourTable u on t.name = u.name and t.id = u.id+1
Change YourTable to the name of your table.
This is painful, but you can do:
select t.*,
(select top 1 t2.sub1
from t as t2
where t2.name = t.name and t2.id < t.id
order by t2.id desc
) as prev_sub1
from t;
This gives the previous value or NULL for the first row. You can just use - for the subtraction.
An index on (name, id) would help a bit with performance. However, if you can upgrade to a better database, you can then just use lag().

Multi not like expression sql

So basically i've a table like this.
+--------+----------+
| name | Group |
+--------+----------+
| xxxx | 1 |
| yyyy | 1 |
| xxxx | 2 |
| yyyy | 3 |
| xxxx | 4 |
+--------+----------+
and i don't want to display any records that have name xxxx in their group.
You seem want :
select t.*
from table t
where not exists (select 1 from table t1 where t1.group = t.group and t1.name = 'xxxx')
You need a subquery at first to identify groups you do not need. then you need to filter it from main query
SELECT * FROM Table1
Where group not in ( select group from Table1 where name != 'xxxx')

find records having more than one distinct colum value

Given table t1 with columns Id ( text, primary key ) and place (text) like below.
+-------+-----------+
| Id | place |
+-------+-----------+
| abcde | Santori |
| bcdef | Krypt |
| cdefg | Bali |
| defgh | Bangkok |
| abcde | Colombo |
+-------+-----------+
I need to find out the records for Ids having more than one distinct place. In the above example the output shall be
+-------+-----------+
| Id | place |
+-------+-----------+
| abcde | Santori |
| abcde | Colombo |
+-------+-----------+
I would use exists :
select t.*
from table t
where exists (select 1 from table t1 where t1.id = t.id and t1.place <> t.place);
I think it is OK for you:
SELECT ID, PLACE FROM T1 as A
WHERE A.ID IN
(SELECT ID FROM T1 AS B
GROUP BY ID
HAVING count(*) > 1
)
In a subquery, you need to get count of distinct place and get the ID. And then use an outer query to fetch all records.
Fiddle Example
select * From T1
where T1.ID in
(select ID from T1
group by ID
having count(distinct PLACE) > 1
)

Getting the last updated name

I am having a table having records like this:
+------+------+
| ID | name |
+------+------+
| 1 | A |
| 2 | B |
| 3 | C |
| 4 | A |
| 5 | B |
| 6 | A |
| 7 | A |
| 8 | A |
+------+------+
I need to get value of A after it was last updated from a different value, for example here it would be the row at ID 6.
Try this query (MySQL syntax):
select min(ID)
from records
where name = 'A'
and ID >=
(
select max(ID)
from records
where name <> 'A'
);
Illustration:
select * from records;
+------+------+
| ID | name |
+------+------+
| 1 | A |
| 2 | B |
| 3 | C |
| 4 | A |
| 5 | B |
| 6 | A |
| 7 | A |
| 8 | A |
+------+------+
-- run query:
+---------+
| min(ID) |
+---------+
| 6 |
+---------+
Using the Lag function...
SELECT Max([ID])
FROM (SELECT [name], [ID],
Lag([name]) OVER (ORDER BY [ID]) AS PrvVal
FROM tablename) tbl
WHERE [name] = 'A'
AND prvval <> 'A'
Online Demo: http://www.sqlfiddle.com/#!18/a55eb/2/0
If you want to get the whole row, you can do this...
SELECT Top 1 *
FROM (SELECT [name], [ID],
Lag([name]) OVER (ORDER BY [ID]) AS PrvVal
FROM tablename) tbl
WHERE [name] = 'A' AND prvval <> 'A'
ORDER BY [ID] DESC
Online Demo: http://www.sqlfiddle.com/#!18/a55eb/22/0
The ANSI SQL below uses a self-join on the previous id.
And the where-clause gets those with a name that's different from the previous.
select max(t1.ID) as ID
from YourTable as t1
left join YourTable as t2 on t1.ID = t2.ID+1
where (t1.name <> t2.name or t2.name is null)
and t1.name = 'A';
It should work on most RDBMS, including MS Sql Server.
Note that with the ID+1 that there's an assumption that are no gaps between the ID's.

Find and update specific duplicates in MS SQL

given below table:
+----+---------+-----------+-------------+-------+
| ID | NAME | LAST NAME | PHONE | STATE |
+----+---------+-----------+-------------+-------+
| 1 | James | Vangohg | 04333989878 | NULL |
| 2 | Ashly | Baboon | 09898788909 | NULL |
| 3 | James | Vangohg | 04333989878 | NULL |
| 4 | Ashly | Baboon | 09898788909 | NULL |
| 5 | Michael | Foo | 02933889990 | NULL |
| 6 | James | Vangohg | 04333989878 | NULL |
+----+---------+-----------+-------------+-------+
I want to use MS SQL to find and update duplicate (based on name, last name and number) but only the earlier one(s). So desired result for above table is:
+----+---------+-----------+-------------+-------+
| ID | NAME | LAST NAME | PHONE | STATE |
+----+---------+-----------+-------------+-------+
| 1 | James | Vangohg | 04333989878 | DUPE |
| 2 | Ashly | Baboon | 09898788909 | DUPE |
| 3 | James | Vangohg | 04333989878 | DUPE |
| 4 | Ashly | Baboon | 09898788909 | NULL |
| 5 | Michael | Foo | 02933889990 | NULL |
| 6 | James | Vangohg | 04333989878 | NULL |
+----+---------+-----------+-------------+-------+
This query uses a CTE to apply a row number, where any number > 1 is a dupe of the row with the highest ID.
;WITH x AS
(
SELECT ID,NAME,[LAST NAME],PHONE,STATE,
ROW_NUMBER() OVER (PARTITION BY NAME,[LAST NAME],PHONE ORDER BY ID DESC)
FROM dbo.YourTable
)
UPDATE x SET STATE = CASE rn WHEN 1 THEN NULL ELSE 'DUPE' END;
Of course, I see no reason to actually update the table with this information; every time the table is touched, this data is stale and the query must be re-applied. Since you can derive this information at run-time, this should be part of a query, not constantly updated in the table. IMHO.
Try this statement.
LAST UPDATE:
update t1
set
t1.STATE = 'DUPE'
from
TableName t1
join
(
select name, last_name, phone, max(id) as id, count(id) as cnt
from
TableName
group by name, last_name, phone
having count(id) > 1
) t2 on ( t1.name = t2.name and t1.last_name = t2.last_name and t1.phone = t2.phone and t1.id < t2.id)
If my understanding of your requirements is correct, you want to update all of the STATE values to DUPE when there exists another row with a higher ID value that has the same NAME and LAST NAME. If so, use this:
update t set STATE = (case when sorted.RowNbr = 1 then null else 'DUPE' end)
from yourtable t
join (select
ID,
row_number() over
(partition by name, [last name], phone order by id desc) as RowNbr from yourtable)
sorted on sorted.ID = t.ID