oracle通过一条SQL实现列转行

思路,如果欲将多记录中的某列值合并到一列中,必须使用oracle的树递归方式,即start with id = ? connect by prior id = pid 的方式,并使用SYS_CONNECT_BY_PATH语法。因此第一步需要做的是实现目标表的父子关系,在无需分组合并的情况下,使用伪列ROWNUM生成唯一序号即可;如果需要分组合并较为复杂,因为ROWNUM是唯一顺序号导致无法分组,考虑分析函数ROW_NUMBER()却因为每组中均会出现1,2,3,……,n等数据,导致建立的父子关系重复,此时可采用分析函数lag()来实现父子关系。具体范例见下。

为了方便说明,采用sys用户下的user_tab_cols系统表做为说明范例。在非分组情况下对某一给定的table_name,将column_name合成一个字段并使用“|”作为column_name间的分隔符;在分组情况下按table_name作为分组条件,将每个table_name下的column_name合并到一个字段中,同样使用“|”作为column_name间的分隔符

一、非分组情况下

--非分组
WITH a AS (
SELECT TT.*, SYS_CONNECT_BY_PATH(TT.COLUMN_NAME, '|') path
  FROM (SELECT ROWNUM ID, ROWNUM - 1 PID, T.COLUMN_NAME
		  FROM USER_TAB_COLS T
		 WHERE T.TABLE_NAME = UPPER('all_objects')) TT
 START WITH ID = 1
CONNECT BY PRIOR ID = PID)
SELECT SUBSTR(PATH, 2)
  FROM (SELECT ROWNUM RN, AA.*
		  FROM (SELECT A.* FROM A ORDER BY LENGTH(A.PATH) DESC) AA)
 WHERE RN = 1;


二、分组情况下

--分组
WITH a AS  
(SELECT T.COLUMN_NAME F1,
	   T.TABLE_NAME || T.COLUMN_NAME ID,
	   T.TABLE_NAME PID,
	   LAG(T.TABLE_NAME || T.COLUMN_NAME, 1, NULL) OVER(PARTITION BY T.TABLE_NAME ORDER BY T.TABLE_NAME) PPID
  FROM USER_TAB_COLS T)  
SELECT PID TABLE_NAME, SUBSTR(PATH, 2)
  FROM (SELECT TTT.*,
			   ROW_NUMBER() OVER(PARTITION BY PID ORDER BY LENGTH(PATH) DESC) RN
		  FROM (SELECT A.*, SYS_CONNECT_BY_PATH(A.F1, '|') PATH
				  FROM A
				 START WITH PPID IS NULL
				CONNECT BY PRIOR ID = PPID) TTT)
 WHERE RN = 1;


---END
 

发布了29 篇原创文章 · 获赞 0 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/levin_li/article/details/7414565
今日推荐