将具有NULL的多行“合并”到具有不同总和的行中

时间:2016-10-16 10:29:00

标签: sql

想象一下下表

*** Process received signal ***
Signal: Segmentation fault (11)
Signal code: Address not mapped (1)
Failing at address: 0x14ae7b8
[ 0] /lib/x86_64-linux-gnu/libpthread.so.0(+0x113d0)[0x7fe1ad91c3d0]
[ 1] /lib/x86_64-linux-gnu/libc.so.6(cfree+0x22)[0x7fe1ad5c5a92]
[ 2] ./out[0x400de4]
[ 3] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7fe1ad562830]
[ 4] ./out[0x400ec9]
*** End of error message ***

试图避免供应商特定的功能,使用SQL将其“合并”的最佳方式是什么,如下所示

| EEID | CODE1 | VALUE1 | CODE2 | VALUE2 |
|------|-------|--------|-------|--------|
| 001  | ABC   | 10     | NULL  | 0      |
| 001  | ABC   | 5      | NULL  | 0      |
| 001  | DEF   | 2      | NULL  | 0      |
| 001  | NULL  | 0      | 123   | 3      |
| 001  | NULL  | 0      | 123   | 6      |
| 001  | NULL  | 0      | 456   | 4      |
| 001  | NULL  | 0      | 789   | 1      |

基本上我需要能够对CODEx列中的不同值求和。

2 个答案:

答案 0 :(得分:1)

一种方法是

SELECT COALESCE(T1.EEID, T2.EEID) AS EEID,
       CODE1,
       VALUE1,
       CODE2,
       VALUE2
FROM   (SELECT EEID,
               CODE1,
               SUM(VALUE1)                        AS VALUE1,
               ROW_NUMBER() OVER (ORDER BY CODE1) AS RN
        FROM   YourTable
        WHERE  CODE1 IS NOT NULL
        GROUP  BY EEID,
                  CODE1) T1
       FULL JOIN (SELECT EEID,
                         CODE2,
                         SUM(VALUE2)                        AS VALUE2,
                         ROW_NUMBER() OVER (ORDER BY CODE2) AS RN
                  FROM   YourTable
                  WHERE  CODE2 IS NOT NULL
                  GROUP  BY EEID,
                            CODE2) T2
         ON  ON T1.RN = T2.RN AND T1.EEID = T2.EEID;

它没有使用任何特定于供应商的功能,尽管MySQL还没有实现窗口功能(或完全加入)。

或者另一种方式。

SELECT EEID,
       MAX(CODE1)  AS CODE1,
       SUM(VALUE1) AS VALUE1,
       MAX(CODE2)  AS CODE2,
       SUM(VALUE2) AS VALUE2
FROM   (SELECT EEID,
               CODE1,
               VALUE1,
               CODE2,
               VALUE2,
               DENSE_RANK() OVER (PARTITION BY EEID ORDER BY CASE WHEN CODE1 IS NULL THEN 1 ELSE 0 END, Code1) AS RN1,
               DENSE_RANK() OVER (PARTITION BY EEID ORDER BY CASE WHEN CODE2 IS NULL THEN 1 ELSE 0 END, Code2) AS RN2
        FROM   YourTable) T
GROUP  BY EEID,
          CASE
            WHEN CODE1 IS NULL
              THEN RN2
            ELSE RN1
          END
HAVING COALESCE(MAX(CODE1), MAX(CODE2)) IS NOT NULL; 

答案 1 :(得分:0)

如果你想对不同列中的值求和,我建议使用不同的输出结构:

group by

这会将值放在不同的行中,但它可以解决您的问题。

可以使用row_number()select eeid, max(code1) as code1, max(value1) as value1, max(code2) as code2, max(value2) as value2 from ((select eeid, code1, sum(value1) as value1, NULL as code2, NULL as value2, row_number() over (partitionby eeid order by code1) as seqnum from t where code1 is not null group by eeid, code1 ) union all (select eeid, NULL, NULL, code2, sum(value2) row_number() over (partition by eeid order by code2) as seqnum from t where code2 is not null group by eeid, code2 ) ) t12 group by eeid, seqnum;

将其扩展为数据透视表
public class SpringHelloWorldTest {
    public static void main(String[] args) {
           ApplicationContext context= new ClassPathXmlApplicationContext("spring.xml");
           Triangle triangle =(Triangle) factory.getBean("triangle");
           triangle.draw();
}