68

我正在与中的 distinct 关键字作斗争sql。我只想distinct在一列中显示唯一()值的所有行号,所以我尝试了:

SELECT DISTINCT id, ROW_NUMBER() OVER (ORDER BY id) AS RowNum
FROM table
WHERE fid = 64

但是下面的代码给了我distinct值:

SELECT distinct id FROM table WHERE fid = 64

但是当用Row_Number.
然后它不工作。

4

8 回答 8

118

这可以很简单地完成,你已经很接近了

SELECT distinct id, DENSE_RANK() OVER (ORDER BY  id) AS RowNum
FROM table
WHERE fid = 64
于 2013-08-08T08:26:56.783 回答
60

用这个:

SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS RowNum FROM
    (SELECT DISTINCT id FROM table WHERE fid = 64) Base

并将查询的“输出”作为另一个查询的“输入”。

使用 CTE:

; WITH Base AS (
    SELECT DISTINCT id FROM table WHERE fid = 64
)

SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS RowNum FROM Base

这两个查询应该是等价的。

从技术上讲,你可以

SELECT DISTINCT id, ROW_NUMBER() OVER (PARTITION BY id ORDER BY id) AS RowNum 
    FROM table
    WHERE fid = 64

但是如果增加 DISTINCT 字段的数量,则必须将所有这些字段放在 中PARTITION BY,例如

SELECT DISTINCT id, description,
    ROW_NUMBER() OVER (PARTITION BY id, description ORDER BY id) AS RowNum 
    FROM table
    WHERE fid = 64

我什至希望您理解您在这里违反标准命名约定,id应该是主键,根据定义如此独特,因此 aDISTINCT将无用,除非您将查询与一些JOINs/ UNION ALL...

于 2013-08-08T08:20:52.843 回答
35

本文介绍了ROW_NUMBER()DENSE_RANK()之间的一个有趣的关系(RANK()函数没有具体处理)。当您需要ROW_NUMBER()SELECT DISTINCT语句上生成时,将在关键字删除之前ROW_NUMBER()生成不同的值DISTINCT。例如这个查询

SELECT DISTINCT
  v, 
  ROW_NUMBER() OVER (ORDER BY v) row_number
FROM t
ORDER BY v, row_number

...可能会产生这个结果(DISTINCT没有效果):

+---+------------+
| V | ROW_NUMBER |
+---+------------+
| a |          1 |
| a |          2 |
| a |          3 |
| b |          4 |
| c |          5 |
| c |          6 |
| d |          7 |
| e |          8 |
+---+------------+

而这个查询:

SELECT DISTINCT
  v, 
  DENSE_RANK() OVER (ORDER BY v) row_number
FROM t
ORDER BY v, row_number

...在这种情况下产生你可能想要的东西:

+---+------------+
| V | ROW_NUMBER |
+---+------------+
| a |          1 |
| b |          2 |
| c |          3 |
| d |          4 |
| e |          5 |
+---+------------+

请注意,ORDER BY该函数的子句DENSE_RANK()将需要该子句中的所有其他列SELECT DISTINCT才能正常工作。

比较所有三个功能

使用 PostgreSQL / Sybase / SQL 标准语法(WINDOW从句):

SELECT
  v,
  ROW_NUMBER() OVER (window) row_number,
  RANK()       OVER (window) rank,
  DENSE_RANK() OVER (window) dense_rank
FROM t
WINDOW window AS (ORDER BY v)
ORDER BY v

... 你会得到:

+---+------------+------+------------+
| V | ROW_NUMBER | RANK | DENSE_RANK |
+---+------------+------+------------+
| a |          1 |    1 |          1 |
| a |          2 |    1 |          1 |
| a |          3 |    1 |          1 |
| b |          4 |    4 |          2 |
| c |          5 |    5 |          3 |
| c |          6 |    5 |          3 |
| d |          7 |    7 |          4 |
| e |          8 |    8 |          5 |
+---+------------+------+------------+
于 2014-05-23T06:24:16.060 回答
6

在添加字段时使用DISTINCT会导致问题,它还可以掩盖您选择中的问题。用作GROUP BY这样的替代方案:

SELECT id
      ,ROW_NUMBER() OVER (ORDER BY  id) AS RowNum
  FROM table
 where fid = 64
 group by id

然后,您可以从您的选择中添加其他有趣的信息,如下所示:

,count(*) as thecount

或者

,max(description) as description
于 2016-03-26T20:43:55.097 回答
2

像这样的东西怎么样

;WITH DistinctVals AS (
        SELECT  distinct id 
        FROM    table 
        where   fid = 64
    )
SELECT  id,
        ROW_NUMBER() OVER (ORDER BY  id) AS RowNum
FROM    DistinctVals

SQL 小提琴演示

你也可以试试

SELECT distinct id, DENSE_RANK() OVER (ORDER BY  id) AS RowNum
FROM @mytable
where fid = 64

SQL 小提琴演示

于 2013-08-08T08:21:54.237 回答
0

尝试这个

SELECT distinct id
FROM  (SELECT id, ROW_NUMBER() OVER (ORDER BY  id) AS RowNum
      FROM table
      WHERE fid = 64) t

或使用RANK()代替行号并选择记录DISTINCT rank

SELECT id
FROM  (SELECT id, ROW_NUMBER() OVER (PARTITION BY  id ORDER BY  id) AS RowNum
      FROM table
      WHERE fid = 64) t
WHERE t.RowNum=1

这也返回不同的 id

于 2013-08-08T08:20:45.650 回答
0

尝试这个:

;WITH CTE AS (
               SELECT DISTINCT id FROM table WHERE fid = 64
             )
SELECT id, ROW_NUMBER() OVER (ORDER BY  id) AS RowNum
  FROM cte
 WHERE fid = 64
于 2013-08-08T08:21:00.070 回答
0

问题太老了,我的回答可能不会增加太多,但这是我的两分钱,可以让查询有点用处:

;WITH DistinctRecords AS (
    SELECT  DISTINCT [col1,col2,col3,..] 
    FROM    tableName 
    where   [my condition]
), 
serialize AS (
   SELECT
    ROW_NUMBER() OVER (PARTITION BY [colNameAsNeeded] ORDER BY  [colNameNeeded]) AS Sr,*
    FROM    DistinctRecords 
)
SELECT * FROM serialize 

使用两个 cte 的用处在于,现在您可以在查询中更轻松地使用序列化记录,并且count(*)非常轻松地执行等操作。

DistinctRecords将选择所有不同的记录并将serialize序列号应用于不同的记录。之后,您可以将最终的序列化结果用于您的目的,而不会造成混乱。

Partition By在大多数情况下可能不需要

于 2020-08-31T09:40:40.483 回答