【问题标题】:MySQL - Get a counter for each duplicate valueMySQL - 为每个重复值获取一个计数器
【发布时间】:2012-09-17 16:39:39
【问题描述】:

我有一个有两列的表格。

+------+------+
| data | num  | 
+------+------+
| a    |      | 
| a    |      |
| a    |      |
| b    |      |
| b    |      |
| c    |      |
| d    |      |
| a    |      |
| b    |      | 
+------+------+

我希望“num”列为每个重复条目显示一个增量计数器:

+------+------+
| data | num  | 
+------+------+
| a    |    1 | 
| a    |    2 |
| a    |    3 |
| b    |    1 |
| b    |    2 |
| c    |    1 |
| d    |    1 |
| a    |    4 |
| b    |    3 | 
+------+------+

除了 mySQL 查询之外,这是否可以在没有任何其他脚本的情况下完成?

更新:

扩展问题here

【问题讨论】:

  • 我认为可以用光标完成
  • COUNT() 与 GROUP BY 一起为我提供了重复条目的数量。但是我找不到如何增加“每次”重复出现...
  • 怎么样?如果我只是按数据排序,它会给我一个增量,每次找到新条目时都不会重置..对吗?它只会显示:a - 1, a - 2, a - 3, a - 4, b - 5, b - 6...

标签: mysql sql


【解决方案1】:

不幸的是,MySQL 没有您需要的窗口函数。所以你将不得不使用这样的东西:

最终查询

select data, group_row_number, overall_row_num
from
(
  select data,
        @num := if(@data = `data`, @num + 1, 1) as group_row_number,
        @data := `data` as dummy, overall_row_num
  from
  (
    select data, @rn:=@rn+1 overall_row_num
    from yourtable, (SELECT @rn:=0) r
  ) x
  order by data, overall_row_num
) x
order by overall_row_num

SQL Fiddle with Demo

说明:

首先,内部选择,这会将模拟row_number 应用于表中的所有记录(请参阅SQL Fiddle with Demo):

select data, @rn:=@rn+1 overall_row_num
from yourtable, (SELECT @rn:=0) r

查询的第二部分,将表中的每一行与下一行进行比较,看看它是否具有相同的值,如果没有,则重新开始 group_row_number(参见 SQL Fiddle with Demo):

select data,
      @num := if(@data = `data`, @num + 1, 1) as group_row_number,
      @data := `data` as dummy, overall_row_num
from
(
  select data, @rn:=@rn+1 overall_row_num
  from yourtable, (SELECT @rn:=0) r
) x
order by data, overall_row_num

最后一个选择,返回你想要的值,并按照你要求的顺序放回去:

select data, group_row_number, overall_row_num
from
(
  select data,
        @num := if(@data = `data`, @num + 1, 1) as group_row_number,
        @data := `data` as dummy, overall_row_num
  from
  (
    select data, @rn:=@rn+1 overall_row_num
    from yourtable, (SELECT @rn:=0) r
  ) x
  order by data, overall_row_num
) x
order by overall_row_num

【讨论】:

  • 只是为这个出色的答案添加一些纹理 :),图像我有另一个带有 ID 的列(增量)。现在我想将我的“num”列更新为“data”上的字母和您建议的计数器之间的连接,例如“num”数据将是:aa1,aa2,aa3,bb1,bb2,......无论如何,太好了!您已经保存了我的一天(或一周或一个月)。与此同时,我会尝试自己更新我的表格......
  • @kairos 很乐意为您提供帮助,我的建议是,如果您还有其他问题,请发布一个新问题以寻求帮助。 :) 如果此答案对您有所帮助,请务必通过左侧的复选标记将其标记为已接受。
  • +1 适当的 ROW_NUMBER() 支持会更容易。我建议在执行查询之前初始化@rn,否则,尤其是随着查询随着时间的推移而发展,可能会遇到obscure, unpleasant behavior 这样的用户变量初始化。
  • @pilcrow 我同意适当的row_number() 支持对于这些类型的查询会容易得多。
  • 我在许多 MySQL 版本和许多客户端上尝试了此代码,我不断得到每行的 group_row_number = 1,我应用了相同的架构和相同的数据集。
【解决方案2】:

这是一个简单的查询,可以满足您的要求。

select id,data,rownum 
  from (
          select id,
                 data,
                 @row:=if(@prev=data,@row,0) + 1 as rownum,
                 @prev:=data 
            from tbl
        order by data,id
)t

我在每一行都包含了一个 ID。但你不需要它。

去小提琴:http://sqlfiddle.com/#!2/1d1f3/11/0

信用:Want Row Number on Group of column in MY SQL?

【讨论】:

    【解决方案3】:

    数据是否必须保持显示的顺序,还是我们可以按“数据”值排序?

    如果你可以排序,那么你只需要跟踪当前的“数据”值,这可以通过变量来完成:

    set @last_data = null;
    set @count = 0;
    select data, @count,
      case when @last_data is null or data != @last_data then @count := 1 else @count := @count + 1 end as new_count,
      @last_data := data, @count
    from t20120917
    order by data;
    

    如果不是,我认为它会更复杂......

    【讨论】:

      【解决方案4】:

      是这样的,但是你需要创建过程

      create procedure procname()
      begin
      DECLARE done,i,j int DEFAULT 0;
      DECLARE n,m nvarchar(500) DEFAULT '';
      
      DECLARE cur CURSOR FOR SELECT d.data,d.num FROM tablename AS d ORDER BY DATA;
      DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
      
      
      OPEN cur;
      
      read_loop: LOOP
      
      set m = n;
      SET j = i;
      fetch cur into n,i;
      
      IF n = m 
      THEN
      SET i = i+1;
      // UPDATE here your TABLE but you will need one more colomn to be able to UPDATE ONLY one RAW that you need
      ELSE 
      SET i = 0; //RESET indexer 
      END IF;
      
      IF done = 1 THEN
      LEAVE read_loop;
      END IF;
      
      END LOOP read_loop;
      
      CLOSE cur;
      end
      

      【讨论】:

        猜你喜欢
        • 2013-11-16
        • 1970-01-01
        • 2015-09-11
        • 2014-04-27
        • 2020-10-07
        • 2023-01-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多