简体   繁体   中英

Converting ORACLE hierarchical START WITH / CONNECT BY PRIOR to SQL Server CTE

I am having trouble converting a current ORACLE script across to an equivalent MS SQL Server version equivalent - so as to achieve the same functionality.

All of the research I have done points me to a CTE as the only solution, and I have got that mostly working. The only remaining issue is that the sequence is not correct - by that I therefore mean the 'hierarchy' does not come out correctly. I have tried using ORDER BY to get the result set into line, then tried ROW_NUMBER() etc, but none of these approaches quite work either. I think the main issue is that the script is not parsing up and down the levels in the same way the Oracle script does - and me then trying to 'correct' that after the CTE has completed is digging me into a deeper hole.

Here are the 2 scripts below;

CURRENT ORACLE SQL SCRIPT VERSION (works perfectly)

SELECT lpad('-',2*(level-2), '-') || l.lcname descr, r.lrlocuri1 id, l.lciswithin, l.lctype, 1 lcisactive, l.lcvalidto 
    FROM tslocrel r,  tslocation l WHERE l.uri=r.lrlocuri1
    AND level>1 AND level<6
    AND lctype=1 AND lcvalidto<'2' 
START WITH lrlocuri1=4485 CONNECT BY PRIOR lrlocuri1 = lrlocuri2 

MY MS SQL SERVER VERSION WIP ATTEMPT (SQL 2012 IS THE TARGET VERSION)

WITH locationCTE (lcname, lrlocuri1, lciswithin, lctype, lcisactive, lcvalidto, level) AS (

  SELECT l.lcname, r.lrlocuri1, l.lciswithin, l.lctype, 1 AS lcisactive, l.lcvalidto, 1 AS level
  FROM tslocrel r
  INNER JOIN tslocation l ON r.lrlocuri1 = l.uri
  AND r.lrlocuri1=4485

  UNION ALL

  SELECT l.lcname, r.lrlocuri1, l.lciswithin, l.lctype, 1 AS lcisactive, l.lcvalidto, cte.level + 1 AS level
  FROM tslocrel r
  INNER JOIN tslocation l ON r.lrlocuri1 = l.uri
  INNER JOIN locationCTE cte ON cte.lrlocuri1 = r.lrlocuri2

)

SELECT RIGHT(REPLICATE('-', 2*(level-2)) + LEFT('-', 2*(level-2)), 2*(level-2)) + lcname AS descr, lrlocuri1 id, lciswithin, lctype, lcisactive, 
lcvalidto
FROM locationCTE
WHERE level>1 AND level<6
AND lctype=1 AND lcvalidto<'2'

I have tried a few other attempts and basically keep coming back to the same result. These queries run over a TRIM database and are supposed to list out the Hierarchy of 'Locations' by navigating down thru lrlocuri1 and lrlocuri2, for example like as below;

General Manager
  -Corporate Support
    --Customer Service
      --Xxxxxxx
      --Xxxxxxx
      (etc)
    --Finance
      --Xxxxx
  -Environment and Planning
    --Xxxxx
    --Xxxxx
  -Xxxxxxxxxxxx
    --Xxxxx
    --XXxxx

etc

Oracle by definition returns hierarchical datasets in depth first order. Thererfore your ordering here is correct (eg https://docs.oracle.com/cd/B19306_01/server.102/b14200/queries003.htm ).

SqlServer on the other hand does not have this resultset ordering. You have to order the data rows yourself. My solution is to build for each row a hierarchical path value to sort after the data is selected. If you have an id value for each row, something like this

parent-id / child-id

Here is a good example of it: Controlling the sibling order under recursive CTE? (Look at column path ).

If there are other solutions for SQLServer possible, mainly for more recent versions of it, I would be very interested to know.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM