Quantcast
Channel: SCN : Blog List - SAP HANA Developer Center
Viewing all articles
Browse latest Browse all 676

'Connect by' like functionality using User Defined Table Functions

$
0
0

Problem statement

 

Data looks like this

 

aField

bField

1
21
31
42
52
62
73
83
93


the output needs to look like this (displaying only aField values) :

 

Level 1Level 2Level 3
124
-35
--6
--7
--8
--9

Solution Explained

 

The solution has two parts
  1. Tag each row with the 'level' it is on - we will use a User Defined Table function for this
  2. Use the level to 'pivot' the table on its side - We will use SQL Query with table views

 

Part 1: Tagging each row with level
  1. Identify the rows whose 'aField' value never occurs in 'bField' (for e.g. values 4 to 9 never occur in bField)
  2. Row identified in step 1 are tagged with a  level (for e.g. 1)
  3. Once tagged, remove the rows from the reckoning (for e.g. remove rows where aField value between 4 to 9, leaving rows with values 1..3 in aField)
  4. loop over steps 1 to 3 until bField has only null values remaining. (for e.g. row 1)
  5. Union all tagged rows and return

 

Output

AFIELDBFIELDLEVEL
1?3
212
312
421
521
621
731
831
931

 

Part 2: Use the level to 'pivot' the table on its side
  1. We generate on (ad hoc) view per level column in the output filtered on level
  2. Each view also uses a window function to generate rownumber
  3. Using row numbers  write an outer join to generate the output

 

Output:

LEVEL1LEVEL2LEVEL3
124
?35
??6
??7
??8
??9

 

The code:

 

FUNCTION "************"."***********.rootpkg.procs.dml::connectby" ( )  RETURNS TABLE(aField tinyint,bfield tinyint, level tinyint)  LANGUAGE SQLSCRIPT  SQL SECURITY INVOKER AS
BEGIN  DECLARE Rank tinyint :=0;  DECLARE level tinyint :=1;  DECLARE I Tinyint;
-- get the data to process  bothFields = select aField,bField from  "DEV_1X28Q7TC9RQSNZH49YABNQ4JZ"."FLATSTRUCT";
--create the output stucture  outputTable = select aField,bField, :level as level from :bothFields where 1=2;  -- check if we need to an iteration  select count(*)  into Rank  from (select distinct bField from :bothFields where bField is not null)  where bField is not null;  --get distinct superior field and count of valid values  while :Rank > 0 Do  -- Get the lowest level - not in superior field and tag with level id  lowestlevel = Select aField, :level as level  from(select aField from :bothFields    EXCEPT    select distinct bField from :bothFields);  -- get rows that were not in the lowest level  newAField = select aField from :bothFields  EXCEPT  select aField from :lowestlevel;  --add tagged levels to output  tempOut=CE_JOIN(:lowestlevel,:bothFields,["AFIELD"],["AFIELD","BFIELD","LEVEL"]);  outputTable = Select aField, bField,  :level as level from :tempOut    UNION ALL    Select aField, bField, level from :outputTable;  --remove the rows tagged with level id from data set  bothFields = CE_JOIN(:newAField,:bothFields,["AFIELD"],["AFIELD","BFIELD"]);  --reset level id  level := :level+1;  -- check if we need to do another iteration  select count(*)  into Rank  from (select distinct bField from :bothFields where bField is not null)  where bField is not null;  END WHILE;  --attaching the top most level  outputTable = Select aField, bField, :level as level from :bothFields WHERE bField is null    UNION ALL    Select aField, bField, level from :outputTable;  return select * from :outputTable;
END;

The SQL Query

select three.afield  as level1, two.AFIELD as level2, one.AFIELD as level3
from
(select afield, ROW_NUMBER() over (order by afield) as rnum from "DEV_1X28Q7TC9RQSNZH49YABNQ4JZ"."i036632sapdev.rootpkg.procs.dml::connectby"()
Where level =1) one
full outer join
(select afield , ROW_NUMBER() over (order by afield) as rnum from "DEV_1X28Q7TC9RQSNZH49YABNQ4JZ"."i036632sapdev.rootpkg.procs.dml::connectby"()
Where level =2) two
on one.rnum = two.rnum
full outer join
(select afield , ROW_NUMBER() over (order by afield) as rnum from "DEV_1X28Q7TC9RQSNZH49YABNQ4JZ"."i036632sapdev.rootpkg.procs.dml::connectby"()
Where level =3) three
on one.rnum = three.rnum

Similar Solutions:

Please have a look at similar solutions Flattening the hierarchy using SQL code

 

Request:

This is my first blog post, please do leave feedback in the comments


Viewing all articles
Browse latest Browse all 676

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>