父和子存储在同一个表中时显示父子关系

kir*_*mal 7 sql t-sql sql-server

我有如下的sql server表结构:

ID    Name     ParentID
-----------------------
1     Root       NULL
2     Business   1
3     Finance    1
4     Stock      3
Run Code Online (Sandbox Code Playgroud)

我想在我的网页中显示详细信息

ID    Name     ParentName
-------------------------
1     Root      -
2     Business  Root
3     Finance   Root
4     Stock     Finance    
Run Code Online (Sandbox Code Playgroud)

如何构建我的SQL查询?请帮我.

Eri*_*ric 10

试试这个...

SELECT a.ID, a.Name, b.Name AS 'ParentName'
FROM TABLE AS a LEFT JOIN TABLE AS b on a.ParentID = b.ID
Run Code Online (Sandbox Code Playgroud)

使用左连接,查询将找不到要为NULL加入的任何内容并为ParentName列返回空白.

编辑:

如果您不希望"父级"列为空,但希望显示" - "破折号,请使用此查询.

SELECT a.ID, a.Name, COALESCE(b.Name,'-') AS 'ParentName'
FROM TABLE AS a LEFT JOIN TABLE AS b on a.ParentID = b.ID
Run Code Online (Sandbox Code Playgroud)


OMG*_*ies 7

假设 SQL Server 2005+,使用这样的递归 CTE:

WITH hierarchy AS (
  SELECT t.id,
         t.name,
         t.parentid,
         CAST(NULL AS VARCHAR(50)) AS parentname
    FROM YOUR_TABLE t
   WHERE t.parentid IS NULL
  UNION ALL
  SELECT x.id,
         x.name,
         x.parentid,
         y.name
    FROM YOUR_TABLE x
    JOIN hierarchy y ON y.id = x.parentid)
SELECT s.id,
       s.name,
       s.parentname
  FROM hierarchy s
Run Code Online (Sandbox Code Playgroud)

NULL 的 CASTing 可能看起来很奇怪,但 SQL Server 将数据类型默认为 INT,除非以您在我的查询中看到的方式指定。


Mee*_*ati 5

我面临着同样的情况。我想从同一个表中获取特定父级的所有子列表,因为 MySQL在 MySQL 8 以下没有提供递归 CTE 。

我已经通过递归存储过程解决了我的问题。我们需要将max_sp_recursion_depth设置为递归存储过程调用。

我的表结构如下

在此输入图像描述

我的存储过程(带递归)如下:

DROP PROCEDURE IF EXISTS getAllChilds;
DELIMITER $$
SET @@SESSION.max_sp_recursion_depth=25; $$
CREATE PROCEDURE getAllChilds (IN inId int(11), INOUT list_obj text, IN end_arr CHAR(1))
BEGIN
    DECLARE stop_cur INTEGER DEFAULT 0;
    DECLARE _id INTEGER DEFAULT 0;
    DECLARE _name VARCHAR(20) DEFAULT 0;
    DEClARE curSelfId CURSOR FOR SELECT id, name FROM new_table where parentId = inId;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET stop_cur = 1; 
    OPEN curSelfId; 
    getSelfId: LOOP
        FETCH curSelfId INTO _id, _name;
        IF stop_cur = 1 THEN LEAVE getSelfId; END IF;
        IF list_obj is null or list_obj = "" then 
            SET list_obj = CONCAT("[","{",'"name":"',_name,'","id":"',_id,'"',"}");
        else 
            SET list_obj = CONCAT(list_obj,',', "{",'"name":"',_name,'","id":"',_id,'"',"}");
        end if;
        CALL getAllChilds(_id,list_obj,"");
    END LOOP getSelfId;
    CLOSE curSelfId;
    IF end_arr is not null and end_arr != "" then 
        SET list_obj = CONCAT(list_obj,end_arr);
        SELECT @ids;
    end if;
END$$
DELIMITER ;
Run Code Online (Sandbox Code Playgroud)

要调用这个存储过程,我们需要传递 3 个参数,

  1. 家长 ID
  2. 空/空对象
  3. 结束数组符号。(仅附加最后一个对象而不是所有对象)。

    调用 getAllChilds(1,@ids,']');

使用此存储过程,您可以获取 JSON 字符串中的所有级别子级。您可以解析此 json 字符串并使用任何 JSONparser 在任何对象中进行转换。

或者

我们可以将这个答案包装在存储过程中,以便将其用于任何编程语言,例如 JAVA。我们将其包装到存储过程中,因为我们不能在查询中使用:=。这里我们使用find_in_set函数。我的存储过程(没有递归)。

DROP PROCEDURE IF EXISTS getAllChilds;
DELIMITER $$
CREATE PROCEDURE getAllChilds (IN inId int(11))
BEGIN
    select id,
        name,
        parentid
    from  
        (select * from new_table
        order by parentid, id) new_table,
        (select @pv := inId) initialisation
    where   
        find_in_set(parentid, @pv) > 0
        and @pv := concat(@pv, ',', id);
END$$
DELIMITER ;
Run Code Online (Sandbox Code Playgroud)

要调用此存储过程,我们只需要父 ID。

CALL getAllChilds(1);
Run Code Online (Sandbox Code Playgroud)