CREATE Paths | SQLite SQL Tutorial Link Search Menu Expand Document

The CREATE script incorporates the following components:

  • prologue - json_ops through base_ops;
  • ancestor list generation - levels through ancestors (note that the referenced template contains a SELECT-style prologue, which is replaced with a modify-style prologue);
  • path_terms removes rows corresponding to already existent categories and adds row numbers;
  • ASCII id generation - id_counts through ids;
  • new_nodes joins path terms with newly generated IDs.
WITH
    ------------------------------ PROLOGUE ------------------------------
    json_ops(ops) AS (
        VALUES
            (json(
                '['                                                            ||
                    '{"op":"create", "path_new":"BAZ/bld/tcl/tests/safe/"},'   ||
                    '{"op":"create", "path_new":"safe/ssub00/modules/"},'      ||
                    '{"op":"create", "path_new":"safe/ssub00/msys/nix/misc/"}' ||
                ']'
            ))
    ),
    base_ops AS (
        SELECT
            "key" + 1 AS opid,
            json_extract(value, '$.op') AS op,
            json_extract(value, '$.path_old') AS rootpath_old,
            json_extract(value, '$.path_new') AS rootpath_new
        FROM json_ops AS jo, json_each(jo.ops) AS terms
    ),
    /********************************************************************/
    --------------------------- ANCESTOR LIST ----------------------------
    levels AS (
        SELECT opid, rootpath_new AS path, length(rootpath_new) - length(replace(rootpath_new, '/', '')) AS depth
        FROM base_ops
    ),
    json_objs AS (
        SELECT *, json('{"' || replace(rtrim(path, '/'), '/', '": {"') ||
            '":""' || replace(hex(zeroblob(depth)), '00', '}')) AS json_obj
        FROM levels
    ),
    ancestors AS (
        SELECT min(jo.opid) AS opid,
            replace(replace(substr(fullkey, 3), '.', '/'), '^#^', '.') || '/' AS asc_path,
            replace("key", '^#^', '.') AS asc_name
        FROM
            json_objs AS jo,
            json_tree(replace(jo.json_obj, '.', '^#^')) AS terms
        WHERE terms.parent IS NOT NULL
        GROUP BY asc_path
        ORDER BY opid, asc_path
    ),
    /********************************************************************/
    path_terms AS (
        SELECT 
            row_number() OVER (ORDER BY opid, asc_path) AS counter,
            ancestors.*, substr(asc_path, 1, length(asc_path) - length(asc_name) - 1) AS asc_prefix
        FROM ancestors
        LEFT JOIN categories AS cats ON asc_path = cats.path
        WHERE cats.ascii_id IS NULL        
    ),
    ------------------------- ASCII ID GENERATOR -------------------------
    id_counts(id_counter) AS (SELECT count(*) FROM path_terms),
    json_templates AS (SELECT '[' || replace(hex(zeroblob(id_counter*8/2-1)), '0', '0,') || '0,0]' AS json_template FROM id_counts),
    char_templates(char_template) AS (VALUES ('-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_')),
    ascii_ids AS (
        SELECT group_concat(substr(char_template, (random() & 63) + 1, 1), '') AS ascii_id, "key"/8 + 1 AS counter
        FROM char_templates, json_templates, json_each(json_templates.json_template) AS terms
        GROUP BY counter
    ),
    ids AS (
        SELECT counter, ascii_id,
               (unicode(substr(ascii_id, 1, 1)) << 8*7) +
               (unicode(substr(ascii_id, 2, 1)) << 8*6) +
               (unicode(substr(ascii_id, 3, 1)) << 8*5) +
               (unicode(substr(ascii_id, 4, 1)) << 8*4) +
               (unicode(substr(ascii_id, 5, 1)) << 8*3) +
               (unicode(substr(ascii_id, 6, 1)) << 8*2) +
               (unicode(substr(ascii_id, 7, 1)) << 8*1) +
               (unicode(substr(ascii_id, 8, 1)) << 8*0) AS bin_id
        FROM ascii_ids
    ),
    /********************************************************************/
    new_nodes AS (
        SELECT bin_id AS id, asc_name AS name, asc_prefix AS prefix
		FROM path_terms, ids USING (counter)
	)
INSERT INTO categories (id, name, prefix)
SELECT * FROM new_nodes;