Implement a multi level outline structure - sql

I need to setup and manage a multi level outline structure for requirements management in Microsoft Access 2013.
outline needs to work much like a word outline where each record can have only 1 parent, but can have 1 or more siblings (sibling order does matter) and 0 to many children.
Need to support as many outline levels as possible, current data exceeds 15 levels but is being reduced where possible.
need to be able to determine if a record has children, has siblings, and what is its parent.
need to be able to delete all children of a record when a record is deleted.
need to be able to add new records either after or below a record in the outline structure
need to be able to renumber the outline when adds, deletes, copies, and moves are done within the outline structure.
current approach is a table which contains a unique ID, 15 numeric fields for each individual level # of the outline #, and using a sort of the numeric fields to organize into the outline order.
running into several question related to this situation:
is this the best data structure approach or should I move outline info to a separate table?
given that I am in a query with an outline order sort, can I write a VBA function as a calculated column to determine a record's parent, if it has siblings, and if it has children.
is it possible/practical to perform an sql select in vba to query the same table/query I am in to get a records parent, children, siblings, as a calculated column?
is it possible to use data triggers to support any management of this outline structure.
Example of the outline structure:
1
1.1
1.1.1
1.1.2
1.1.2.1
1.1.2.2
1.1.3
2
2.1
2.2
2.3
2.3.1
2.3.1.1
2.3.1.1.1

This ain't going to be at all trivial in Access. For maximum flexibility in the number of levels I would not use separate fields for the level numbers but would instead have a self-referencing table with columns ID, NodeNumber, OutlineNumber, ParentID (NodeNumber would be a single number indicating which sibling this record is under a given parent - 1, 2, 3 - and OutlineNumber would be the full Outline reference for this record - 1.2.1, 1.2.2, 1.2.3). You would use the ParentID to identify a record's parent; query all records with the same ParentID to find siblings; query records where the ParentID = current record's ID to find children. You're going to have to write some serious VBA code to control inserts, updates and deletes, and definitely don't let people add data manually into the table. Unfortunately Access does not have data triggers.
[EDIT] Apparently I'm wrong! Access does have an equivalent to SQL-Server "trigger" functionality called data macro, but I've never used it. Maybe this could help you?

Related

One to many relationship data addition for multiple level not working properly in MS Access

I have a MS Access application with four levels of one to many relationships. The levels are as below:
Scenario ->> Attractiveness->> Metrics->> Parameters
I have a set of attractiveness, metrics and parameters list all the data are independent. We can map one attractiveness with any number of metrics and for that metrics I need to map parameters. The first higher level is scenario so I am going to create scenarios. So for a scenario we can have only two attractiveness. Then for that two attractiveness user can map any metrics available. In the next level user need to select the parameters for given attractiveness->>Metrics levels.
Please find the below image of my relationship between these tables.
I am using the datasheet view to enter data for each level in a sub form. Please find the below data entry sub form
Please find the below relationship keys:
Scenario Table PK-> (Scenario ID with no Duplicates) -> Attractiveness Table FK ->(Scenario ID with Duplicates)
Attractiveness Table PK ->(Attractiveness ID with no Duplicates) - > Metrics Table FK->(Attractiveness ID with Duplicates)
Metrics Table PK ->(AttractivenessMetrics ID with no Duplicates) - > Parameter Table FK->(AttractivenessMetrics ID with Duplicates)
I can able to add level by level (i.e adding attractiveness, Metrics then update the attID, MetricID, attMetricID in Metric table) then add parameter level is working fine. But if I add parameter without updating the previous metric level then all the parameter are added into the first metric. Since I have no AttractivenessMetrics ID combination in Metrics Table.
I fixed the above issue by using form timer control to keep track of the active control. So while users moving into parameter level updation form metrics level then it will update the metric tables fields this will fix the no parent issues in parameter level. It works well and easy to update the data.

sql single big view vs. union of views

I have a database with a root table, let's call it Study, and several child tables. The Study table has a unique ID and one other field relevant to this question: Study type - this is an enumeration field, there are currently 8 possible study types. Each row is one and only one study type.
I also have 8 views, one for each Study type. Each view has logic to compute a new field called Study name - the logic to compute this field is different for each study type, using different fields from child tables, different lookup tables, etc. This is why the 8 separate views were created.
I now need to create a combined view that has all the rows from the Study table AND for each row also includes the Study name field, which is currently computed in the 8 views depending on study type.
So my question is: what's the best way to do this? Assume I have control over the DB structure, I can create what I need including indexes. The options that come to mind are:
UNION ALL across the 8 views. My worry here is performance, as I will then need to use the combined view to run several reports with their own filters, I'm not sure if indexes from the source tables would be preserved after the union.
Write a single view that combines the logic from the current 8 views into one big view, using CASE statements to execute the correct Study name logic on a row-by-row basis depending on study type.
Something else I haven't thought of? Maybe 8 stored procedures that just compute the 8 different study types, and a single view that calls them?
Thanks -

Table design for hierarchical data

i am trying to design a table which contains sections and each section contains tasks and each task contains sub tasks and so on. I would like to do it under one table. Please let me know the best single table approach which is scalable. I am pretty new to database design. Also please suggest if single table is not the best approach then what could be the best approach to do this. I am using db2.
Put quite simply, I would say use 1 table for tasks.
In addition to all its various other attributes, each task should have a primary identifier, and another column to optionally contain the identifier of its parent task.
If you are using DB2 for z/OS, then you will use a recursive query with a common table expression. Otherwise you you can use a hierarchical recursive query in DB2 for i, or possibly in DB2 for LUW (Linux, Unix, Windows).
Other designs requiring more tables, each specializing in a certain part of the task:subtask relationship, may needlessly introduce issues or limitations.
There are a few ways to do this.
One idea is to use two tables: Sections and Tasks
There could be a one to many relationship between the two. The Task table could be designed as a tree with a TaskId and a ParentTaksId which means you can have Tasks that go n-levels deep (sub tasks of sub tasks og sub tasks etc). Every Task except for the root task will have a parent.
I guess you can also solve this by using a single table where you just add a section column to the Task table I described above.
If you are going to put everything into one table although convenient will be inefficient in the long run. This would mean you will be storing unnecessary repeated groups of data in your database which would not be processor and memory friendly at all. It would in fact violate the Normalization rules and to be more specific the 1st Normal Form which says that there should be no repeating groups that could be found in your table. And it would actually also violate the 3rd Normal Form which means there will be no (transitional) dependency of a non-primary key to another non-primary key.
To give you an illustration, I will put your design into one table. Although I will be guessing on the possible fields but just bear with it because this is for the sake of discussion. Look at the graphics below:
If you look the graphics above (although this is rather small you could download the image and see it closer for yourself), the SectionName, Taskname, TaskInitiator, TaskStartDate and TaskEndDate are unnecessary repeated which as I mentioned earlier a violation of the 1st Normal Form.
Secondly, Taskname, TaskInitiator, TaskStartDate and TaskEndDate are functionally dependent on TaskID which is not a primary key instead of SectionID which in this case should be the primary key (if on a separate table). This is violation of 3rd Normal Form which says that there should be no Transitional Dependence or non-primary key should be dependent on
another non-primary key.
Although there are instances that you have to de-normalized but I believe this one should be normalized. In my own estimation there should be three tables involved in your design, namely, Sections,Tasks and SubTasks that would like the one below.
Section is related to Tasks, that is, a section could have many Tasks.
And Task is related to Sub-Tasks, that is, a Task could have many Sub-tasks.
If I understand correctly the original poster does not know, how many levels of hierarchy will be needed (hence "and so on"). His problem is to create a design that can hold a structure of any depth.
Imho that is a complex issue that does not have a single answer. When implementing such a design you need to count such factors as:
Will the structure be fairly constant? (How many writes?)
How often will this structure be read?
What operations will need to be possible? (Get all children objects of a given object? Get the parent object? Get the direct children?)
If the structure will be constant You could use the nested set model (http://en.wikipedia.org/wiki/Nested_set_model)
In this way the table has a 'left' and 'right' column. The parent object has its left and right column encompasing the values of any of its children object.
In that way you can list all the children of an object using a query like this:
SELECT child.id
FROM table AS parent
JOIN table AS child
ON child.left BETWEEN parent.left AND parent.right
AND child.right BETWEEN parent.left AND parent.right
WHERE
parent.id = #searchId
This design can be VERY fast to read, but is also EXTREMELY costly when the structure changes (for example when adding a child to any object You will have to update any object with a 'right' value that is higher than the inserted one).
If you need to be able to make changes to structure in real time you should probably use a design with two tables - one holding the objects, the second the structure (something like parentId, childId, differenceInHierarchyLevels).

Best Relational DataBase Representation Of Time Bound Hierarchies

What in everyone's opinion is the best representation for a time-bound hierarchy in SQL?
What I mean by this is:
- On any given date you have a normal tree hierarchy
- This hierarchy can change from day to date
- Each child still only has one parent on any given date
Day 1...
Business
|
|-Joe
| |-Happy
| |-Sneezy
| |-Doc(*)
|
|-Moe
|-Bashfull
|-Sleepy
Day 2...
Business
|
|-Joe
| |-Happy
| |-Sneezy
|
|-Moe
|-Doc(*)
|-Bashfull
|-Sleepy
At any time, a child can join the hierarchy for the first time, or leave the hierarchy completely. (For example, new employees, and retired employees.)
The main considerations:
Updating the hierarchy
Viewing the whole hierarchy across a date range
Reporting on whole sub-trees within the hierarchy
Reporting on whole sub-trees across a date range
I know how I do it at present, but am intrigued as to how other people may do it :)
EDIT
I naively assumed a few considerations so will be more explicit...
Each 'team' or 'person' will have a unique ID in a dimension table elsewhere
Other fact tables will use those IDs (storing performance metrics, for example)
The structure needs to facilitate historical reporting across date ranges
Use of ETL or triggers to maintain alternative structures Is an option
The generic nature is most important (forming just one part of a generic relational mode), combined with ease of use for driving report (for any part of the tree across any range of dates) and the ability to be updated reliably.
There are several different books of relevance here - one set is for 'temporal databases', and the other for 'hierarchical structures in RDBMS'.
Snodgrass "Developing Time-Oriented Applications in SQL" (PDF available online at URL)
Date, Darwen and Lorentzos "Temporal Data and the Relational Model"
Celko "Joe Celko's Trees and Hierarchies in SQL for Smarties"
The tricky parts of your question, it seems to me, are:
Viewing the whole hierarchy across a date range
Reporting on whole sub-trees across a date range
The other items are, if not straight-forward, then manageable using the techniques outlined in the books, and along the lines suggested in other answers. Part of the problem is understanding what those two bullet points mean. In one sense, they are 'the same'; the 'whole hierarchy' is just a special case of 'whole sub-trees'. But the deeper question is 'how do you want to demonstrate - visualize, represent - the changes in the hierarchy over time?' Are you seeking to compare the states at the start and end times, or are you seeking to see the intermediate changes too? How do you want to represent the moves of an individual within a hierarchy?
More questions than answers - but I hope the pointers are some help.
A couple of flat tables can work here. For each row, we need columns ID, Name, ParentID, and InactivatedDatetime (which defaults to null). Set the datetime for the old Doc belonging to Joe indicating that that record is no longer valid and move it off to an archive table (for cleanliness), and then create a new row (a near copy of the original row) for a new Doc with Moe's ID as the ParentID. The drawback with this approach is that the person being moved must get a new ID, which may not be convenient.
I can think of a couple of reasonable solutions, depending on how your data is being used and how it changes.
1) Assuming today's hierarchy is the most important. I'd store today's hierarchy with a conventional ParentId column in each record. For previous versions of the hierarchy I'd have a history table of
ItemId, ParentId, ValidFromDate, ValidToDate
Any time the hierarchy changes, you add a new row to the history table.
2) If any/all of the hierarchies are of equal importance, I'd store a base line hierarchy and then implement a hierarchy transaction table.
TransactionId, ItemId, Action (Move/Delete/Add), DateTime, OldParentId, NewParentId
table item(id, ...)
table item_link(parent_item, child_item, from_date, until_date)
The links will store the representation of the tree for a certain time
This structure represents a network instead of a plain hierarchy but it supports moving things in a hierarchy but also look back in time. Some things need to be checked in application logic is to disallow joe being linked at different places in the hierarchy at the sametime.
Reporting is relatively easy with connect by prior clause (in oracle)
Other details can be related to item or even item link if it is to specify additional data on the relation.

How to find all nodes in a subtree in a recursive SQL query?

I have a table which defines a child-parent relationship between nodes:
CREATE TABLE node ( ' pseudo code alert
id INTEGER PRIMARY KEY,
parentID INTEGER, ' should be a valid id.
)
If parentID always points to a valid existing node, then this will naturally define a tree structure.
If the parentID is NULL then we may assume that the node is a root node.
How would I:
Find all the nodes which are decendents of a given node?
Find all the nodes under a given node to a specific depth?
I would like to do each of these as a single SQL (I expect it would necessarily be recursive) or two mutually recursive queries.
I'm doing this in an ODBC context, so I can't rely on any vendor specific features.
Edit
No tables are written yet, so adding extra columns/tables is perfectly acceptable.
The tree will potentially be updated and added to quite often; auxillary data structures/tables/columns would be possible, though need to be kept up-to-date.
If you have any magic books you reach for for this kind of query, I'd like to know.
Many thanks.
This link provides a tutorial on both the Adjacency List Model (as described in the question), and the Nested Set Model. It is written as part of the documentation for MySQL.
What is not discussed in that article is insertion/delection time, and maintenance cost of the two approaches. For example:
a dynamically grown tree using the Nested Set Model would seem to need some maintenance to maintain the nesting (e.g. renumbering all left and right set numbers)
removal of a node in the adjacency list model would require updates in at least one other row.
If you have any magic books you reach for for this kind of query, I'd like to know.
Celko's Trees and Hierarchies in SQL For Smarties
Store the entire "path" from the root node's ID in a separate column, being sure to use a separator at the beginning and end as well. E.g. let's say 1 is the parent of 5, which is the parent of 17, and your separator character is dash, you would store the value -1-5-17- in your path column.
Now to find all children of 5 you can simply select records where the path includes -5-
The separators at the ends are necessary so you don't need to worry about ID's that are at the leftmost or rightmost end of the field when you use LIKE.
As for your depth issue, if you add a depth column to your table indicating the current nesting depth, this becomes easy as well. You look up your starting node's depth and then you add x to it where x is the number of levels deep you want to search, and you filter out records with greater depth than that.