<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
		>
<channel>
	<title>Comments on: Adjacency list model</title>
	<atom:link href="http://blog.richardknop.com/2009/05/adjacency-list-model/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.richardknop.com/2009/05/adjacency-list-model/</link>
	<description>Zend Framework, PHP, Django, Python, SQL, MySQL, PostgreSQL, Oracle, PL/SQL, data model patterns, OOP, design patterns, JavaScript, jQuery, HTML, XHTML, CSS, XML, web services &#38; APIs, Security, E-commerce and much more</description>
	<lastBuildDate>Fri, 03 Feb 2012 23:50:21 +0000</lastBuildDate>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
	<item>
		<title>By: Anonymous</title>
		<link>http://blog.richardknop.com/2009/05/adjacency-list-model/comment-page-1/#comment-926</link>
		<dc:creator>Anonymous</dc:creator>
		<pubDate>Tue, 17 Jan 2012 23:51:58 +0000</pubDate>
		<guid isPermaLink="false">http://blog.richardknop.com/?p=121#comment-926</guid>
		<description>[...]  [...]</description>
		<content:encoded><![CDATA[<p>[...]  [...]</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Back online &#124; Zend Framework Blog Written By Richard Knop</title>
		<link>http://blog.richardknop.com/2009/05/adjacency-list-model/comment-page-1/#comment-552</link>
		<dc:creator>Back online &#124; Zend Framework Blog Written By Richard Knop</dc:creator>
		<pubDate>Wed, 09 Feb 2011 16:05:13 +0000</pubDate>
		<guid isPermaLink="false">http://blog.richardknop.com/?p=121#comment-552</guid>
		<description>[...] have already drawn new pictures for Adjacency list model and Nested set model posts. They don&#8217;t look quite as good as the previous ones. That&#8217;s [...]</description>
		<content:encoded><![CDATA[<p>[...] have already drawn new pictures for Adjacency list model and Nested set model posts. They don&#8217;t look quite as good as the previous ones. That&#8217;s [...]</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Chusa</title>
		<link>http://blog.richardknop.com/2009/05/adjacency-list-model/comment-page-1/#comment-354</link>
		<dc:creator>Chusa</dc:creator>
		<pubDate>Sun, 27 Dec 2009 23:32:54 +0000</pubDate>
		<guid isPermaLink="false">http://blog.richardknop.com/?p=121#comment-354</guid>
		<description>Perfect!! Thank you</description>
		<content:encoded><![CDATA[<p>Perfect!! Thank you</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Richard Knop</title>
		<link>http://blog.richardknop.com/2009/05/adjacency-list-model/comment-page-1/#comment-347</link>
		<dc:creator>Richard Knop</dc:creator>
		<pubDate>Sat, 12 Dec 2009 17:24:56 +0000</pubDate>
		<guid isPermaLink="false">http://blog.richardknop.com/?p=121#comment-347</guid>
		<description>Yeah that&#039;s an alternative. You can just fetch all rows from the table and do all computing in PHP. I believe there are robust PHP classes floating around the Web with just that purpose.

But when I wrote this I was working on a simple CMS application where the client would hardly ever create more than 1 level of hierarchy (so 4 levels were more than enough). And many applications are like that - with just one or two levels of hierarchy.

If you need unlimited levels then, of course, either use the nested set model or the adjacency list model the way you are suggesting.

Thanks for comments :)</description>
		<content:encoded><![CDATA[<p>Yeah that&#8217;s an alternative. You can just fetch all rows from the table and do all computing in PHP. I believe there are robust PHP classes floating around the Web with just that purpose.</p>
<p>But when I wrote this I was working on a simple CMS application where the client would hardly ever create more than 1 level of hierarchy (so 4 levels were more than enough). And many applications are like that &#8211; with just one or two levels of hierarchy.</p>
<p>If you need unlimited levels then, of course, either use the nested set model or the adjacency list model the way you are suggesting.</p>
<p>Thanks for comments <img src='http://blog.richardknop.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Geoff</title>
		<link>http://blog.richardknop.com/2009/05/adjacency-list-model/comment-page-1/#comment-346</link>
		<dc:creator>Geoff</dc:creator>
		<pubDate>Sat, 12 Dec 2009 15:42:25 +0000</pubDate>
		<guid isPermaLink="false">http://blog.richardknop.com/?p=121#comment-346</guid>
		<description>You&#039;re right, your SQL does work! Sorry about that - In my CMS I have an extra `status` field that I was checking in each table to force only &#039;active&#039; categories to appear.  Even though all my categories are active, the addition of a WHERE clause was throwing it all off. I think if I allow NULL on that column it may work again. Although, the total number of rows, and the order of the rows in the output aren&#039;t what I was hoping for, either. Sigh. 

For what it&#039;s worth, I think @ficuscr was after a PHP function that uses recursion to return a nested structure from a SELECT * scenario like I described in my previous comment. Basically a findChildren( $cat ) method that calls itself to ouput something like:

$cats = array ( 
  &#039;id&#039; =&gt; 1 ,
   &#039;name&#039; =&gt; &#039;Top 1&#039;,
  &#039;children&#039; =&gt; array (
  &#039;id&#039; =&gt; 2, 
  &#039;name&#039; =&gt; &#039;Sub 1&#039;,
&#039;children&#039; =&gt; array( 
  &#039;id&#039; =&gt; 3
  &#039;name&#039; =&gt; &#039;Third 1&#039;,
  &#039;children =&gt; array()
)
)
)

If you have that, then you can use recursive function to output a nested ul li as well. The benefit to using recursive functions is that they&#039;d work to any arbitrary depth.</description>
		<content:encoded><![CDATA[<p>You&#8217;re right, your SQL does work! Sorry about that &#8211; In my CMS I have an extra `status` field that I was checking in each table to force only &#8216;active&#8217; categories to appear.  Even though all my categories are active, the addition of a WHERE clause was throwing it all off. I think if I allow NULL on that column it may work again. Although, the total number of rows, and the order of the rows in the output aren&#8217;t what I was hoping for, either. Sigh. </p>
<p>For what it&#8217;s worth, I think @ficuscr was after a PHP function that uses recursion to return a nested structure from a SELECT * scenario like I described in my previous comment. Basically a findChildren( $cat ) method that calls itself to ouput something like:</p>
<p>$cats = array (<br />
  &#8216;id&#8217; =&gt; 1 ,<br />
   &#8216;name&#8217; =&gt; &#8216;Top 1&#8242;,<br />
  &#8216;children&#8217; =&gt; array (<br />
  &#8216;id&#8217; =&gt; 2,<br />
  &#8216;name&#8217; =&gt; &#8216;Sub 1&#8242;,<br />
&#8216;children&#8217; =&gt; array(<br />
  &#8216;id&#8217; =&gt; 3<br />
  &#8216;name&#8217; =&gt; &#8216;Third 1&#8242;,<br />
  &#8216;children =&gt; array()<br />
)<br />
)<br />
)</p>
<p>If you have that, then you can use recursive function to output a nested ul li as well. The benefit to using recursive functions is that they&#8217;d work to any arbitrary depth.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Geoff</title>
		<link>http://blog.richardknop.com/2009/05/adjacency-list-model/comment-page-1/#comment-345</link>
		<dc:creator>Geoff</dc:creator>
		<pubDate>Sat, 12 Dec 2009 15:19:01 +0000</pubDate>
		<guid isPermaLink="false">http://blog.richardknop.com/?p=121#comment-345</guid>
		<description>I&#039;ve always thought that the easy way out was just doing SELECT * FROM category and passing the result to a PHP class that handles sorting out how everything is nested, having functions to getNestedArray( ), getDepth( $id ) and getParent( $id ) but the SQL purist in me wants to figure out a way to let the DB do as much as it can before PHP takes over.

What I&#039;m looking for is SQL that renders something like this:

1 &#124; Top 1 &#124; Null &#124; Null
2 &#124; Top 1 &#124; Sub 1 &#124; Null
3 &#124; Top 1 &#124; Sub 1 &#124; Third 1
4 &#124; Top 1 &#124; Sub 2 &#124; Null
5 &#124; Top 2 &#124; Null &#124; Null
6 &#124; Top 2 &#124; Sub 3 &#124; Null

... just like you would logically think of how a menu would be constructed.

Great blog, by the way! Lots of really useful stuff here. Keep going.</description>
		<content:encoded><![CDATA[<p>I&#8217;ve always thought that the easy way out was just doing SELECT * FROM category and passing the result to a PHP class that handles sorting out how everything is nested, having functions to getNestedArray( ), getDepth( $id ) and getParent( $id ) but the SQL purist in me wants to figure out a way to let the DB do as much as it can before PHP takes over.</p>
<p>What I&#8217;m looking for is SQL that renders something like this:</p>
<p>1 | Top 1 | Null | Null<br />
2 | Top 1 | Sub 1 | Null<br />
3 | Top 1 | Sub 1 | Third 1<br />
4 | Top 1 | Sub 2 | Null<br />
5 | Top 2 | Null | Null<br />
6 | Top 2 | Sub 3 | Null</p>
<p>&#8230; just like you would logically think of how a menu would be constructed.</p>
<p>Great blog, by the way! Lots of really useful stuff here. Keep going.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Richard Knop</title>
		<link>http://blog.richardknop.com/2009/05/adjacency-list-model/comment-page-1/#comment-344</link>
		<dc:creator>Richard Knop</dc:creator>
		<pubDate>Sat, 12 Dec 2009 15:06:35 +0000</pubDate>
		<guid isPermaLink="false">http://blog.richardknop.com/?p=121#comment-344</guid>
		<description>OK, I just tried it with MyISAM:

CREATE TABLE categories (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
parent_id INT NULL DEFAULT NULL,
INDEX (parent_id),
PRIMARY KEY (id)
) ENGINE = MYISAM;

Then:

INSERT INTO categories (id, name, parent_id) VALUES
(NULL, &#039;Relational databases&#039;, NULL),
(NULL, &#039;SQLite&#039;, 1),
(NULL, &#039;MySQL&#039;, 1),
(NULL, &#039;PostgreSQL&#039;, 1),
(NULL, &#039;PDO&#039;, 3),
(NULL, &#039;Transactions&#039;, 3);

Then:

SELECT t0.id AS lvl0_id, t0.name AS lvl0_name,
t1.id AS lvl1_id, t1.name as lvl1_name,
t2.id AS lvl2_id, t2.name as lvl2_name,
t3.id AS lvl3_id, t3.name as lvl3_name,
t4.id AS lvl4_id, t4.name as lvl4_name
FROM categories AS t0
LEFT JOIN categories AS t1 ON t1.parent_id = t0.id
LEFT JOIN categories AS t2 ON t2.parent_id = t1.id
LEFT JOIN categories AS t3 ON t3.parent_id = t2.id
LEFT JOIN categories AS t4 ON t4.parent_id = t3.id
ORDER BY t0.id, t1.id, t2.id, t3.id, t4.id;

And it works as expected.

Yes, the point of this approach is that it has limited number of levels, so it can only go as deep as the number of levels defined in the SELECT query (I defined 4 levels in this example but you can define 10 or more if you need). But it doesn&#039;t use a recursion which means it is much faster and overall more elegant solution.

If you have a hierarchy with 10+ levels I would advise against using the adjacency list model. In that case use the &lt;a href=&quot;http://blog.richardknop.com/2009/05/nested-set-model/&quot; rel=&quot;nofollow&quot;&gt;nested set model&lt;/a&gt;.</description>
		<content:encoded><![CDATA[<p>OK, I just tried it with MyISAM:</p>
<p>CREATE TABLE categories (<br />
id INT NOT NULL AUTO_INCREMENT,<br />
name VARCHAR(255) NOT NULL,<br />
parent_id INT NULL DEFAULT NULL,<br />
INDEX (parent_id),<br />
PRIMARY KEY (id)<br />
) ENGINE = MYISAM;</p>
<p>Then:</p>
<p>INSERT INTO categories (id, name, parent_id) VALUES<br />
(NULL, &#8216;Relational databases&#8217;, NULL),<br />
(NULL, &#8216;SQLite&#8217;, 1),<br />
(NULL, &#8216;MySQL&#8217;, 1),<br />
(NULL, &#8216;PostgreSQL&#8217;, 1),<br />
(NULL, &#8216;PDO&#8217;, 3),<br />
(NULL, &#8216;Transactions&#8217;, 3);</p>
<p>Then:</p>
<p>SELECT t0.id AS lvl0_id, t0.name AS lvl0_name,<br />
t1.id AS lvl1_id, t1.name as lvl1_name,<br />
t2.id AS lvl2_id, t2.name as lvl2_name,<br />
t3.id AS lvl3_id, t3.name as lvl3_name,<br />
t4.id AS lvl4_id, t4.name as lvl4_name<br />
FROM categories AS t0<br />
LEFT JOIN categories AS t1 ON t1.parent_id = t0.id<br />
LEFT JOIN categories AS t2 ON t2.parent_id = t1.id<br />
LEFT JOIN categories AS t3 ON t3.parent_id = t2.id<br />
LEFT JOIN categories AS t4 ON t4.parent_id = t3.id<br />
ORDER BY t0.id, t1.id, t2.id, t3.id, t4.id;</p>
<p>And it works as expected.</p>
<p>Yes, the point of this approach is that it has limited number of levels, so it can only go as deep as the number of levels defined in the SELECT query (I defined 4 levels in this example but you can define 10 or more if you need). But it doesn&#8217;t use a recursion which means it is much faster and overall more elegant solution.</p>
<p>If you have a hierarchy with 10+ levels I would advise against using the adjacency list model. In that case use the <a href="http://blog.richardknop.com/2009/05/nested-set-model/" rel="nofollow">nested set model</a>.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Geoff</title>
		<link>http://blog.richardknop.com/2009/05/adjacency-list-model/comment-page-1/#comment-343</link>
		<dc:creator>Geoff</dc:creator>
		<pubDate>Sat, 12 Dec 2009 14:56:17 +0000</pubDate>
		<guid isPermaLink="false">http://blog.richardknop.com/?p=121#comment-343</guid>
		<description>I&#039;m using a MyISAM table and I don&#039;t have a foreign key explicitly defined as such; just

CREATE TABLE category ( 
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 
category VARCHAR(100) NOT NULL, 
parent_id INT UNSIGNED NOT NULL , 
INDEX( parent_id ) 
)

but InnoDB &amp; Foreign Key constraints are not required for adjacency SQL? 
Don&#039;t you only get rows that have all 4 levels deep?</description>
		<content:encoded><![CDATA[<p>I&#8217;m using a MyISAM table and I don&#8217;t have a foreign key explicitly defined as such; just</p>
<p>CREATE TABLE category (<br />
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,<br />
category VARCHAR(100) NOT NULL,<br />
parent_id INT UNSIGNED NOT NULL ,<br />
INDEX( parent_id )<br />
)</p>
<p>but InnoDB &amp; Foreign Key constraints are not required for adjacency SQL?<br />
Don&#8217;t you only get rows that have all 4 levels deep?</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Richard Knop</title>
		<link>http://blog.richardknop.com/2009/05/adjacency-list-model/comment-page-1/#comment-341</link>
		<dc:creator>Richard Knop</dc:creator>
		<pubDate>Sat, 12 Dec 2009 14:50:19 +0000</pubDate>
		<guid isPermaLink="false">http://blog.richardknop.com/?p=121#comment-341</guid>
		<description>@Geoff: I just tested it in phpmyadmin and it works fine here. Are you sure your MySQL installation allows InnoDB tables? Because I used the InnoDB format in the CREATE TABLE query. Change that to MyISAM and it should work the same.</description>
		<content:encoded><![CDATA[<p>@Geoff: I just tested it in phpmyadmin and it works fine here. Are you sure your MySQL installation allows InnoDB tables? Because I used the InnoDB format in the CREATE TABLE query. Change that to MyISAM and it should work the same.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Geoff</title>
		<link>http://blog.richardknop.com/2009/05/adjacency-list-model/comment-page-1/#comment-340</link>
		<dc:creator>Geoff</dc:creator>
		<pubDate>Sat, 12 Dec 2009 14:39:09 +0000</pubDate>
		<guid isPermaLink="false">http://blog.richardknop.com/?p=121#comment-340</guid>
		<description>For me, creating the ultimate adjacency model PHP/MySQL solution is one of the holy grail projects I will tackle before I die. The SQL you gave above doesn&#039;t work for me. I get zero rows.  I completely disagree with Richard Knop. Using a recursive function is the ideal way to handle an arbitrarily deep nested set. You ought to be able to make a single query and write a single recursive function that returns a nested array, but I&#039;ve tried many times and it&#039;s a lot harder than it seems. 
 
Here is some alternate SQL that I&#039;ve used in the past but is nowhere near as elegant as the solution I really want to create. It uses MySQL&#039;s WHERE ... IN (  ) and sub-select/subquery syntax to find categories in the top level, then level 1, ... one SQL query per level is required. Each deeper level requires an additional layer in the sub-select, but it&#039;s pretty easy to follow, and each subquery is based on the previous level.

# LEVEL 0 #################################

SELECT
       t0.id as id0,
       t0.name as name0,
FROM category t0
WHERE
       t0.parent_id IS NULL
ORDER BY
       t0.ord

# LEVEL 1 #################################

SELECT
       t1.id as id1,
       t1.parent_id as parent1,
       t1.name as name1,
FROM caegory t1
WHERE
       t1.parent_id IN
       (
               SELECT
                       t0.id as id0
               FROM
                       category t0
               WHERE
                       t0.parent_pid IS NULL
       )
ORDER BY
       t1.ord

# LEVEL 2 #################################

SELECT
       t2.id as id2 ,
       t2.parent_id as parent2 ,
       t2.name as name2
FROM
       category AS t2
WHERE
       t2.parent_id
IN (
       SELECT t1.id as id1
       FROM category  t1
       WHERE  t1.parent_id IN
               (
                       SELECT t0.id as id0
                       FROM category  t0
                       WHERE  t0.parent_id IS NULL
               )
)</description>
		<content:encoded><![CDATA[<p>For me, creating the ultimate adjacency model PHP/MySQL solution is one of the holy grail projects I will tackle before I die. The SQL you gave above doesn&#8217;t work for me. I get zero rows.  I completely disagree with Richard Knop. Using a recursive function is the ideal way to handle an arbitrarily deep nested set. You ought to be able to make a single query and write a single recursive function that returns a nested array, but I&#8217;ve tried many times and it&#8217;s a lot harder than it seems. </p>
<p>Here is some alternate SQL that I&#8217;ve used in the past but is nowhere near as elegant as the solution I really want to create. It uses MySQL&#8217;s WHERE &#8230; IN (  ) and sub-select/subquery syntax to find categories in the top level, then level 1, &#8230; one SQL query per level is required. Each deeper level requires an additional layer in the sub-select, but it&#8217;s pretty easy to follow, and each subquery is based on the previous level.</p>
<p># LEVEL 0 #################################</p>
<p>SELECT<br />
       t0.id as id0,<br />
       t0.name as name0,<br />
FROM category t0<br />
WHERE<br />
       t0.parent_id IS NULL<br />
ORDER BY<br />
       t0.ord</p>
<p># LEVEL 1 #################################</p>
<p>SELECT<br />
       t1.id as id1,<br />
       t1.parent_id as parent1,<br />
       t1.name as name1,<br />
FROM caegory t1<br />
WHERE<br />
       t1.parent_id IN<br />
       (<br />
               SELECT<br />
                       t0.id as id0<br />
               FROM<br />
                       category t0<br />
               WHERE<br />
                       t0.parent_pid IS NULL<br />
       )<br />
ORDER BY<br />
       t1.ord</p>
<p># LEVEL 2 #################################</p>
<p>SELECT<br />
       t2.id as id2 ,<br />
       t2.parent_id as parent2 ,<br />
       t2.name as name2<br />
FROM<br />
       category AS t2<br />
WHERE<br />
       t2.parent_id<br />
IN (<br />
       SELECT t1.id as id1<br />
       FROM category  t1<br />
       WHERE  t1.parent_id IN<br />
               (<br />
                       SELECT t0.id as id0<br />
                       FROM category  t0<br />
                       WHERE  t0.parent_id IS NULL<br />
               )<br />
)</p>
]]></content:encoded>
	</item>
</channel>
</rss>

