转自 :http://www.ll19.com/log/2010/06/04/115.html
一个工作中遇到的ORACLE合并行,对合并结果排序的记录。本来简单的认为使用wmsys.wm_concat函数就行,结果出了一些小问题,解决起来还是挺折腾的,认真记录一下:
表eims_gwjk_dbcb_log部分记录如下:
SELECT * FROM eims_gwjk_dbcb_log t
注意选中的几行。现在想以WFID为准进行合并行的操作,一开始使用的是wmsys.wm_concat函数来进行合并行的操作。
SELECT t.wfid,
wmsys.wm_concat(dbcb) AS dbcb ,
wmsys.wm_concat(tacheid) AS tacheid,
wmsys.wm_concat(tacheno) AS tacheno,
wmsys.wm_concat(senduserid) AS senduserid
FROM eims_gwjk_dbcb_log t GROUP BY t.wfid;
下面是合并后的结果:
注意选中的行,和前面选中的四行对比。我的想法是合并行之后,合并行的字段都应该按照顺序排序。
之前选中的行:
wfid |
dbcb |
tacheid |
tacheno |
senduserid |
85652 |
CB |
0000003075 |
3 |
U75CB3 |
85652 |
CB |
0000003076 |
2 |
U76CB2 |
85652 |
DB |
0000003076 |
2 |
U76DB2 |
85652 |
DB |
0000003075 |
3 |
U75DB3 |
合并之后:
wfid |
dbcb |
tacheid |
tacheno |
senduserid |
85652 |
DB,DB,CB,CB |
0000003076,0000003076,0000003075,0000003075 |
2,3,3,2 |
U76DB2,U75CB3,U75DB3,U76CB2 |
通过senduserid字段可以看出来(其实这个字段的值是我更改了用来检测合并之后字段顺序用的,对应了前面几个字段的值),几个合并行的字段顺序完全乱了,并没有按照预想的结果排列。
即使排序后合并:
SELECT t.wfid,
wmsys.wm_concat(dbcb) AS dbcb ,
wmsys.wm_concat(tacheid) AS tacheid,
wmsys.wm_concat(tacheno) AS tacheno,
wmsys.wm_concat(senduserid) AS senduserid
FROM (SELECT * FROM eims_gwjk_dbcb_log ORDER BY wfid,dbcb,tacheid,tacheno,senduserid) t GROUP BY t.wfid;
顺序也不对。还是说我不会用wmsys.wm_concat这个函数如何排序合并字段,反正搜了很多都没有解决方法。
没办法用的另一种合并行的方法,首先看这个语句:
SELECT wfid,dbcb,tacheid,tacheno,senduserid,
--按照wfid分组 每组的senduserid进行排序
(row_number() over(partition BY wfid ORDER BY senduserid)) rn
FROM eims_gwjk_dbcb_log
同注释,按照wfid分组,每组的senduserid进行排序别名RN。之后根据WFID和RN用sys_connect_by_path函数对数据进行合并:
SELECT wfid,(substr(sys_connect_by_path(dbcb,','),2)) AS dbcb,
(substr(sys_connect_by_path(tacheid,','),2)) AS tacheid,
(substr(sys_connect_by_path(tacheno,','),2)) AS tacheno,
(substr(sys_connect_by_path(senduserid,','),2)) AS senduserid,
level AS curr_level
FROM(
SELECT wfid,dbcb,tacheid,tacheno,senduserid,
--按照wfid分组 每组的senduserid进行排序
(row_number() over(partition BY wfid ORDER BY senduserid)) rn
FROM eims_gwjk_dbcb_log
)
connect BY wfid = prior wfid AND rn-1 = prior rn;
数据的合并类似于递归合并,我们只需要curr_level最高的那行,即合并了所有相关数据的那行,之后的语句:
SELECT * FROM (
--我们只需要curr_level最高的那行,即是已经完全合并好数据的那行,之后排序取得curr_level最高的行
SELECT wfid,dbcb,tacheid,tacheno,senduserid,
row_number() over(partition BY wfid ORDER BY wfid,curr_level DESC) c_level
FROM (
--根据WFID和RN用sys_connect_by_path函数对数据进行合并
SELECT wfid,(substr(sys_connect_by_path(dbcb,','),2)) AS dbcb,
(substr(sys_connect_by_path(tacheid,','),2)) AS tacheid,
(substr(sys_connect_by_path(tacheno,','),2)) AS tacheno,
(substr(sys_connect_by_path(senduserid,','),2)) AS senduserid,
level AS curr_level
FROM(
SELECT wfid,dbcb,tacheid,tacheno,senduserid,
--按照wfid分组 每组的senduserid进行排序
(row_number() over(partition BY wfid ORDER BY senduserid)) rn
FROM eims_gwjk_dbcb_log
)
connect BY wfid = prior wfid AND rn-1 = prior rn
))
WHERE c_level = 1
对比数据排序正常! = =
本来个人认为很EASY的一个事情最后确搞得如此复杂,或者说其实还是有对wmsys.wm_concat的合并排序方法?起码我搜索半天也没找到,最后用的这个方法我感觉还是,以后数据多了性能上的问题(但MS sys_connect_by_path 函数性能其实不错?)。
顺带对使用的函数进行一个总结:
-
Start with...Connect By
Start with...Connect By子句递归查询一般用于一个表维护树形结构的应用。(即递归查询)
一个使用实例,创建示例表:
CREATE TABLE TBL_TEST
(ID NUMBER,
NAME VARCHAR2(100 BYTE),
PID NUMBER DEFAULT 0);
插入测试数据:
INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('1','10','0');
INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('2','11','1');
INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('3','20','0');
INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('4','12','1');
INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('5','121','2');
从Root往树末梢递归 (取全部“子孙”集):
SELECT * FROM TBL_TEST
start WITH id=1
connect BY prior id = pid
ORDER BY pid
从末梢往树ROOT递归(取全部“父爷”集):
SELECT * FROM TBL_TEST
start WITH id=5
connect BY prior pid = id
ORDER BY id
-
Group By聚合语句
Group By聚合语句,必须配合相关的例如sum,max,min等函数使用:
SELECT * FROM eims_gwjk_dbcb_log t
WHERE t.wfid = 85652
计算wfid=85652的tacheno的总和:
SELECT wfid,sum(tacheno) FROM eims_gwjk_dbcb_log
WHERE wfid = 85652
GROUP BY wfid;
-
min max
即取得最大和最小值:
SELECT max(senduserid) FROM eims_gwjk_dbcb_log
--U76DB2
SELECT min(senduserid) FROM eims_gwjk_dbcb_log
--U123
-
三个"评价"函数
这三个分析函数都可以在各个分组内从1开始排序。
ROW_NUMBER()是没有重复值的,可以利用它实现分页显示。
DENSE_RANK() 是连续排序,有两个第二名时仍然跟着第三名。
RANK()是跳跃排序,有两个第二名时接下来就是第四名(同样是在各个分组内)。
实例:
SELECT tacheid,
(ROW_NUMBER() over(ORDER BY tacheid)) rn
FROM eims_gwjk_dbcb_log t
tacheid rn
0000001864 1
0000001864 2
0000001889 3
0000001889 4
0000001911 5
0000001911 6
0000001911 7
0000001911 8
0000001918 9
0000001930 10
0000002896 11
SELECT tacheid,
(DENSE_RANK() over(ORDER BY tacheid)) rn
FROM eims_gwjk_dbcb_log t
tacheid rn
0000001864 1
0000001864 1
0000001889 2
0000001889 2
0000001911 3
0000001911 3
0000001911 3
0000001911 3
0000001918 4
0000001930 5
0000002896 6
SELECT tacheid,
(RANK() over(ORDER BY tacheid)) rn
FROM eims_gwjk_dbcb_log t
tacheid rn
0000001864 1
0000001864 1
0000001889 3
0000001889 3
0000001911 5
0000001911 5
0000001911 5
0000001911 5
0000001918 9
0000001930 10
0000002896 11
更多的使用例如:row_number() over ([partition by col1] order by col2) ) as 别名
表示根据col1分组,在分组内部根据col2排序,而这个“别名”的值就表示每组内部排序后的顺序编号(组内连续的唯一的), [partition by col1] 可省略。
SELECT dbcb,tacheid,
(RANK() over(partition BY dbcb ORDER BY tacheid)) rn
FROM eims_gwjk_dbcb_log t
先按照dbcb分组,后按照tacheid排序(即排序)即每个组内自己排序,而不是整个排序。
-
level
LEVEL查询数据所对应的级,level仅仅用于在对表执行层次树遍历的select语句中,个人理解遍历的层次越多,级别越大。
SELECT wfid,(substr(sys_connect_by_path(dbcb,','),2)) AS dbcb,
(substr(sys_connect_by_path(tacheid,','),2)) AS tacheid,
(substr(sys_connect_by_path(tacheno,','),2)) AS tacheno,
(substr(sys_connect_by_path(senduserid,','),2)) AS senduserid,
level AS curr_level
FROM(
SELECT wfid,dbcb,tacheid,tacheno,senduserid,
(row_number() over(partition BY wfid ORDER BY senduserid)) rn
FROM eims_gwjk_dbcb_log
)
connect BY wfid = prior wfid AND rn-1 = prior rn
-
sys_connect_by_path
sys_connect_by_path函数主要作用是可以把一个父节点下的所有子节点通过某个字符进行区分,然后连接在一个列中显示。这个函数使用之前必须先建立一个树,例如:
SELECT level ,sys_connect_by_path( id , '/' )
FROM test
start WITH pid= 1
connect BY prior pid = id ;
转自:http://www.ll19.com/log/2010/06/04/115.html#
分享到:
相关推荐
在Oracle数据库中,多行记录的合并通常是为了将相同字段的多行数据整合成一行,以便于数据分析或者简化展示。这种操作在报表制作、数据整理等场景中非常常见。本篇文章将详细介绍Oracle中实现多行记录合并的几种方法...
在Oracle数据库中,有时我们需要将多个字段值转换为单个字符串,或者将多行记录合并成一行,这在数据处理和报告生成时尤其常见。Oracle提供了多种方法来实现这一目标,包括使用内置函数、PL/SQL过程以及一些高级特性...
现在的需求是:对于每一个股票代码,将其对应的所有研究人员的名字合并成一个字符串,并用逗号`,`分隔,以便于快速地在页面上显示。 #### 二、解决方案及实现步骤 为了实现上述需求,我们将采用以下步骤: 1. **...
此标题明确指出了解决的问题:在Oracle数据库中,如何将特定字段的多行记录合并成一行记录。这种需求通常出现在报告或数据分析的过程中,当需要将多个相关的值组合在一起进行展示或进一步处理时。 ### 描述理解 ...
在Oracle数据库系统中,经常需要将多个行的数据合并成单行显示,尤其是在处理报告或者需要将多个值组合成一个字符串的情况下。本文将详细介绍如何在Oracle 10g与9i版本中实现这一功能,并分别提供具体的实现方法。 ...
### ORACLE技巧 - 不同记录集的横向合并 #### 概述 在处理数据库操作时,经常需要对比两个记录集的差异,例如比较原先输入的订单数据与之后更新的订单数据之间的不同之处,并将这些差异展示给用户查看。在Oracle...
多行记录合并 采用的是方法4,希望对你们有用
Oracle数据库在处理多行记录合并、连接和聚合字符串时,有多种方法,下面将详细介绍其中的几种常见技术。 1. 被集合字段范围小且固定型 这种方法适用于字段值有限且已知的情况。通过使用`DECODE`函数,我们可以为每...
此外,题目还提到了另一种情况,即针对特定的`callid`、`callerno`、`calleeno`和`devicetype`合并记录。这种情况下,可以采用类似的逻辑来实现: ```sql WITH ranked_data AS ( SELECT callid, callerno, ...
Oracle数据库提供了多种方法来实现这一需求,其中`WMSYS.WM_CONCAT`是一个非常实用且高效的函数,它可以将多个字符串值合并成一个单独的字符串,并在每个值之间插入指定的分隔符。 #### 二、WMSYS.WM_CONCAT函数...
在SQL中,有时候我们需要将查询结果中多行的数据合并成一行,这在处理某些特定的报表或数据分析时非常有用。这种技术通常被称为行合并或行聚合。在本例中,我们将探讨如何使用纯SQL实现这一功能,特别是针对Oracle...
在Oracle数据库中,合并多行记录的字符串是一个常见的需求,特别是在报表或数据分析中。这个问题涉及到字符串的连接和聚合,使得多个记录的某个字段值能够整合到一行。在Oracle中,虽然没有内置的聚合函数直接支持...
在IT行业中,数据转换是一项关键...总之,Kettle作为一个强大的ETL工具,使得Oracle到MySQL的数据转换变得直观且高效。通过理解其工作原理和配置方法,你可以灵活地处理各种数据集成问题,实现数据的无缝迁移和整合。
随着业务发展和技术迭代,企业往往需要对现有的数据库系统进行调整优化,其中包括将数据从一个数据库迁移至另一个数据库、或将来自不同数据库的数据进行整合等场景。这些操作通常涉及到表结构的一致性检查、数据的...
统一审计还支持归档功能,这意味着审计记录可以被归档到一个安全的地方,比如归档到一个专用的归档数据库或者归档到一个文件系统。归档功能是可选的,但在某些法规遵从要求的环境中可能是必要的。 开启归档审计的...
介绍了如何创建一个新的Oracle数据库。 ### Java操作Oracle 这部分讲解了Java应用程序如何连接和操作Oracle数据库。 - **Java连接Oracle**:使用JDBC驱动建立Java与Oracle之间的连接。 - **在Oracle中操作数据**:...
3. **合并记录集**:有多种方法可以合并记录集,例如使用“Append”方法或者创建一个新的记录集来合并数据。下面是一个使用“Append”方法的例子: ```vb ' 创建一个新的记录集来合并两个表 Dim rsCombined As New ...
在Oracle GoldenGate实施过程中,抽取进程的合并与拆分是十分重要的一个环节。抽取进程(Extract process)是GoldenGate中的核心组件之一,负责捕获源数据库的事务日志,并生成用于数据复制的数据提取文件。为了满足...