闭包表(Closure Table)

设计血缘关系(data-lineage)时,想到要使用的表模型。

表设计 

节点记录表 - node


CREATE TABLE `lineages_node` (
  `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '节点名称',
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='节点';

节点关系表 - relation

CREATE TABLE `lineages_relation` (
  `ancestor` bigint(20) unsigned DEFAULT NULL COMMENT '祖先节点',
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `descendant` bigint(20) unsigned DEFAULT NULL COMMENT '后代节点',
  `depth` int(10) unsigned DEFAULT NULL COMMENT '相隔层级',
  PRIMARY KEY (`id`),
  KEY `lineages_relation_descendant_IDX` (`descendant`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='数据血缘-关系';

祖先 和 后代 数据表中的 约束 和 外键,还有表中其他字段,看自己业务需求

数据结构获取

获取祖先为id 1的节点的关系

SELECT elr.relation, elr.ancestor, elr.descendant FROM lineages_node eln


INNER JOIN lineages_relation elr ON eln.id = elr.ancestor


INNER JOIN lineages_node n3 ON elr.descendant = n3.id


WHERE eln.id = 1

删除id为4的节点

DELETE FROM NodeInfo WHERE node_id = 4;

DELETE FROM NodeRelation AS n1
 WHERE n1.descendant IN 
 (SELECT a.descendant FROM 
    (SELECT n2.descendant FROM NodeRelation AS n2 WHERE n2.ancestor = 4)
 AS a);

添加节点

CREATE DEFINER = `root`@`localhost` PROCEDURE `AddNode`(`_parent_name` varchar(255),`_node_name` varchar(255))

BEGIN

  DECLARE _ancestor INT(10) UNSIGNED;

  DECLARE _descendant INT(10) UNSIGNED;

  DECLARE _parent INT(10) UNSIGNED;

  IF NOT EXISTS(SELECT node_id From NodeInfo WHERE node_name = _node_name)

  THEN

    INSERT INTO NodeInfo (node_name) VALUES(_node_name);

    SET _descendant = (SELECT node_id FROM NodeInfo WHERE node_name = _node_name);

    INSERT INTO NodeRelation (ancestor,descendant,distance) VALUES(_descendant,_descendant,0);

    

    IF EXISTS (SELECT node_id FROM NodeInfo WHERE node_name = _parent_name)

    THEN

      SET _parent = (SELECT node_id FROM NodeInfo WHERE node_name = _parent_name);

      INSERT INTO NodeRelation (ancestor,descendant,distance) SELECT ancestor,_descendant,distance+1 FROM NodeRelation WHERE descendant = _parent;

    END IF;

  END IF;

END;
<?php

function addNode($nodeEntity, $parentNodeEntity) {

if (LineagesNode::getQuery()->where([['id', '=', $nodeEntity->id]])->exists()) {
            if (!empty($parentNodeEntity)) {
                /** @var LineagesNode $node */
                $node = LineagesNode::getQuery()->where([['id', '=', $nodeEntity->id]])->first();
                $nodeId = $node->id;
                // all descendants update
                $descendants = LineagesRelation::getQuery()->where([['ancestor', '=', $nodeId]])->get();
                // add new ancestor to descendants
                foreach ($descendants as $descendant) {
                    $insertBranches[] = [
                        'ancestor' => $parentNodeEntity->id,
                        'descendant' => $descendant->descendant,
                        'depth' => $descendant->depth + 1,
                    ];
                }
            }
            return true;
        } else {
            // create node and get new node id
            $nodeId = LineagesNode::getQuery()->insertGetId([
                'name' => $nodeEntity->name
            ]);
            // relationship
            $result = LineagesRelation::getQuery()->insert([
                'ancestor' => $nodeId,
                'descendant' => $nodeId,
                'depth' => 0
            ]);
            if (!empty($parentNodeEntity)) {
                // all ancestors from parent node
                $ancestors = LineagesRelation::getQuery()->where([['descendant', '=', $parentNodeEntity->id], ['deleted_at', '=', null]])->get();
                LineagesRelation::getQuery()->insert([
                    'ancestor' => $parentNodeEntity->id,
                    'descendant' => $nodeId,
                    'depth' => 1
                ]);
                LineagesRelation::getQuery()->insert([
                    'ancestor' => $parentNodeEntity->id,
                    'descendant' => $nodeId,
                    'depth' => 1
                ]);
                foreach ($ancestors as $ancestor) {
                    $insertBranches[] = [
                        'ancestor' => $ancestor->id,
                        'descendant' => $nodeId,
                        'depth' => $ancestor->depth + 1
                    ];
                }
            }
            // update
            if (!empty($insertBranches)) {
                return LineagesRelation::getQuery()->insert($insertBranches);
            }
            return $result;
        }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/718103.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python图像处理库-PIL(Pillow)

PIL库全称为Python Imaging Library&#xff0c;即Python图像处理库&#xff0c;是一个在Python中用于处理图像的非常流行的库。 一、PIL介绍 这个库提供了广泛的文件格式支持、高效的内部表示以及相当强大的图像处理功能。 核心图像库旨在快速访问存储在几种基本像素格式中的数…

C#特性-CallerMemberName、CallerFilePath和CallerLineNumber的介绍和应用

介绍 在csharp中&#xff0c;CallerMemberName, CallerFilePath, 和 CallerLineNumber 是编译时常量&#xff0c;它们是csharp 5.0引入的特性&#xff0c;用于提供有关调用堆栈的信息&#xff0c;通常用于日志记录和调试。这些特性可以自动填充方法的参数&#xff0c;无需显式…

基于SpringBoot校园食堂订餐管理系统

文章目录 系统运行图概要整体架构流程技术名词解释 系统运行图 概要 随着校园人口的增加和生活节奏的加快&#xff0c;校园食堂的订餐管理面临着诸多挑战&#xff0c;传统的人工点餐方式已经不能满足日益增长的需求和期望。因此&#xff0c;本论文旨在设计和实现一种基于Java的…

图解Attention学习笔记

教程是来自https://github.com/datawhalechina/learn-nlp-with-transformers/blob/main/docs/ 图解Attention Attention出现的原因是&#xff1a;基于循环神经网络&#xff08;RNN&#xff09;一类的seq2seq模型&#xff0c;在处理长文本时遇到了挑战&#xff0c;而对长文本中…

IPD体系进阶:组织体系诊断7S模型

目录 1. IPD 变革说明 2. 麦肯锡 7S 模型 3. IPD 资源 1. IPD 变革说明 企业引入 IPD&#xff0c;最直接的原因在于&#xff1a; 要解决组织当下遇到的发展问题。 这个时候就离不开对自身的诊断。 这跟解决日常问题是一样的思路。 有这样一句爱因斯坦的名言&#xff0c…

垃圾回收管理系统设计

一、引言 随着城市化进程的加快&#xff0c;垃圾处理问题日益凸显。为了有效管理垃圾回收&#xff0c;提高资源利用效率&#xff0c;降低环境污染&#xff0c;本文设计了一套垃圾回收管理系统。该系统涵盖了数据收集与分析、智能监测与识别、资源调配与协调、用户参与与反馈、…

maven编译【-Dmaven.test.skip=true和-DskipTests=true的区别】

1、背景 我在执行maven编译时&#xff0c;遇到下面情况&#xff1a; 1、当执行命令为下面&#xff1a; mvn clean compile package install -Dmaven.wagon.http.ssl.insecuretrue -Dmaven.wagon.http.ssl.allowalltrue -Dmaven.wagon.http.ssl.ignore.validity.datestrue -Dra…

基于自编码器的心电图信号异常检测(Python)

使用的数据集来自PTB心电图数据库&#xff0c;包括14552个心电图记录&#xff0c;包括两类&#xff1a;正常心跳和异常心跳&#xff0c;采样频率为125Hz。 import numpy as np np.set_printoptions(suppressTrue) import pandas as pd import matplotlib.pyplot as plt import…

qss实现登录界面美化

qss实现登录界面美化 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);// 去掉头部this->setWindowFlag(Qt::FramelessWindowHint);// 去掉空白部分th…

批量修改文件后缀名

背景引言 bat 文件是dos下的批处理文件。批处理文件是无格式的文本文件&#xff0c;它包含一条或多条命令。它的文件扩展名为 .bat 或 .cmd。在命令提示下输入批处理文件的名称&#xff0c;或者双击该批处理文件&#xff0c;系统就会调用cmd.exe按照该文件中各个命令出现的顺序…

鸿蒙 用tabs的 divider 属性 添加分割线,非常好用

divider10DividerStyle | null 用于设置区分TabBar和TabContent的分割线样式设置分割线样式&#xff0c;默认不显示分割线。 DividerStyle: 分割线的样式&#xff1b; null: 不显示分割线。 添加前&#xff1a; 添加后的效果&#xff1a;

JavaScript-事件监听及对象

添加事件监听 语法&#xff1a;对象名.addEventListener(事件类型,要执行的函数) 作用&#xff1a;当事件触发时&#xff0c;就调用这个函数 事件类型&#xff1a;比如用鼠标点击&#xff0c;或用滚轮滑动&#xff0c;鼠标经过这些 要执行的函数&#xff1a;要做的事 &l…

物联网主机E6000:智慧安防的核心动力

随着科技的不断进步&#xff0c;物联网&#xff08;IoT&#xff09;技术已经深入到我们生活的各个领域&#xff0c;尤其是在智慧安防领域&#xff0c;物联网技术的应用正变得越来越广泛。物联网主机E6000作为一款高性能的智能设备&#xff0c;其在智慧安防系统中扮演着至关重要…

海外仓系统有哪些?主流海外仓系统类型、优缺点,不同海外仓如何选择

作为海外仓的经营者&#xff0c;不管海外仓大小&#xff0c;你都应该知道海外仓系统对提升仓库管理效率有多重要。 不过现在市场上的海外仓系统确实种类太多了&#xff0c;想选到一个适合自己海外仓&#xff0c;性价比又比较高的wms海外仓系统也不是一件容易的事情。 本文会详…

小白入手实现AI客服机器人demo

一、环境准备 1 安装python 2 安装vscode 3 安装相关python库 pip install flask flask_cors openai 4.在vscode里安装TONGYI Lingma(AI编程助手&#xff09; 二、后端搭建 创建一个后端文件夹chatbot&#xff0c;再新建一个app.py的python文件 from flask import Flask, requ…

睿烨蜘蛛池福建官网下载

baidu搜索&#xff1a;如何联系八爪鱼SEO? baidu搜索&#xff1a;如何联系八爪鱼SEO? baidu搜索&#xff1a;如何联系八爪鱼SEO? 现在做站群程序的时候,由于百度、搜狗蜘蛛越来越少了,所以缓存也跟着减少,很多人都降低了服务器的配置,这个时候google蜘蛛却疯狂涌入,烦不胜烦…

Airflow任务流调度

0 前言 Airflow是Airbnb内部发起的一个工作流管理平台。使用Python编写实现的任务管理、调度、监控工作流平台。Airflow的调度依赖于crontab命令&#xff0c;与crontab相比&#xff0c;Airflow可以方便地查看任务的执行状况&#xff08;执行是否成功、执行时间、执行依赖等&…

CMSIS-RTOS2简介

本文介绍CMSIS-RTOS2。 1.引入 CMSIS-RTOS2在基于Arm Cortex处理器的设备上运行的实时操作系统内核上指定了通用RTOS接口。应用程序和中间件组件可以使用CMSIS-RTOS2 API在各种软件生态系统中实现更好的代码重用和更简单的集成。 CMSIS-RTOS2还指定了RTOS内核使用的标准OS T…

归并排序的应用—计算逆序对的个数

归并排序的应用—计算逆序对的个数 什么是逆序对题目的思路 题目 如果你还不会归并排序&#xff0c;那么请你先学会它&#xff0c;再来看本篇文章效果更佳。 什么是逆序对 逆序对的定义&#xff1a;在一个数列中&#xff0c;如果前面的数字大于后面的数字&#xff0c;那么这两…

NTP8835数字功放-智能投影仪音频解决方案

数字功放是智能投影仪音频解决方案的一种重要技术&#xff1b;与传统的模拟功放相比&#xff0c;数字功放具有更高的效率和更低的失真&#xff1b;在智能投影仪中应用数字功放技术&#xff0c;可以提供更清晰、更真实的音频效果&#xff0c;为用户带来更好的听觉体验。 数字功放…