ORACLE 连续数 并以逗号分隔 显示的问题

今天有guys在论坛里提出了连续数并分段显示成一行的问题,趁有时间留个记录以便日后查找,嘿嘿

 

Question:

 

如何对多条字符串记录进行"汇总"运算?
我有多条记录,要对其分类汇总.如下表,想通过形如 SELECT cardtype,sum(numbers) AS 数量, str_sum(CARDID) AS 号码范围 FROM card GROUP BY  cardtype.
原表记录:
cardtype numbers cardid
A 3 01001
A 2 01002
A 1 01003
A 2 01007
B 3 05005
B 5 05006
统计后形成:
cardtype 数量 号码范围
A 8 01001-01003,01007
B 8 05005-05006

现在这个str_sum()函数,就是我想象出来的功能,不能哪位大侠可以帮我写出解答?
当然,如果能够求出 01001,01002,01003,01007这样的结果也算是帮了大忙了,我再想办法变成01001-01003,01007的形式.
(注:我是想用vs2008c#+sqlserver2005写一个简单的项目,如果能用oracle写的SQL也行)

 

本人用SQL和FUNCTION两种方式实现:

 

1> SQL:

SQL> SELECT * FROM SCOTT.CARD;

CARDTYPE      NUMBERS CARDID
---------- ---------- ----------
A                   3 01001
A                   2 01002
A                   1 01003
A                   2 01007
B                   3 05005
B                   5 05006

6 rows selected

如果不支持WMSYS.WM_CONCAT函数(10g里才有),用下面的方法:
SQL> SELECT DISTINCT CARDTYPE,
  2                  COUNTS,
  3                  LTRIM(FIRST_VALUE(SYS_CONNECT_BY_PATH(SEGMENTS, ','))
  4                        OVER(PARTITION BY CARDTYPE ORDER BY LEVEL DESC),
  5                        ',') "STR_SUM"
  6    FROM (SELECT CARDTYPE,
  7                 COUNTS,
  8                 SEGMENTS,
  9                 CARDTYPE || ROW_NUMBER() OVER(PARTITION BY CARDTYPE ORDER BY SEGMENTS) "FRONTS",
 10                 CARDTYPE ||
 11                 (ROW_NUMBER()
 12                  OVER(PARTITION BY CARDTYPE ORDER BY SEGMENTS) + 1) "BEHINDS"
 13            FROM (SELECT CARDTYPE,
 14                         COUNTS,
 15                         DECODE(MIN(CARDID),
 16                                MAX(CARDID),
 17                                MIN(CARDID),
 18                                MIN(CARDID) || '-' || MAX(CARDID)) "SEGMENTS"
 19                    FROM (SELECT CARDTYPE,
 20                                 CARDID,
 21                                 SUM(NUMBERS) OVER(PARTITION BY CARDTYPE) "COUNTS",
 22                                 TO_NUMBER(CARDID) -
 23                                 (ROW_NUMBER()
 24                                  OVER(PARTITION BY CARDTYPE ORDER BY CARDID)) DIF
 25                            FROM SCOTT.CARD)
 26                   GROUP BY CARDTYPE, COUNTS, DIF) T2) T3
 27  CONNECT BY PRIOR BEHINDS = FRONTS;

CARDTYPE       COUNTS STR_SUM
---------- ---------- --------------------------------------------------------------------------------
A                   8 01001-01003,01007
B                   8 05005-05006

如果支持WMSYS.WM_CONCAT函数,用下面的方法:
SQL> SELECT CARDTYPE, COUNTS, WMSYS.WM_CONCAT(SEGMENTS) "STR_SUM"
  2    FROM (SELECT CARDTYPE,
  3                 COUNTS,
  4                 DECODE(MIN(CARDID),
  5                        MAX(CARDID),
  6                        MIN(CARDID),
  7                        MIN(CARDID) || '-' || MAX(CARDID)) "SEGMENTS"
  8            FROM (SELECT CARDTYPE,
  9                         CARDID,
 10                         SUM(NUMBERS) OVER(PARTITION BY CARDTYPE) "COUNTS",
 11                         TO_NUMBER(CARDID) -
 12                         (ROW_NUMBER()
 13                          OVER(PARTITION BY CARDTYPE ORDER BY CARDID)) DIF
 14                    FROM SCOTT.CARD)
 15           GROUP BY CARDTYPE, COUNTS, DIF) T1
 16   GROUP BY CARDTYPE, COUNTS;

CARDTYPE       COUNTS STR_SUM
---------- ---------- --------------------------------------------------------------------------------
A                   8 01001-01003,01007
B                   8 05005-05006

SQL>

 

2> FUNCTION:

 

/*
     Author: mantisXF
     Date: Sep 7, 2008
    
     GROUPID      -- Your group data vlaue   E.G: 'A' OR COLUMN_NAME: CARDTYPE
     GROUPNAME    -- Your group column name
     COLUMN_NAME  -- Your column name which you need to return
     SCHEMA_NAME  -- Your schema name of table
     TABLE_NAME   -- Your table name

*/

CREATE OR REPLACE FUNCTION SCOTT.GET_CONTINUUM_NUMBERS(GROUPID IN VARCHAR2,
                                                 GROUPNAME IN VARCHAR2,
                                                 COLUMN_NAME IN VARCHAR2,
                                                 SCHEMA_NAME IN VARCHAR2,
                                                 TABLE_NAME IN VARCHAR2) RETURN VARCHAR2 IS
  -- DECLARE VARIABLE
  CUR_NUMBERS SYS_REFCURSOR;
  V_CON_NUMBERS VARCHAR2(1000) := '';
  V_MIN_NUMBERS VARCHAR2(30) := '';
  V_MAX_NUMBERS VARCHAR2(30) := '';
  V_TEMP_NUMBERS VARCHAR2(30) := '';
  V_SQL VARCHAR2(100);

  V_STEP VARCHAR2(100) := '';
 
BEGIN
  V_STEP := 'GET THE CURSOR BY PARTICULARLY GROUP_ID';
  V_SQL := 'SELECT '||COLUMN_NAME||' FROM '||SCHEMA_NAME||'.'||TABLE_NAME||' WHERE '||GROUPNAME||' = :X ORDER BY '||COLUMN_NAME||' ';
  DBMS_OUTPUT.PUT_LINE('V_SQL: '||V_SQL);
  OPEN CUR_NUMBERS FOR V_SQL USING GROUPID;
 
  V_STEP := 'LOOP THE RESULT';
  LOOP
  FETCH CUR_NUMBERS INTO V_TEMP_NUMBERS;
 
    V_STEP := 'DECIDE WHETHER V_TEMP_NUMBERS HAVING VALUE';
    IF LENGTH(V_TEMP_NUMBERS) > 0 THEN
      V_STEP := 'DECIDE WHETHER V_MIN_NUMBE HAVING VALUE';
      IF V_MAX_NUMBERS IS NOT NULL THEN
        V_STEP := 'DECIDE WHETHER IT HAVING CONTINUUM_NUMBERS VALUE';
        IF TO_NUMBER(V_TEMP_NUMBERS) - NVL(TO_NUMBER(V_MAX_NUMBERS),0) = 1 THEN
          V_MAX_NUMBERS := V_TEMP_NUMBERS;
        ELSE
          V_STEP := 'DECIDE WHETHER V_MIN_NUMBE = V_MAX_NUMB. IT MEANS JUST HAVING 1 VALUE';
          IF V_MIN_NUMBERS = V_MAX_NUMBERS THEN
            V_CON_NUMBERS := V_CON_NUMBERS||','||V_MIN_NUMBERS;
          ELSE
            V_CON_NUMBERS := V_CON_NUMBERS||','||V_MIN_NUMBERS||'-'||V_MAX_NUMBERS;
            V_MIN_NUMBERS := V_TEMP_NUMBERS;
            V_MAX_NUMBERS := V_TEMP_NUMBERS;
          END IF;
        END IF;
      ELSE
        V_MIN_NUMBERS := V_TEMP_NUMBERS;
        V_MAX_NUMBERS := V_TEMP_NUMBERS;
      END IF;
    ELSE
      V_CON_NUMBERS := V_CON_NUMBERS||V_TEMP_NUMBERS;
    END IF;
 
    EXIT WHEN CUR_NUMBERS%NOTFOUND;

  END LOOP;
 
  V_STEP := 'CLOSE CURSOR CUR_NUMBERS';
  IF CUR_NUMBERS%ISOPEN THEN
    CLOSE CUR_NUMBERS;
  END IF;
 
  V_STEP := 'RETURN V_CON_NUMBERS';
  RETURN(LTRIM(V_CON_NUMBERS,','));

EXCEPTION
   WHEN OTHERS THEN
   DBMS_OUTPUT.PUT_LINE('Error at: '||V_STEP);
   DBMS_OUTPUT.PUT_LINE(SQLCODE||' : '||SQLERRM);
 
END GET_CONTINUUM_NUMBERS;

-- 实现方式:

SQL> SELECT CARDTYPE,
  2         SUM(NUMBERS),
  3         SCOTT.GET_CONTINUUM_NUMBERS(CARDTYPE,'CARDTYPE','CARDID','SCOTT','CARD') "STR_SUM"
  4    FROM SCOTT.CARD
  5   GROUP BY CARDTYPE;

CARDTYPE   SUM(NUMBERS) STR_SUM
---------- ------------ --------------------------------------------------------------------------------
A                     8 01001-01003,01007
B                     8 05005-05006

SQL>

 

函数的方法试着去适合所有表和相关列情况,如果有什么不对的地方欢迎指出。

 

Good luck~~

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值