0

我有一个具有以下格式的 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. 但这可能非常棘手,我应该通过在 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$$
4

2 回答 2

0

参考:

具有关系 innoDB 的递归 MySQL 查询

如何在 MySQL 中查找所有子行?

它将给出如何处理这种数据结构的想法MYSQL

于 2013-04-19T14:53:09.157 回答
0

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

于 2013-04-19T15:03:34.757 回答