如何创建一个以递归方式显示项目子项的查询

时间:2013-04-19 14:49:31

标签: mysql sql recursion

我有一个MySQL表,其格式如下:

CREATE  TABLE IF NOT EXISTS `Company` (
  `CompanyId` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
  `Name` VARCHAR(45) NULL ,
  `Address` VARCHAR(45) NULL ,
  `ParentCompanyId` INT UNSIGNED NULL ,
  PRIMARY KEY (`CompanyId`) ,
  INDEX `fk_Company_Company_idx` (`ParentCompanyId` ASC) ,
  CONSTRAINT `fk_Company_Company`
    FOREIGN KEY (`ParentCompanyId` )
    REFERENCES `Company` (`CompanyId` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;

因此,为了澄清,我有可以拥有母公司的公司。这可能会导致以下示例表内容:

CompanyId    Name    Address        ParentCompanyId
1            Foo     Somestreet 3   NULL
2            Bar     Somelane 4     1
3            McD     Someway 1337   1
4            KFC     Somewhere 12   2
5            Pub     Someplace 2    4

现在我的问题出现了。 我想检索CompanyId 2递归的所有子项。因此,应显示以下结果集:

CompanyId    Name    Address        ParentCompanyId
4            KFC     Somewhere 12   2
5            Pub     Someplace 2    4

我想过使用With ... AS ...语句,但MySQL不支持它。我想到的另一个解决方案是使用一个返回结果集的过程或函数,并将其与该函数的递归调用结合起来。但MySQL只支持列类型作为返回值。

我想到的最后一个可能的解决方案是创建一个包含两个字段的表:CompanyId和HasChildId。然后我可以编写一个程序,通过公司递归循环,并通过companyid填充所有递归子表。在这种情况下,我可以编写一个连接此表的查询:

SELECT CompanyId, Name, Address
FROM   Company C -- The child
INNER JOIN CompanyChildMappingTable M
        ON M.CompanyId = C.HasChildId
INNER JOIN Company P -- The parent
        ON P.CompanyId = M.CompanyId
WHERE P.CompanyId = 2;

如果我每隔24小时调用一次该程序,并且在将新记录插入Company时动态填写表格,则此选项应该是快速的。但这可能非常棘手,我应该通过在公司表上编写触发器来实现这一点。

我想听听你的意见。

解决方案:我已经构建了以下过程来填充我的表(现在它只返回SELECT结果)。

DELIMITER $$
DROP PROCEDURE IF EXISTS CompanyFillWithSubCompaniesByCompanyId$$

CREATE PROCEDURE CompanyFillWithSubCompaniesByCompanyId(IN V_CompanyId BIGINT UNSIGNED, IN V_TableName VARCHAR(100))
BEGIN

    DECLARE V_CONCAT_IDS VARCHAR(9999) DEFAULT '';
    DECLARE V_CURRENT_CONCAT VARCHAR(9999) DEFAULT '';

    SET V_CONCAT_IDS = (SELECT GROUP_CONCAT(CompanyId) FROM Company WHERE V_CompanyId IS NULL OR ParentCompanyId = V_CompanyId);
    SET V_CURRENT_CONCAT = V_CONCAT_IDS;

    IF V_CompanyId IS NOT NULL THEN

        companyLoop: LOOP

            IF V_CURRENT_CONCAT IS NULL THEN
                LEAVE companyLoop;
            END IF;

            SET V_CURRENT_CONCAT = (SELECT GROUP_CONCAT(CompanyId) FROM Company WHERE FIND_IN_SET(ParentCompanyId, V_CURRENT_CONCAT));
            SET V_CONCAT_IDS = CONCAT_WS(',', V_CONCAT_IDS, V_CURRENT_CONCAT);

        END LOOP;

    END IF;

    SELECT * FROM Company WHERE FIND_IN_SET(CompanyId, V_CONCAT_IDS);

END$$

2 个答案:

答案 0 :(得分:0)

参考:

<强> Recursive MySQL Query with relational innoDB

<强> How to find all child rows in MySQL?

它应该了解如何在MYSQL

中处理这样的数据结构

答案 1 :(得分:0)

最快的搜索方式是,使用公司ID值为2. companyId = parentId * 2然后查询数据库,选择* from company where((CompanyId%$ parentId)== 0) 我尝试了这个代码,它很快但问题是它创建了child的id为parentId * 2,如果子深度变深,int,float可能会超出范围。所以,我重新创建了我的整个程序。