sql—沿dag的顶点行

cygmwpex  于 2021-07-24  发布在  Java
关注(0)|答案(1)|浏览(427)

目标是从

  1. -- a b c d
  2. --
  3. -- g e f
  4. --
  5. -- h
  6. dag (vertex, successor) as (values
  7. ('alpha', 'bravo'),
  8. ('bravo', 'charlie'),
  9. ('charlie', 'delta'),
  10. ('delta', null),
  11. ('alpha', 'echo'),
  12. ('echo', 'foxtrot'),
  13. ('bravo', 'foxtrot'),
  14. ('foxtrot', null),
  15. ('alpha', 'golf'),
  16. ('golf', 'hotel'),
  17. ('hotel', null)
  18. )

进入之内

  1. 'id_foo', 0, 'alpha'
  2. 'id_foo', 1, 'bravo'
  3. 'id_foo', 2, 'charlie'
  4. 'id_foo', 3, 'delta'
  5. 'id_bar', 0, 'alpha'
  6. 'id_bar', 1, 'bravo'
  7. 'id_bar', 2, 'foxtrot'
  8. 'id_qux', 0, 'alpha'
  9. 'id_qux', 1, 'echo'
  10. 'id_qux', 2, 'foxtrot'
  11. 'id_fno', 0, 'alpha'
  12. 'id_fno', 1, 'golf'
  13. 'id_fno', 2, 'hotel'

我可以分两步做。

  1. with recursive intermediate as (
  2. select * from (
  3. with recursive
  4. dag (vertex, successor) as (values
  5. ('alpha', 'bravo'),
  6. ('bravo', 'charlie'),
  7. ('charlie', 'delta'),
  8. ('delta', null),
  9. ('alpha', 'echo'),
  10. ('echo', 'foxtrot'),
  11. ('bravo', 'foxtrot'),
  12. ('foxtrot', null),
  13. ('alpha', 'golf'),
  14. ('golf', 'hotel'),
  15. ('hotel', null)
  16. ),
  17. cte as (
  18. select
  19. vertex,
  20. successor,
  21. 1 as length,
  22. vertex as path
  23. from dag where successor is null
  24. union all
  25. select
  26. dag.vertex,
  27. dag.successor,
  28. length + 1,
  29. dag.vertex||'→'||path
  30. from dag join cte
  31. where dag.successor = cte.vertex
  32. )
  33. select
  34. length, path
  35. from cte
  36. where vertex = 'alpha'
  37. -- 3, 'alpha→bravo→charlie→delta'
  38. -- 3, 'alpha→bravo→foxtrot'
  39. -- 3, 'alpha→echo→foxtrot'
  40. -- 4, 'alpha→golf→hotel'
  41. )
  42. ),
  43. cte as (
  44. select
  45. length,
  46. path,
  47. -1 as "index",
  48. '' as vertex,
  49. path||'→' as rest
  50. from intermediate
  51. union all
  52. select
  53. length,
  54. path,
  55. "index" + 1,
  56. substr(rest, 0, instr(rest, '→')),
  57. substr(rest, instr(rest, '→') + 1)
  58. from cte
  59. where rest != ''
  60. )
  61. select length, path, "index", vertex from cte
  62. where vertex != ''
  63. order by path, "index";

我认为这样做是浪费。有没有可能没有字符串连接和拆分,没有中间结果集?
目标平台是模糊的现代sql。上面的代码已经过测试,并用sqlite运行。

j2datikz

j2datikz1#

  1. with recursive
  2. dag (vertex, successor) as (values
  3. ('alpha', 'bravo'),
  4. ('bravo', 'charlie'),
  5. ('charlie', 'delta'),
  6. ('delta', null),
  7. ('alpha', 'echo'),
  8. ('echo', 'foxtrot'),
  9. ('bravo', 'foxtrot'),
  10. ('foxtrot', null),
  11. ('alpha', 'golf'),
  12. ('golf', 'hotel'),
  13. ('hotel', null)
  14. ),
  15. head (vertex) as (
  16. select vertex from dag except select successor from dag
  17. ),
  18. paths (row, depth, parent_row, vertex, successor) as (
  19. select row_number() over (), 1, 0::bigint, dag.vertex, dag.successor
  20. from head
  21. join dag on (dag.vertex = head.vertex)
  22. union all
  23. select row_number() over (), depth + 1, row, dag.vertex, dag.successor
  24. from paths
  25. join dag on (dag.vertex = paths.successor)
  26. ),
  27. result (path_id, parent_row, depth, vertex) as (
  28. select row_number() over (), parent_row, depth, vertex
  29. from paths
  30. where successor is null
  31. union all
  32. select result.path_id, paths.parent_row, paths.depth, paths.vertex
  33. from result
  34. join paths on (paths.row = result.parent_row and paths.depth = result.depth - 1)
  35. )
  36. select path_id, depth, vertex
  37. from result
  38. order by 1, 2
  39. ;

特定于postgresql

  1. with recursive
  2. dag (vertex, successor) as (values
  3. ('alpha', 'bravo'),
  4. ('bravo', 'charlie'),
  5. ('charlie', 'delta'),
  6. ('delta', null),
  7. ('alpha', 'echo'),
  8. ('echo', 'foxtrot'),
  9. ('bravo', 'foxtrot'),
  10. ('foxtrot', null),
  11. ('alpha', 'golf'),
  12. ('golf', 'hotel'),
  13. ('hotel', null)
  14. ),
  15. head (vertex) as (
  16. select vertex from dag except select successor from dag
  17. ),
  18. paths (path, successor) as (
  19. select array[dag.vertex], dag.successor
  20. from head
  21. join dag on (dag.vertex = head.vertex)
  22. union all
  23. select array_append(paths.path, dag.vertex), dag.successor
  24. from paths
  25. join dag on (dag.vertex = paths.successor)
  26. ),
  27. result_paths (path_id, path) as (
  28. select row_number() over (), path
  29. from paths
  30. where successor is null
  31. ),
  32. result (path_id, depth, vertex) as (
  33. select path_id, p.nr, p.elem
  34. from result_paths
  35. left join lateral unnest (path) with ordinality as p(elem, nr) on true
  36. )
  37. select * from result
  38. order by 1,2
  39. ;
展开查看全部

相关问题