How to select unique records by SQL

SqlDatabase

Sql Problem Overview


When I perform SELECT * FROM table I got results like below:

1 item1 data1
2 item1 data2
3 item2 data3
4 item3 data4

As you can see, there are dup records from column2 (item1 are dupped). So how could I just get result like this:

1 item1 data1
2 item2 data3
3 item3 data4

Only one record are returned from the duplicate, along with the rest of the unique records.

Sql Solutions


Solution 1 - Sql

With the distinct keyword with single and multiple column names, you get distinct records:

SELECT DISTINCT column 1, column 2, ...
FROM table_name;

Solution 2 - Sql

There are 4 methods you can use:

  1. DISTINCT
  2. GROUP BY
  3. Subquery
  4. Common Table Expression (CTE) with ROW_NUMBER()

Consider the following sample TABLE with test data:

/** Create test table */
CREATE TEMPORARY TABLE dupes(word text, num int, id int);

/** Add test data with duplicates */
INSERT INTO dupes(word, num, id)
VALUES ('aaa', 100, 1)
	  ,('bbb', 200, 2)
	  ,('ccc', 300, 3)
	  ,('bbb', 400, 4)
	  ,('bbb', 200, 5)     -- duplicate
	  ,('ccc', 300, 6)     -- duplicate
	  ,('ddd', 400, 7)
	  ,('bbb', 400, 8)     -- duplicate
	  ,('aaa', 100, 9)     -- duplicate
	  ,('ccc', 300, 10);   -- duplicate

Option 1: SELECT DISTINCT

This is the most simple and straight forward, but also the most limited way:

SELECT DISTINCT word, num 
FROM 	dupes
ORDER BY word, num;

/*
word|num|
----|---|
aaa |100|
bbb |200|
bbb |400|
ccc |300|
ddd |400|
*/

Option 2: GROUP BY

Grouping allows you to add aggregated data, like the min(id), max(id), count(*), etc:

SELECT 	word, num, min(id), max(id), count(*)
FROM 	dupes
GROUP BY word, num
ORDER BY word, num;

/*
word|num|min|max|count|
----|---|---|---|-----|
aaa |100|  1|  9|    2|
bbb |200|  2|  5|    2|
bbb |400|  4|  8|    2|
ccc |300|  3| 10|    3|
ddd |400|  7|  7|    1|
*/

Option 3: Subquery

Using a subquery, you can first identify the duplicate rows to ignore, and then filter them out in the outer query with the WHERE NOT IN (subquery) construct:

/** Find the higher id values of duplicates, distinct only added for clarity */
	SELECT  distinct d2.id
	FROM 	dupes d1
		INNER JOIN dupes d2 ON d2.word=d1.word AND d2.num=d1.num
	WHERE d2.id > d1.id

/*
id|
--|
 5|
 6|
 8|
 9|
10|
*/

/** Use the previous query in a subquery to exclude the dupliates with higher id values */
SELECT 	*
FROM 	dupes
WHERE 	id NOT IN (
	SELECT  d2.id
	FROM 	dupes d1
		INNER JOIN dupes d2 ON d2.word=d1.word AND d2.num=d1.num
	WHERE d2.id > d1.id
)
ORDER BY word, num;

/*
word|num|id|
----|---|--|
aaa |100| 1|
bbb |200| 2|
bbb |400| 4|
ccc |300| 3|
ddd |400| 7|
*/

Option 4: Common Table Expression with ROW_NUMBER()

In the Common Table Expression (CTE), select the ROW_NUMBER(), partitioned by the group column and ordered in the desired order. Then SELECT only the records that have ROW_NUMBER() = 1:

WITH CTE AS (
	SELECT 	*
	       ,row_number() OVER(PARTITION BY word, num ORDER BY id) AS row_num
	FROM 	dupes
)
SELECT 	word, num, id 
FROM 	cte
WHERE 	row_num = 1
ORDER BY word, num;

/*
word|num|id|
----|---|--|
aaa |100| 1|
bbb |200| 2|
bbb |400| 4|
ccc |300| 3|
ddd |400| 7|
*/

Solution 3 - Sql

If you only need to remove duplicates then use DISTINCT. GROUP BY should be used to apply aggregate operators to each group

GROUP BY v DISTINCT

Solution 4 - Sql

It depends on which rown you want to return for each unique item. Your data seems to indicate the minimum data value so in this instance for SQL Server.

SELECT item, min(data)
FROM  table
GROUP BY item

Solution 5 - Sql

just use inner join because group by won't work with multiple columns saying not contained in either an aggregate function.

SELECT a.*
FROM yourtable a
INNER JOIN 
  (SELECT yourcolumn,
    MIN(id) as id
  FROM yourtable 
  GROUP BY yourcolumn
) AS b
  ON a.yourcolumn= b.yourcolumn
  AND a.id = b.id;

Solution 6 - Sql

To get all the columns in your result you need to place something as:

SELECT distinct a, Table.* FROM Table

it will place a as the first column and the rest will be ALL of the columns in the same order as your definition. This is, column a will be repeated.

Solution 7 - Sql

I am not sure if the accepted answer works. It does not work on postgres 12 at least. DISTINCT keyword is supposed to be applied to all the columns in the select query and not just to the column next to which DISTINCT keyword is written. So, basically, it means that every row returned in the result will be unique in terms of the combination of the select query columns. In OP's question, the below two result rows are already distinct, as they have different values for column1 and column 3.

1 item1 data1
2 item1 data2

Now, to answer the question, atleast in postgres, there is a DISTINCT ON keyword. This will achieve what the OP requires.

select DISTINCT ON(column2) column1, column3 from Table1;

Solution 8 - Sql

I find that if I can't use DISTINCT for any reason, then GROUP BY will work.

Solution 9 - Sql

Select Eff_st from ( select EFF_ST,ROW_NUMBER() over(PARTITION BY eff_st) XYZ - from ABC.CODE_DIM

) where XYZ= 1 order by EFF_ST fetch first 5 row only

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionYinanView Question on Stackoverflow
Solution 1 - SqlmjalldayView Answer on Stackoverflow
Solution 2 - SqlisapirView Answer on Stackoverflow
Solution 3 - SqlrahulView Answer on Stackoverflow
Solution 4 - SqlDave BarkerView Answer on Stackoverflow
Solution 5 - SqlAnkit KashyapView Answer on Stackoverflow
Solution 6 - SqlhtafoyaView Answer on Stackoverflow
Solution 7 - SqlBinita BharatiView Answer on Stackoverflow
Solution 8 - SqlJohn HamelinkView Answer on Stackoverflow
Solution 9 - SqlShailendra SinghaiView Answer on Stackoverflow