Move Non-NULL Values Up Within Partition

十年热恋 提交于 2020-01-05 17:19:41

问题


Not sure if the title makes sense but here is my problem and how I got to where I am.

Background: I have 2 tables in a one-to-many setup. The many table can have any number of records that tie back to the one but has an additional column that can identify the many record as anything between a value of 1-7. I "gathered" all the rows for each group 1-7 with 7 CTE's and then joined them together to the one table getting me to the point of my sample data.

If all of the rows in a single column are null then I want to display an *, otherwise display all distinct values within each column per GROUPID/GROUPNAME. I've somewhat hack and slashed my way to getting what I want with one caveat. If possible I would like to order each column individually within the GROUPID/GROUPNAME so that NULLs aren't in the middle of the data.

Here is my code that got me to the point I am stuck at:

WITH SAMPLEDATA (CYCLEID,GROUPID,GROUPNAME,COL1,COL2,COL3,COL4,COL5,COL6,COL7)
AS (
SELECT 1,7669,'000000261','GAS',NULL,NULL,NULL,'1',NULL,'00' FROM DUAL
UNION ALL
SELECT 2,7669,'000000261','GAS',NULL,NULL,NULL,'1',NULL,'000000261' FROM DUAL
UNION ALL
SELECT 3,7669,'000000261','GAS',NULL,NULL,NULL,'Chester',NULL,'00' FROM DUAL
UNION ALL
SELECT 4,7669,'000000261','GAS',NULL,NULL,NULL,'Chester',NULL,'000000261' FROM DUAL
UNION ALL
SELECT 5,7669,'000000261','GFG',NULL,NULL,NULL,'1',NULL,'00' FROM DUAL
UNION ALL
SELECT 6,7669,'000000261','GFG',NULL,NULL,NULL,'1',NULL,'000000261' FROM DUAL
UNION ALL
SELECT 7,7669,'000000261','GFG',NULL,NULL,NULL,'Chester',NULL,'00' FROM DUAL
UNION ALL
SELECT 8,7669,'000000261','GFG',NULL,NULL,NULL,'Chester',NULL,'000000261' FROM DUAL
UNION ALL
SELECT 9,7669,'000000261','GKE',NULL,NULL,NULL,'1',NULL,'00' FROM DUAL
UNION ALL
SELECT 10,7669,'000000261','GKE',NULL,NULL,NULL,'1',NULL,'000000261' FROM DUAL
UNION ALL
SELECT 11,7669,'000000261','GKE',NULL,NULL,NULL,'Chester',NULL,'00' FROM DUAL
UNION ALL
SELECT 12,7669,'000000261','GKE',NULL,NULL,NULL,'Chester',NULL,'000000261' FROM DUAL
 ) 
 , GROUPSPROCESSED AS (
SELECT
  GROUPID,
  GROUPNAME,
  CASE
    WHEN cycleid = 1
    THEN NVL(COL1,'*')
    WHEN COL1 = FIRST_VALUE(COL1) OVER (PARTITION BY GROUPNAME ORDER BY GROUPNAME, COL1)
    THEN NULL
    WHEN COL1 = LAG(COL1) OVER (PARTITION BY GROUPNAME ORDER BY GROUPNAME, COL1)
    THEN NULL
    ELSE COL1
  END AS "COL1",
  CASE
    WHEN cycleid = 1
    THEN NVL(COL2,'*')
    WHEN COL2 = FIRST_VALUE(COL2) OVER (PARTITION BY GROUPNAME ORDER BY GROUPNAME, COL2)
    THEN NULL
    WHEN COL2 = LAG(COL2) OVER (PARTITION BY GROUPNAME ORDER BY GROUPNAME, COL2)
    THEN NULL
    ELSE COL2
  END AS "COL2",
  CASE
    WHEN cycleid = 1
    THEN NVL(COL3,'*')
    WHEN COL3 = FIRST_VALUE(COL3) OVER (PARTITION BY GROUPNAME ORDER BY GROUPNAME, COL3)
    THEN NULL
    WHEN COL3 = LAG(COL3) OVER (PARTITION BY GROUPNAME ORDER BY GROUPNAME, COL3)
    THEN NULL
    ELSE COL3
  END AS "COL3",
  CASE
    WHEN cycleid = 1
    THEN NVL(COL4,'*')
    WHEN COL4 = FIRST_VALUE(COL4) OVER (PARTITION BY GROUPNAME ORDER BY GROUPNAME, COL4)
    THEN NULL
    WHEN COL4 = LAG(COL4) OVER (PARTITION BY GROUPNAME ORDER BY GROUPNAME, COL4)
    THEN NULL
    ELSE COL4
  END AS "COL4",
  CASE
    WHEN cycleid = 1
    THEN NVL(COL5,'*')
    WHEN COL5 = FIRST_VALUE(COL5) OVER (PARTITION BY GROUPNAME ORDER BY GROUPNAME, COL5)
    THEN NULL
    WHEN COL5 = LAG(COL5) OVER (PARTITION BY GROUPNAME ORDER BY GROUPNAME, COL5)
    THEN NULL
    ELSE COL5
  END AS "COL5",
  CASE
    WHEN cycleid = 1
    THEN NVL(COL6,'*')
    WHEN COL6 = FIRST_VALUE(COL6) OVER (PARTITION BY GROUPNAME ORDER BY GROUPNAME, COL6)
    THEN NULL
    WHEN COL6 = LAG(COL6) OVER (PARTITION BY GROUPNAME ORDER BY GROUPNAME, COL6)
    THEN NULL
    ELSE COL6
  END AS "COL6",
  CASE
    WHEN cycleid = 1
    THEN NVL(COL7,'*')
    WHEN COL7 = FIRST_VALUE(COL7) OVER (PARTITION BY GROUPNAME ORDER BY GROUPNAME, COL7)
    THEN NULL
    WHEN COL7 = LAG(COL7) OVER (PARTITION BY GROUPNAME ORDER BY GROUPNAME, COL7)
    THEN NULL
    ELSE COL7
  END AS "COL7"
FROM SAMPLEDATA)
SELECT * FROM GROUPSPROCESSED
WHERE COALESCE (COL1,COL2,COL3,COL4,COL5,COL6,COL7) IS NOT NULL
ORDER BY 1,2,3,4,5,6,7,8,9

Current output:

Desired output:

EDIT Here is code to import the exact raw data from my example before any manipulation. It's technically 3 tables that I need to tie together to derrive the output above.

The GROUPPROFILE holds the ID and NAME from fields 1-2 in my output above.

The COLVALUES holds the data (NAME) for the remainder of the fields in the output based on the COLLEVELID being 1-7

The GROUPCOLMM table is just used to connect GROUPPROFILE.GROUPPROFILEID > COLVALUES.COLVALUEID

CREATE TABLE GROUPPROFILE (GROUPPROFILEID NUMBER(12), SHORTNM NVARCHAR2(30))
REM INSERTING into GROUPPROFILE
Insert into GROUPPROFILE (GROUPPROFILEID,SHORTNM) values (7669,'000000261');

CREATE TABLE COLVALUES (COLVALUEID NUMBER(12), NAME NVARCHAR2(50), COLLEVELID NUMBER(12))
REM INSERTING into COLVALUES
Insert into COLVALUES (COLVALUEID,NAME,COLLEVELID) values (18901,'GFG',1);
Insert into COLVALUES (COLVALUEID,NAME,COLLEVELID) values (106,'GKE',1);
Insert into COLVALUES (COLVALUEID,NAME,COLLEVELID) values (1351,'GAS',1);
Insert into COLVALUES (COLVALUEID,NAME,COLLEVELID) values (423,'0',4);
Insert into COLVALUES (COLVALUEID,NAME,COLLEVELID) values (1,'1',5);
Insert into COLVALUES (COLVALUEID,NAME,COLLEVELID) values (18514,'Chester',5);

CREATE TABLE GROUPCOLMM (GROUPPROFILEID NUMBER(12), COLVALUEID NUMBER(12))
REM INSERTING into GROUPCOLMM
Insert into GROUPCOLMM (GROUPPROFILEID,COLVALUEID) values (7669,1);
Insert into GROUPCOLMM (GROUPPROFILEID,COLVALUEID) values (7669,3);
Insert into GROUPCOLMM (GROUPPROFILEID,COLVALUEID) values (7669,106);
Insert into GROUPCOLMM (GROUPPROFILEID,COLVALUEID) values (7669,1351);
Insert into GROUPCOLMM (GROUPPROFILEID,COLVALUEID) values (7669,16503);
Insert into GROUPCOLMM (GROUPPROFILEID,COLVALUEID) values (7669,18514);
Insert into GROUPCOLMM (GROUPPROFILEID,COLVALUEID) values (7669,18901);

回答1:


You can't get your sample data from the "raw" data you posted. I reverse engineered raw data from your sample data in the subquery ORIGINALDATA, then came up with this solution:

WITH SAMPLEDATA (CYCLEID,GROUPID,GROUPNAME,COL1,COL2,COL3,COL4,COL5,COL6,COL7)
AS (
SELECT 1,7669,'000000261','GAS',NULL,NULL,NULL,'1',NULL,'00' FROM DUAL
UNION ALL
SELECT 2,7669,'000000261','GAS',NULL,NULL,NULL,'1',NULL,'000000261' FROM DUAL
UNION ALL
SELECT 3,7669,'000000261','GAS',NULL,NULL,NULL,'Chester',NULL,'00' FROM DUAL
UNION ALL
SELECT 4,7669,'000000261','GAS',NULL,NULL,NULL,'Chester',NULL,'000000261' FROM DUAL
UNION ALL
SELECT 5,7669,'000000261','GFG',NULL,NULL,NULL,'1',NULL,'00' FROM DUAL
UNION ALL
SELECT 6,7669,'000000261','GFG',NULL,NULL,NULL,'1',NULL,'000000261' FROM DUAL
UNION ALL
SELECT 7,7669,'000000261','GFG',NULL,NULL,NULL,'Chester',NULL,'00' FROM DUAL
UNION ALL
SELECT 8,7669,'000000261','GFG',NULL,NULL,NULL,'Chester',NULL,'000000261' FROM DUAL
UNION ALL
SELECT 9,7669,'000000261','GKE',NULL,NULL,NULL,'1',NULL,'00' FROM DUAL
UNION ALL
SELECT 10,7669,'000000261','GKE',NULL,NULL,NULL,'1',NULL,'000000261' FROM DUAL
UNION ALL
SELECT 11,7669,'000000261','GKE',NULL,NULL,NULL,'Chester',NULL,'00' FROM DUAL
UNION ALL
SELECT 12,7669,'000000261','GKE',NULL,NULL,NULL,'Chester',NULL,'000000261' FROM DUAL
 ) 
, originaldata as (
  select distinct groupid, groupname, col, val from sampledata
  unpivot (val for col in (COL1 as 1,COL2 as 2,COL3 as 3,COL4 as 4,COL5 as 5,COL6 as 6,COL7 as 7))
)
select GROUPID, GROUPNAME, 
  case when rn = 1 and col1 is null then '*' else col1 end col1,
  case when rn = 1 and col2 is null then '*' else col2 end col2,
  case when rn = 1 and col3 is null then '*' else col3 end col3,
  case when rn = 1 and col4 is null then '*' else col4 end col4,
  case when rn = 1 and col5 is null then '*' else col5 end col5,
  case when rn = 1 and col6 is null then '*' else col6 end col6,
  case when rn = 1 and col7 is null then '*' else col7 end col7
from (
  select o.*,
  row_number() over(partition by groupid, groupname, col order by val) rn
  from originaldata o
)
pivot(
  max(val) 
  for col in (1 as COL1,2 as COL2,3 as COL3,4 as COL4,5 as COL5,6 as COL6,7 as COL7)
)
order by groupid, groupname, rn;

   GROUPID GROUPNAME COL1      COL2      COL3      COL4      COL5      COL6      COL7     
---------- --------- --------- --------- --------- --------- --------- --------- ---------
      7669 000000261 GAS       *         *         *         1         *         00       
      7669 000000261 GFG                                     Chester             000000261
      7669 000000261 GKE                                   

Best regards, Stew Ashton



来源:https://stackoverflow.com/questions/57515150/move-non-null-values-up-within-partition

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!