Managing category structures in relational databases

660 views
615 views

Published on

An introduction to numbered sets

Published in: Technology, Business
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
660
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
17
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Managing category structures in relational databases

  1. 1. Managing category structures in relational databases An introduction to numbered sets Antoine Osanz <antoine@ivt.com.au>
  2. 2. <ul><li>Parent-Child relationships </li></ul><ul><li>Very common in web applications </li></ul><ul><li>Categorise content </li></ul><ul><li>Manage organisation structures </li></ul>Hierarchical Data
  3. 3. Hierarchical Data – A tree Home Theatre Projectors Surround Sound Sub Woofers Satellites Speakers
  4. 4. Common Category Storage <ul><li>“ Adjacency List Model” </li></ul><ul><li>Stores serial of the parent </li></ul>
  5. 5. function getPathDetails( $categorySerial , $pathDetails = array ()) { $sql = &quot;SELECT parentSerial, title FROM adjacentList WHERE categorySerial = '&quot; . $categorySerial . &quot;' LIMIT 0,1&quot; ; $result = $this ->dbase->query( $sql ) ; if ( $result ->numRows() == 1 ) { $row = $result ->fetchAssoc( $result ) ; $pathDetails [] = $row [ 'title' ] ; if ( $row [ 'parentSerial' ] > 0) { $pathDetails = $this ->getPathDetails( $row [ 'parentSerial' ], $pathDetails ) ; } return ( $pathDetails ) ; } else { return ( $pathDetails ) ; } } Projectors: getPathDetails(2); [0] => Projectors [1] => Home Theatre Satellites: getPathDetails(6); [0] => Satellites [1] => Speakers [2] => Surround Sound [3] => Home Theatre‏ Path details: Recursive Function
  6. 6. SELECT level1.title AS lev1Title, level2.title as lev2Title, level3.title as lev3Title, level4.title as lev4Title FROM adjacentList AS level1 LEFT JOIN adjacentList AS level2 ON (level2.parentSerial = level1.categorySerial)‏ LEFT JOIN adjacentList AS level3 ON (level3.parentSerial = level2.categorySerial)‏ LEFT JOIN adjacentList AS level4 ON (level4.parentSerial = level3.categorySerial)‏ WHERE level4.categorySerial = '6'; +--------------+-------------------+--------------+------------+ | lev1Title | lev2Title | lev3Title | lev4Title | +--------------+-------------------+--------------+------------+ | Home Theatre | Surround Sound | Speaker | Satellites | +--------------+-------------------+--------------+------------+ Path details: Self Joins
  7. 7. Too much effort <ul><li>Recursive functions are confusing </li></ul><ul><li>Self joins only good depth is known </li></ul><ul><li>How else can I organise my categories? </li></ul>
  8. 8. The tree again… Home Theatre Projectors Surround Sound Sub Woofers Satellites Speakers
  9. 9. Nested and Numbered Sets
  10. 10. A Numbered Tree Home Theatre Projectors Surround Sound Sub Woofers Satellites Speakers 2 3 4 1 12 5 10 7 9 8 6 11
  11. 11. Storing a Numbered Tree
  12. 12. function getPathDetails( $categorySerial , $pathDetails = array ()) { $sql = &quot;SELECT parent.title FROM productCategories AS node, productCategories AS parent WHERE parent.leftNode <= node.leftNode AND parent.rightNode >= node.rightNode AND node.categorySerial = '&quot; . $categorySerial . &quot;' ORDER BY parent.leftNode DESC&quot; ; $result = $this ->dbase->query( $sql ) ; $pathDetails = array () ; while ( $row = $result ->fetchAssoc( $result )) { $pathDetails [] = $row [ 'title' ] ; } return ( $pathDetails ) ; } Projectors: getPathDetails(2); [0] => Projectors [1] => Home Theatre Satellites: getPathDetails(6); [0] => Satellites [1] => Speakers [2] => Surround Sound [3] => Home Theatre Path details: Revisited
  13. 13. function getDescendants( $categorySerial ) { $sql = &quot;SELECT node.title FROM productCategories AS node, productCategories AS parent WHERE node.leftNode BETWEEN parent.leftNode AND parent.rightNode AND parent.categorySerial = '&quot; . $categorySerial . &quot;' AND node.categorySerial != '&quot;. $categorySerial .&quot;' ORDER BY node.leftNode ASC&quot; ; $result = $this ->dbase->query( $sql ) ; $pathDetails = array () ; while ( $row = $result ->fetchAssoc( $result )) { $pathDetails [] = $row [ 'title' ] ; } return ( $pathDetails ) ; } Speakers: getDescendants(5); [0] => Satellites Surround Sound: getDescendants(3); [0] => Speakers [1] => Satellites [2] => Sub Woofers Getting Category Descendants
  14. 14. START TRANSACTION SELECT @myLeft := leftNode FROM productCategories WHERE categorySerial = '$parentSerial' LIMIT 0,1 UPDATE productCategories SET rightNode = rightNode + 2 WHERE rightNode > @myLeft UPDATE productCategories SET leftNode = leftNode + 2 WHERE leftNode > @myLeft INSERT INTO productCategories SET leftNode = @myLeft + 1, rightNode = @myLeft + 2, title = 'NEW CATEGORY', parentSerial = '$parentSerial' COMMIT Adding Nodes
  15. 15. START TRANSACTION SELECT @myLeft := IF(MAX(rightNode) IS NULL, 0, MAX(rightNode)) FROM productCategories WHERE parentSerial = '0' LIMIT 0,1 INSERT INTO productCategories SET leftNode = @myLeft + 1, rightNode = @myLeft + 2, title = 'NEW CATEGORY', parentSerial = '$parentSerial' COMMIT Adding Primary Nodes
  16. 16. START TRANSACTION SELECT @myLeft := leftNode, @myRight := rightNode, @myWidth := rightNode - leftNode + 1 FROM productCategories WHERE categorySerial = '$categorySerial' LIMIT 0,1&quot;; DELETE FROM productCategories WHERE leftNode BETWEEN @myLeft AND @myRight UPDATE productCategories SET rightNode = rightNode - @myWidth WHERE rightNode > @myRight UPDATE productCategories SET leftNode = leftNode - @myWidth WHERE leftNode > @myLeft COMMIT Delete a node & its children
  17. 17. <ul><li>Less queries to read </li></ul><ul><li>Better handling of large data sets </li></ul><ul><li>Simpler/More readable code </li></ul>Why Bother?
  18. 18. <ul><li>Category Manager </li></ul><ul><li>Access Permissions </li></ul><ul><li>Organisation Structures </li></ul>Current Applications
  19. 19. Thankyou Special thanks to Arjen Lentz, Jonathan Oxer and Mike Hellyer for edumacating me. Questions?

×