如何编写存储递归过程以获得层次元素

问题描述 投票:0回答:6

你好,我有一个有很多属性的表配置文件,配置文件有父级但父级可以有父级等等。 我想获取所有属性列表(甚至是父母的属性) 我用 mysql 5.1.42 编写了这个存储过程,但它只返回配置文件的属性,不包括父母的属性 ...

CREATE DEFINER=`root`@`localhost` PROCEDURE `get_all_attributes`(IN profile_id INT)
BEGIN
  DECLARE parent_id INT DEFAULT NULL;

  -- Get the attributes for the current profile
  SELECT
    Id, attribut_rank, attribut_type, create_date, editor, label, memo, name, profile
  FROM 
    marketing_profile_attribut
  WHERE 
    profile = profile_id
  ORDER BY 
    attribut_rank;

  -- Get the parent ID for the current profile
  SELECT 
    parent
  INTO
    parent_id
  FROM
    marketing_profile
  WHERE 
    Id = profile_id;

  -- If the parent ID is not null, call the stored procedure recursively with the parent ID
  IF parent_id IS NOT NULL THEN
    CALL get_all_attributes(parent_id);
  END IF;
END
...

你能告诉我这个程序有什么问题我正在使用 mysql 5.1.42

c# mysql stored-procedures hierarchy recursive-query
6个回答
0
投票

按原样尝试这个(它适用于我的数据库):

CREATE PROCEDURE `get_all_attributes2`(IN p_profile INT)
BEGIN
    DECLARE not_found INT DEFAULT FALSE;
  DECLARE parent_id INT DEFAULT NULL;
    
  DECLARE cur_data CURSOR FOR
  SELECT parent
  FROM marketing_profile
  WHERE Id = p_profile;
    
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET not_found = TRUE;    
    
    SET @@max_sp_recursion_depth = 100;
    
    CREATE TEMPORARY TABLE IF NOT EXISTS temp_attributes (
    Id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    name VARCHAR(45) DEFAULT NULL,
    memo VARCHAR(1000) DEFAULT NULL,
    label VARCHAR(45) DEFAULT NULL,
    editor INT(10) UNSIGNED DEFAULT NULL,
    attribut_type INT(10) UNSIGNED DEFAULT NULL,
    profile INT(10) UNSIGNED DEFAULT NULL,
    create_date DATETIME DEFAULT NULL,
    attribut_rank INT(10) UNSIGNED DEFAULT NULL,
    PRIMARY KEY (Id)
  );
    
    -- insert the attributes of p_profile into temporary table
    INSERT INTO temp_attributes
  SELECT Id, name, memo, label, editor, attribut_type, profile, create_date, attribut_rank
  FROM marketing_profile_attribut
  WHERE profile = p_profile;
    
    OPEN cur_data;
  data_loop: LOOP
    FETCH cur_data
        INTO parent_id;
    IF not_found THEN
      LEAVE data_loop;
    END IF;
        CALL get_all_attributes2(parent_id);
    END LOOP;
    CLOSE cur_data;
    
  select * from temp_attributes
    order by attribut_rank;
        
    DROP TABLE temp_attributes;
END

0
投票

检查MySQL的

max_sp_recursion_depth
设置。由于您只是从树中寻找直接父级,因此您可以使用游标循环而不是递归。

最好的解决方案是将旧的 MySQL 版本更新到更新的版本,您可以为此使用通用表表达式。


0
投票

有几件事使程序无法正常工作。

  1. max_sp_recursion_depth:如果它假定值为 0,这会使过程不是递归的,并在您尝试调用正在运行的相同过程时停止执行。
  2. 来自 marketing_profile_attribut 的选择是本地的,并且只存在于当前实例中!以递归方式调用的每个实例只会产生一个条目。您需要一个可以存储结果的结构。

考虑到以上两点,程序可能是这样的:

CREATE PROCEDURE `get_all_attributes`(IN profile_id INT)
BEGIN
    
  DECLARE parent_id INT DEFAULT NULL;
    
    CREATE TEMPORARY TABLE IF NOT EXISTS temp_table
    AS SELECT
    Id, attribut_rank, attribut_type, create_date, editor, label, memo, name, profile
    FROM 
    marketing_profile_attribut;
    
    SET @@max_sp_recursion_depth = 100;
        
  -- Get the attributes for the current profile
  INSERT INTO temp_table(Id, create_date)
  SELECT
    Id, attribut_rank, attribut_type, create_date, editor, label, memo, name, profile
  FROM 
    marketing_profile_attribut
  WHERE 
    profile = profile_id
  ORDER BY 
    Id;
        
  -- Get the parent ID for the current profile
  SELECT 
    parent
  INTO
    parent_id
  FROM
    marketing_profile
  WHERE 
    Id = profile_id;

  -- If the parent ID is not null, call the stored procedure recursively with the parent ID
  IF parent_id IS NOT NULL THEN
    CALL get_all_attributes(parent_id);
  else
      select * from temp_table;
      DROP TABLE temp_table;
    end if;
END

0
投票

谢谢你的回答 我尝试使用临时表作为建议的解决方案,但在使用 repeat until 时结果相同,使用以下函数 创建定义器=

root
@
localhost
过程
get_all_attributes
(在p_profile INT中) 开始 声明完成 INT DEFAULT FALSE; 声明父 INT; DECLARE cur CURSOR FOR SELECT parent FROM marketing_profile WHERE Id = p_profile; 为 NOT FOUND SET 声明继续处理程序 done = TRUE;

CREATE TEMPORARY TABLE temp_attributes (
    Id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    name VARCHAR(45) DEFAULT NULL,
    memo VARCHAR(1000) DEFAULT NULL,
    label VARCHAR(45) DEFAULT NULL,
    editor INT(10) UNSIGNED DEFAULT NULL,
    attribut_type INT(10) UNSIGNED DEFAULT NULL,
    profile INT(10) UNSIGNED DEFAULT NULL,
    create_date DATETIME DEFAULT NULL,
    attribut_rank INT(10) UNSIGNED DEFAULT NULL,
    PRIMARY KEY (Id)
);

INSERT INTO temp_attributes
SELECT Id, name, memo, label, editor, attribut_type, profile, create_date, attribut_rank
FROM marketing_profile_attribut
WHERE profile = p_profile
ORDER BY attribut_rank;

SET parent = p_profile;

WHILE NOT done DO
    SELECT parent INTO parent FROM marketing_profile WHERE Id = parent;

    IF parent IS NOT NULL THEN
        INSERT INTO temp_attributes
        SELECT Id, name, memo, label, editor, attribut_type, profile, create_date, attribut_rank
        FROM marketing_profile_attribut
        WHERE profile = parent
        ORDER BY attribut_rank;
    END IF;
END WHILE;

SELECT * FROM temp_attributes;

DROP TEMPORARY TABLE IF EXISTS temp_attributes;

结束


0
投票

您的存储过程的问题是您只选择当前配置文件的属性,而不是递归地选择所有父配置文件的属性。您需要修改存储过程以递归地选择所有父配置文件的属性。

您可以通过使用递归公用表表达式 (CTE) 来选择所有父配置文件的属性来实现此目的。不幸的是,MySQL 5.1 不支持 CTE,但您可以使用临时表来实现相同的结果。

这里是一个示例存储过程,它使用临时表递归地选择所有父配置文件的属性:

CREATE DEFINER=`root`@`localhost` PROCEDURE `get_all_attributes`(IN profile_id INT)
BEGIN
  -- Create a temporary table to store the attributes for all parent profiles
  CREATE TEMPORARY TABLE temp_attributes (
    Id INT,
    attribut_rank INT,
    attribut_type VARCHAR(255),
    create_date DATETIME,
    editor VARCHAR(255),
    label VARCHAR(255),
    memo TEXT,
    name VARCHAR(255),
    profile INT
  );

  DECLARE parent_id INT DEFAULT NULL;

  -- Get the attributes for the current profile and insert them into the temporary table
  INSERT INTO temp_attributes
  SELECT
    Id, attribut_rank, attribut_type, create_date, editor, label, memo, name, profile
  FROM 
    marketing_profile_attribut
  WHERE 
    profile = profile_id;

  -- Get the parent ID for the current profile
  SELECT 
    parent
  INTO
    parent_id
  FROM
    marketing_profile
  WHERE 
    Id = profile_id;

  -- If the parent ID is not null, recursively insert the attributes for all parent profiles into the temporary table
  IF parent_id IS NOT NULL THEN
    CALL get_all_attributes(parent_id);
    INSERT INTO temp_attributes
    SELECT
      Id, attribut_rank, attribut_type, create_date, editor, label, memo, name, profile
    FROM 
      temp_attributes
    WHERE 
      profile = parent_id;
  END IF;

  -- Select all the attributes from the temporary table
  SELECT * FROM temp_attributes;

  -- Drop the temporary table
  DROP TEMPORARY TABLE IF EXISTS temp_attributes;
END

在此存储过程中,创建了一个名为 temp_attributes 的临时表来存储所有父配置文件的属性。 INSERT INTO 语句用于将当前配置文件的属性插入到临时表中。如果父 ID 不为空,则使用父 ID 递归调用存储过程,并将所有父配置文件的属性插入到临时表中。最后,从临时表中选择所有属性,并删除临时表。

注意DROP TEMPORARY TABLE IF EXISTS语句用于确保临时表总是在存储过程结束时被删除,即使发生错误。


0
投票

其实也有例外 为此我做了一些更正..结果函数 创建定义器=

root
@
localhost
过程
get_all_attributes
(IN profile_id INT) 开始

DECLARE parent_id INT DEFAULT NULL;

CREATE TEMPORARY TABLE IF NOT EXISTS temp_table
AS SELECT
Id, attribut_rank, attribut_type, create_date, editor, label, memo, name, profile
FROM
marketing_profile_attribut
where profile=   profile_id
group by Id
;


SET @@max_sp_recursion_depth = 100;

-- 获取当前配置文件的属性 INSERT INTO temp_table (Id, attribut_rank, attribut_type, create_date, editor,

label
, memo, name, profile)

选择 Id, attribut_rank, attribut_type, create_date, editor, label, memo, name, profile 从 营销资料属性 在哪里 配置文件 = profile_id 订购方式 编号;

-- 获取当前配置文件的父 ID 选择 父母 进入 parent_id 从 营销资料 在哪里 id = profile_id;

-- 如果parent ID不为null,则用parent ID递归调用存储过程 如果 parent_id 不为 NULL 那么 CALL get_all_attributes(parent_id); 否则

  select * from temp_table group by Id order by (attribut_rank);

end if;

结束

© www.soinside.com 2019 - 2024. All rights reserved.