如何处理循环列以在SQL中输出循环数?

时间:2013-05-10 19:18:50

标签: mysql sql

如何使用值为圆形的列(即1,2,3,1,2,3,1,2,3 ....)来计算并输出循环的索引号? 例如,在这个简化的表格中......

num cir
1    1
2    2
3    3
4    1
5    2
6    3
7    1
8    2
9    3

我怎么能得到这个?

num cir index
1    1    1
2    2    1
3    3    1
4    1    2
5    2    2
6    3    2
7    1    3
8    2    3
9    3    3

实际上,我试图管理的表格要大得多(数百万条记录乘以160列),所以如果有多种解决方案,我希望听到更有效的解决方案......谢谢。

4 个答案:

答案 0 :(得分:3)

Gordon Linoff is right:在SQL中,表确实没有固有的顺序。但是,仍然有一种方法可以为您的案例分配索引。唯一的问题是,订单是不确定的,1可能与2组合在一起,不一定是跟随它的2(按照您可能期望的任何特定顺序)。也就是说,最终结果可能与您的示例相似:

num  cir  index
---  ---  -----
1    1    1
2    2    1
3    3    1
4    1    2
5    2    2
6    3    2
7    1    3
8    2    3
9    3    3

但很可能是例如相反:

num  cir  index
---  ---  -----
7    1    1
2    2    1
3    3    1
4    1    2
8    2    2
6    3    2
1    1    3
5    2    3
9    3    3

如果num没有“井然有序”,就像你说的那样(因此,我假设,不能用于排序)。

我们的想法是仅对cir列上的数据集进行排序

num  cir
---  ---
1    1
4    1
7    1
2    2
5    2
8    2
3    3
6    3
9    3

然后使用变量赋值生成index

num  cir                index
---  ---                -----
1    1    1             1
4    1    2             2
7    1    3             3
2    2       1     ->   1
5    2       2          2
8    2       3          3
3    3          1       1
6    3          2       2
9    3          3       3

以下是:

SELECT
  num,
  cir,
  `index`
FROM (
  SELECT
    num,
    @index := @index * (cir = @lastcir) + 1 AS `index`,
    @lastcir := cir AS cir
  FROM
    yourtable,
    (SELECT @index := 0, @lastcir := 0) v
  ORDER BY
    cir
) s
ORDER BY
  `index`,
  cir
;

可以猜到,这个表达

@index := @index * (cir = @lastcir) + 1

是指定索引的那个。基本上,如果您删除* (cir = @lastcir)部分,则会获得

@index := @index + 1

可能不需要解释:它只是递增@index值。

每次遇到新的cir值时,都会重置枚举(请记住,数据集是在cir上排序的)。在MySQL中,布尔表达式(如cir = @lastcir)隐式转换为期望数字的上下文中的数字,如算术表达式的上下文。更具体地说,它转换为1的{​​{1}}和true的{​​{1}}。因此,只要0等于false(即前一行cir),@lastcir表达式基本上等同于cir,但{ {1}}和index不同(这意味着我们刚遇到一个新的@index := @index + 1组),表达式实际上变为cir,即枚举现在重新开始。< / p>

如果您愿意,可以测试此解决方案at SQL Fiddle

答案 1 :(得分:1)

假设num1是有序的(尽管可能存在间隙),解决此问题的一种方法是根据找到的循环数的次数来分配索引,以获得较小的{{1}值}}。我认为在MySQL中最明智的方法是使用相关的子查询:

num

如果未订购select t.*, (select count(*) from t t2 where t2.cir = t.cir and t2.num <= t.num ) as `index` from t ,则表示您遇到问题。 SQL表本质上是无序的,因此给定行没有“之前”和“之后”的概念。也就是说,除非您有某种方式对结果进行排序,否则没有一种强大的方式来分配索引。

答案 2 :(得分:0)

尝试使用非下一个cirsakes进行自我加入并计算它们:

SELECT t1.num AS num, t1.cir AS cir, COUNT(*) AS index
  FROM t AS t1 JOIN t AS t2 on t2.cir = t1.cir AND t2.num <= t1.num
  GROUP BY t1.num, t1.cir
;

答案 3 :(得分:0)

试试这个

SELECT 
  num,
  cir,
  @row_num := IF(@prev_cir<cir,@row_num,@row_num+1) as cir_index,
  @prev_cir:= cir
FROM 
(SELECT @row_num := 0) r
JOIN (
    SELECT 
      num, 
      cir 
    FROM 
      mytable 
    ORDER BY
      num
) t

首先,我确保记录按num排序。然后我知道前一个cir与当前的cir。如果之前的cir_index大于当前{{1}},我会增加{{1}}

SQLFIDDLE