Getting all parent rows in one SQL query

后端 未结 7 1905
温柔的废话
温柔的废话 2020-11-27 11:59

I have a simple MySQL table thats contains a list of categories, level is determined by parent_id:

id  name    parent_id
---------------------------
1   Home         


        
相关标签:
7条回答
  • 2020-11-27 12:15

    AFAIK no.

    This Sitepoint article may help you.

    You could retrieve all the elements with one query, store it in an array and then iterate, as explained here and here

    0 讨论(0)
  • 2020-11-27 12:21

    I think, there's no easy way to do that, using one query.

    I would recommend to take a look at Nested Sets, that seems to fit your needs.

    0 讨论(0)
  • 2020-11-27 12:24

    I used the previous answers as examples to make smth more readable.

    SELECT  @org_id as id,
        (SELECT name FROM test.organizations WHERE id = @org_id) as name,
        (SELECT @org_id := parent_id FROM test.organizations WHERE id = @org_id) AS parent_id
    FROM (SELECT @org_id := 4) vars, test.organizations org
    WHERE @org_id is not NULL
    ORDER BY id;
    

    The result of execution looks like that:

    (just for quick) to check it yourself you need to enter values from the question into database test, table organizations

    CREATE TABLE organizations(
    id        int(11) NOT NULL AUTO_INCREMENT,
    name      varchar(45) DEFAULT NULL,
    parent_id int(11)     DEFAULT NULL,
    PRIMARY KEY (id));
    
    insert into organizations values(1, "home", null);
    insert into organizations values(2, "about", 1);
    insert into organizations values(3, "contact", 1);
    insert into organizations values(4, "legal", 2);
    insert into organizations values(5, "privacy", 4);
    insert into organizations values(6, "products", 1);
    insert into organizations values(7, "support", 1);
    
    0 讨论(0)
  • 2020-11-27 12:25

    Adapted from here:

    SELECT T2.id, T2.name
    FROM (
        SELECT
            @r AS _id,
            (SELECT @r := parent_id FROM table1 WHERE id = _id) AS parent_id,
            @l := @l + 1 AS lvl
        FROM
            (SELECT @r := 5, @l := 0) vars,
            table1 h
        WHERE @r <> 0) T1
    JOIN table1 T2
    ON T1._id = T2.id
    ORDER BY T1.lvl DESC
    

    The line @r := 5 is the page number for the current page. The result is as follows:

    1, 'Home'
    2, 'About'
    4, 'Legal'
    5, 'Privacy'
    
    0 讨论(0)
  • 2020-11-27 12:31

    In addition to the above solutions:

    post
    -----
    id
    title
    author
    
    author
    ------
    id
    parent_id
    name
    
    
    [post]
    
    id  | title | author |  
    ----------------------
    1   | abc   | 3      |
    
    
    [author]
    
    | id    | parent_id | name  |   
    |---------------------------|
    | 1     | 0         | u1    |
    | 2     | 1         | u2    |
    | 3     | 2         | u3    |
    | 4     | 0         | u4    |
    

    an author including parents can have an access to the post.

    I want to check whether author has an access to the post.

    Solution:

    give the post author's id and return all its authors and author's parents

    SELECT T2.id, T2.username 
    FROM (
        SELECT @r AS _id, 
            (SELECT @r := parent_id FROM users WHERE id = _id) AS parent_id,
            @l := @l + 1
        FROM
            (SELECT @r := 2, @l := 0) vars, 
            users h     
        WHERE @r <> 0) T1 JOIN users T2 
    ON T1._id = T2.id;
    

    @r := 2 => assigning value to @r variable.

    0 讨论(0)
  • 2020-11-27 12:37

    Awesome answer by Mark Byers!

    Maybe a bit late to the party, but if you also want to prevent an infinite loop when id = parent_id (i.e. somehow when data has been corrupted), you can expand the answer like this:

        SELECT T2.id, T2.name
        FROM (
            SELECT
                @r AS _id,
                @p := @r AS previous,
                (SELECT @r := parent_id FROM table1 WHERE id = _id) AS parent_id,
                @l := @l + 1 AS lvl
            FROM
                (SELECT @r := 5, @p := 0, @l := 0) vars,
                table1 h
            WHERE @r <> 0 AND @r <> @p) T1
        JOIN table1 T2
        ON T1._id = T2.id
        ORDER BY T1.lvl DESC
    
    0 讨论(0)
提交回复
热议问题