【问题标题】:mysql group by using the range record valuemysql 使用范围记录值分组
【发布时间】:2011-08-07 03:55:19
【问题描述】:

在 SQL 中,我有下面的表 t_test:

emp_code | period_month |公司代码 NIK001 | 01 | Α NIK001 | 02 | Α NIK001 | 03 | Α NIK001 | 04 | Α NIK001 | 05 | Α NIK001 | 06 |测试版 NIK001 | 07 |测试版 NIK001 | 08 |测试版 NIK001 | 09 |测试版 NIK001 | 10 | Α NIK001 | 11 | Α NIK001 | 12 | Α

我想查询结果如下:

emp_code |公司代码 |从_月 | to_month -------------------------------------------------- NIK001 |阿尔法 | 01 | 05 NIK001 |测试版 | 06 | 09 NIK001 |阿尔法 | 10 | 12

【问题讨论】:

  • 你的解释没有帮助。您想用输入数据实现什么目标?
  • 为什么要使用纯 SQL 执行此操作?我非常怀疑是否可以满足特定场景,同时仍然保持拥有数据库的有用性。
  • @edalorzo 我认为他希望根据特定的 emp_code-company_code 组合获得不间断的 period_month 范围。
  • @edalorzo :我想在 emp_code 在公司工作时获取期间月份 @Khez :由于员工在不同公司工作,该范围将在 6、7、8、9 中断跨度>
  • 谢谢,我会试一试只是为了好玩,但我看起来不像不使用函数或其他类型的编码就无法完成的事情.

标签: mysql group-by group-concat


【解决方案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');

【讨论】:

  • @yuda,尝试使用我必须根据您的问题复制的创建表/插入语句。
  • 它工作.. thnks 很多.. 但最后一条记录是“from_month : 10”和“to_month : NULL”
【解决方案2】:

您可以使用 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

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

最后,如果您出于某种原因使用旧的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
;");

不确定这种方法在扩展到大型数据库时效果如何,但它确实有效。也许有一个“好”的方法。只要确保您不会在查询中意外弄乱某些东西,以防您不完全理解它。 :)

【讨论】:

    【解决方案3】:

    @magma :非常感谢您的回答。好工作!谢谢。。

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

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

    选择 w.emp_code, w.company_code, w.period_month from_month, 平板电脑( 如果空( 如果空( (选择分钟(u.period_month)-1 从 t_test 你 其中(u.emp_code = w.emp_code) 和(u.period_month > w.period_month) 和(u.company_code w.company_code) ),( 选择最大值(v.period_month) 从 t_test v 在哪里 (v.emp_code=w.emp_code) 和(v.period_month > w.period_month) 和 (v.company_code = w.company_code) ) ),( 选择最大值(z.period_month) 从 t_test z 在哪里 (z.emp_code=w.emp_code) 和(z.period_month = w.period_month) 和 (z.company_code = w.company_code) ) ),2,'0' ) 作为 to_month 从 ( 选择 * 从 ( 选择 y.emp_code, y.company_code, y.period_month, (选择 x.company_code 从 t_test x 在哪里 (x.emp_code = y.emp_code) 和(x.period_month previous_company_code) 或(previous_company_code 为空) ) w

    【讨论】:

    • 不要使用IFNULL,而是考虑使用COALESCE。它在其参数中挑选出第一个非null 值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-27
    • 2014-04-14
    • 1970-01-01
    • 1970-01-01
    • 2010-10-31
    • 2019-02-14
    相关资源
    最近更新 更多