mysql组使用范围记录值

时间:2011-04-17 03:04:51

标签: mysql group-by group-concat

在SQL中我有下面的表t_test:

emp_code | period_month | company_code  
NIK001   | 01           | ALPHA
NIK001   | 02           | ALPHA
NIK001   | 03           | ALPHA
NIK001   | 04           | ALPHA
NIK001   | 05           | ALPHA
NIK001   | 06           | BETA 
NIK001   | 07           | BETA
NIK001   | 08           | BETA
NIK001   | 09           | BETA
NIK001   | 10           | ALPHA
NIK001   | 11           | ALPHA
NIK001   | 12           | ALPHA

我想查询以下结果:

emp_code | company_code | from_month  | to_month 
--------------------------------------------------
NIK001   | ALPHA        | 01          | 05
NIK001   | BETA         | 06          | 09
NIK001   | ALPHA        | 10          | 12

3 个答案:

答案 0 :(得分:1)

这让我在恐惧中颤抖,但它确实输出了你所追求的近似值:

    select w.emp_code, w.company_code, w.period_month from_month,
(select min(convert(u.period_month,unsigned))-1 from t_test u where u.emp_code=w.emp_Code and convert(u.period_month,signed)>convert(w.period_month,signed) and u.company_code<>w.company_code) to_month
 from 
(
select * from
(
select y.emp_code, y.period_month, y.company_code,
(select x.company_code from t_test x where x.emp_code=y.emp_code and convert(x.period_month,unsigned)<convert(y.period_month,unsigned) order by convert(x.period_month,unsigned) desc limit 1) previous_company_code
 from t_test y
) z
where company_code<>previous_company_code or previous_company_code is null
) w

然而,我出于好奇而尝试了这一点。你不应该真的依赖于你的生产环境。我认为简单的SQL查询不适合您的问题。我会去其他地方看看。

编辑:基于下表:

CREATE TABLE `t_test` (
  `emp_code` varchar(50) DEFAULT NULL,
  `period_month` varchar(2) DEFAULT NULL,
  `company_code` varchar(50) DEFAULT NULL
);

填写以下INSERT语句:

INSERT INTO `t_test` (`emp_code`,`period_month`,`company_code`)
VALUES
    ('NIK001', '01', 'ALPHA'),
    ('NIK001', '02', 'ALPHA'),
    ('NIK001', '03', 'ALPHA'),
    ('NIK001', '04', 'ALPHA'),
    ('NIK001', '05', 'ALPHA'),
    ('NIK001', '06', 'BETA'),
    ('NIK001', '07', 'BETA'),
    ('NIK001', '08', 'BETA'),
    ('NIK001', '09', 'BETA'),
    ('NIK001', '10', 'ALPHA'),
    ('NIK001', '11', 'ALPHA'),
    ('NIK001', '12', 'ALPHA');

答案 1 :(得分:1)

您可以使用MySQL变量。例如:

SET @ttt = 0;

SELECT
    @ttt := IF(
        `company_code`=(SELECT `company_code` FROM `range` r2 WHERE r2.`period_month`<r1.`period_month` ORDER BY `period_month` DESC LIMIT 1), 
        @ttt,
        @ttt+1) iter,
`period_month`,
`company_code`
FROM `range` r1
WHERE emp_code = 'NIK001'
ORDER BY period_month ASC;

在我的测试数据上,这给了我:

iter period_month company_code
1    1            Alpha
1    2            Alpha
1    3            Alpha
2    4            Beta
2    5            Beta
2    6            Beta
3    7            Alpha
3    8            Alpha
3    9            Alpha
3    10           Alpha

我们的想法是,在每一行上检查当前company_code是否等于前一记录的SET @ttt = 0; SELECT `company_code`,MIN(`period_month`),MAX(`period_month`) FROM ( SELECT @ttt := IF( `company_code`=(SELECT `company_code` FROM `range` r2 WHERE r2.`period_month`<r1.`period_month` ORDER BY `period_month` DESC LIMIT 1), @ttt, @ttt+1) iter, `period_month`, `company_code` FROM `range` r1 WHERE emp_code = 'NIK001' ORDER BY period_month ASC ) subreq GROUP BY iter ; 。如果不同,请增加变量。

这是向前迈出的一步。但是如何分组行?您不能直接对它们进行分组,但是您需要使用第二个查询来包装它。

company_code MIN(`period_month`) MAX(`period_month`)
Alpha        1                   3
Beta         4                   6
Alpha        7                   10

在外部查询中使用内部查询的结果。这给了我测试数据

period_month

如果需要限制行的选择,请在 inner 查询的where子句中执行此操作,否则整个数据库将在每个查询中加载到内存中。另一个问题是内部查询将前一条记录作为“具有最接近period_month ASC的记录”。作为一种效果,您必须按内容查询除{{ 1}}。如果需要,您仍然可以在外部查询中对事物进行排序。

最后,如果您出于某种原因使用旧的mysql_query界面,则需要将SET行放在单独的查询中,因为它只能处理一次一个查询。

mysql_query("SET @ttt = 0;");

$rs=mysql_query("SELECT `company_code`,MIN(`period_month`),MAX(`period_month`)
FROM
(    SELECT
        @ttt := IF(
            `company_code`=(SELECT `company_code` FROM `range` r2 WHERE r2.`period_month`<r1.`period_month` ORDER BY `period_month` DESC LIMIT 1), 
            @ttt,
            @ttt+1) iter,
    `period_month`,
    `company_code`
FROM `range` r1) subreq
    GROUP BY iter
;");

在扩展到大型数据库时,不确定此方法的效果如何,但它确实有效。也许有一种“好”的方式。如果您不完全理解它,请确保在查询中不小心弄乱了一些内容。 :)

答案 2 :(得分:0)

@magma:答案很多。做得好!谢谢..

我刚做了一点修改,所以from_month和to_month永远不会得到NULL值。

为了在执行查询时加快速度,我创建带会话的临时表来存储查询结果,并使用临时数据生成报告

SELECT
  w.emp_code, w.company_code, w.period_month from_month,
  LPAD(
    IFNULL(
    IFNULL(
      ( select min(u.period_month)-1
        from t_test u
        where (u.emp_code = w.emp_code)
        and (u.period_month > w.period_month)
        and (u.company_code  w.company_code)
      ),( select max(v.period_month)
          from t_test v
          where
          (v.emp_code=w.emp_code)
          and (v.period_month > w.period_month)
          and (v.company_code = w.company_code)
         )
    ),( select max(z.period_month)
          from t_test z
          where
          (z.emp_code=w.emp_code)
          and (z.period_month = w.period_month)
          and (z.company_code = w.company_code)
         )
    ),2,'0'
  ) AS to_month
FROM
  ( select *
    from
    (
      select
        y.emp_code, y.company_code, y.period_month, 
        ( select x.company_code
          from t_test x
          where
          (x.emp_code = y.emp_code)
          and (x.period_month  previous_company_code)
  or (previous_company_code is null)
  ) w