0

It seems MonetDB does not support recursive CTE. This is a useful feature that I used to get BOM from ERP systems. For a greater flexibility I used Firebird recursive stored procedures to enhance the output with extra calculations. A good example of SQLServer recursive CTE can be found here https://www.essentialsql.com/recursive-ctes-explained/

Question is: Is it any way I can achieve similar results in MonetDB?

DanZ
  • 15
  • 6

2 Answers2

0

It is clear that once I have access to procedures, variables and while-loop, something can be done. The following code provides me the desired result using temporary tables. I would appreciate if anybody can provide me an alternative to this solution that provides the same results without using the temporary tables overhead.

CREATE TEMPORARY TABLE BOM (parent_id string, comp_id string, qty double) ON COMMIT PRESERVE ROWS;
INSERT INTO BOM VALUES('a','b',5), ('a','c',2), ('b','d',4), ('b','c',7), ('c','e',3);

select * from BOM;
+-----------+---------+--------------------------+
| parent_id | comp_id | qty                      |
+===========+=========+==========================+
| a         | b       |                        5 |
| a         | c       |                        2 |
| b         | d       |                        4 |
| b         | c       |                        7 |
| c         | e       |                        3 |
+-----------+---------+--------------------------+

CREATE TEMPORARY TABLE EXPLODED_BOM (parent_id string, comp_id string, path string, qty double, level integer) ON COMMIT PRESERVE ROWS;

CREATE OR REPLACE PROCEDURE UPDATE_BOM()
BEGIN

    DECLARE prev_count int;
    DECLARE crt_count int;
    DECLARE crt_level int;


    delete from EXPLODED_BOM; --make sure is empty
    insert into EXPLODED_BOM select parent_id, comp_id, parent_id||'-'||comp_id, qty, 0 from BOM; --insert first level

    SET prev_count = 0;
    SET crt_count = (select count(*) from EXPLODED_BOM);
    SET crt_level = 0;

    -- (crt_level < 100) avoids possible infinite loop, if BOM is malformed 
    WHILE (crt_level < 100) and (crt_count > prev_count) DO
        SET prev_count = crt_count;
        insert into EXPLODED_BOM select e.parent_id, a.comp_id, e.path||'-'||a.comp_id, a.qty*e.qty, crt_level+1 
        from BOM a, EXPLODED_BOM e
        where a.parent_id = e.comp_id and e.level=crt_level; 

        -- is it any chance to get the amount of "affected rows" by insert, update or delete statements, this way I can avoid checking the new count?
        SET crt_count = (select count(*) from EXPLODED_BOM);  
        SET crt_level = crt_level +1; 
    END WHILE;

END;

call UPDATE_BOM();

select * from EXPLODED_BOM;

+-----------+---------+---------+--------------------------+-------+
| parent_id | comp_id | path    | qty                      | level |
+===========+=========+=========+==========================+=======+
| a         | b       | a-b     |                        5 |     0 |
| a         | c       | a-c     |                        2 |     0 |
| b         | d       | b-d     |                        4 |     0 |
| b         | c       | b-c     |                        7 |     0 |
| c         | e       | c-e     |                        3 |     0 |
| a         | d       | a-b-d   |                       20 |     1 |
| a         | c       | a-b-c   |                       35 |     1 |
| a         | e       | a-c-e   |                        6 |     1 |
| b         | e       | b-c-e   |                       21 |     1 |
| a         | e       | a-b-c-e |                      105 |     2 |
+-----------+---------+---------+--------------------------+-------+
DanZ
  • 15
  • 6
0

There is currently no support for recursive CTEs in MonetDB[Lite]. The solution you have proposed yourself seems like the way to go.

Hannes Mühleisen
  • 2,542
  • 11
  • 13
  • DuckDB has support for recursive CTEs though ^^ – Hannes Mühleisen Jul 25 '20 at 07:37
  • I am aware of that. And is good that it was implemented in the early stages, too. I like many things about DuckDB (vs MonetDB) like CTE or single file storage (on-fly blocks compression would be fantastic). But I do miss an extended functionality like CREATE FUNCTION (AGGREGATE) ... LANGUAGE "C" more :) – DanZ Jul 25 '20 at 08:01
  • To be fair, another plus of DuckDB against MonetDB (if I am not mistaken) is per blocks computations. If that is true, it would dramatically save (memory) resources in a lot of cases where columns are parsed in the natural (storage) order to compute something. – DanZ Jul 25 '20 at 08:15
  • @DanZ yes this is true. The `CREATE FUNCTION LANGUAGE C` functionality is a little tricky since it adds a compiler dependency. We have an external API to create functions though. See here: https://github.com/cwida/duckdb/pull/712 – Hannes Mühleisen Jul 28 '20 at 06:24
  • These are great news. As a general mechanism, I wouldn’t need more, to be honest. Considering that a dll is often used from within C/C++ programs, DuckDB mechanism is as “native” as possible for me. To have the entire functionality I seek for, adding AGGREGATE and WINDOW functions, as well as TABLE returning functions would be ideal. BTW, 3 arguments limitation in DuckDB implementation can prove to be a serious restriction from an analytical perspective. You want examples? MultilinearRegression or Cluster(vector1, vector2, vector3,…, vector_ref, “method”, scalar_method_related_param1, …). – DanZ Jul 29 '20 at 11:59