Query and modify list of children with arbitrary positions - postgresql

With the following schema in mind:
parent (
parent_id
child_id
)
child (
parent_id
child_id
position
)
I try to design a schema that allows me to retrieve a list of children, where children can be ordered arbitrarily. Adding a child to a parent is the same as appending it to the end of list, with its position equal to the maximum position of all positions for a given parent + 1. One should also be able to re-position a child with respect to its siblings, here, by changing the position columns of multiple child entries. One should also be able to delete a child, with their respective positions staying unchanged.
Querying the children of a given parent according to their position would follow this type of query:
select child.*
from child
where child.parent_id = $1
order by child.position asc;
I wonder whether this sort of schema would be adequate, as any manipulation, whether insertion of a child, or changing the position of a child, becomes quite complicated, as it involves querying/modifying existing records at first. Should we instead place the position data onto the parent table, as an array of some sort?

There are two common ways of modelling hierarchical date in relational database - the adjacency list and the nested set. Joe Celko has an entire book dedicated to this.
Your proposed model is based on the adjacency list. It's intuitive, but often hard to work with - retrieving a hierarchy requires recursive queries, and updates/inserts can be complicated.
The alternative is the nested set - which is much more efficient when querying, and inserts/updates are simpler (though do require more records to be modified).

Related

Sqlalchemy way to handle select based on outdated data

Assuming I have a table sets with a field filters, containing array of key - value mappings, table items to which select query must be applied to extract rows based on these filters, and associated table for M:M relations to link each set with each item. I am seeking for a method or mechanism to cancel select query if sets.filters were updated, otherwise M:M relation will be built invalid as based on yet not refreshed filters.
The concrete scenario when a problem takes place is:
Receive file with items data, to parse, and insert into items returning new relevant ids(primary keys here);
After insertion, select from relevant sets for filters;
Take items ids and select from items using filters;
Update M:M association table for all the items returned at step 3.
So, unfortunately between step 3 and 4 or even earlier, API call makes an update on one of the sets rows, changing its filters. As the result - M:M table is invalid, because one filter was changed(lets say the filters contained kind of weight <= 100 kilos expression, however after the mentioned update it has become weight <= 50 kilos, so if there are some new items with weight greater than 50, those items ids should not be in M:M table, obviously).
Is there some efficient way to cancel select query from items during transaction? Or maybe there is a strong query to use. My idea is to rollback changes post-factum, checking sets.modified_at column. But it seems as doing additional job by wasting disk and cpu time.

insert or update parent id to reference child records on same table

I have a PostgreSQL table in an application that holds both parent and child records. There is a column in the table to reference the the parent id where applicable for each child record. The problem is I am trying to import data from an external source where the child record is made up of a sub number of the parent. eg parent_reference_id = 123456000000 and a child_reference record for this could 123456000001, 123456000002 and so on. The application itself generates a unique id for each record when I import the data and so its possible to import the child and parent records simultaneously, however the difficulty I'm facing is linking the application generated id for the parent record to the parent_reference_id for the corresponding child records. The only hook I have is that the 1st six digits of the child_value_reference match the 1st six digits of the parent_value_reference and I've tried something like foo = bar(left(value,6)||'000000'; to create a match. However, I don't know how to use this to return the unique_id in a meaningful way and update the matching records. I've tried temporary tables and cte, however my knowledge of postgres is limited and I can't seem to find a solution that fits my problem. Another thing to mention is that these groups can change with updates within the external data so i'd also need a solution to make those updates too. Thanks in advance, Crispian

OrientDB query for hierarchical data

OrientDB Server v2.0.10 ,
I am trying to come up with a query for the following scenario.
I have 2 hierarchies: A->B->C and D->E->F
The number of nodes in the hierarchy can change.
The node in 1st hierarchy can be connected to the other hierarchy using some relation say 'Assigned'.
What I want is the parent node of the 2nd hierarchy if there is any incoming edge to any of the node in that 2nd hierarchy from the 1st.
For example, say we have Car-Child->Engine-Child->Piston and Country-Child->State-Child->City
And a relationship Made_In which relates Car or Engine or Piston to either Country or State or City
So if there is a relation with either of Country or State or City, the Country should be returned. Example, Engine1-Made_In->Berlin, this would return Germany.
Sorry for such a toyish example. I hope it is clear.
Thanks.
You should consider reading the chapter about "traversing" - that should be the missing link to answer your question. You can find it here: http://orientdb.com/docs/last/SQL-Traverse.html
Basically, if you think of your graph as a family tree, you want to achieve 3 things:
Find all children, grand-children, grand-grand-children (and so on) from tree 1 for a given family member (=Hierarchy1)
Find those who have relations to members of another family tree (=ASSIGNED)
Show me who's on top of this tree (=Hierarchy2)
One of the possible solutions should look a little something like this:
Since you want to end up on top of hierarchy2, you have to start on the other side, i.e. hierarchy1.
Get hierarchy1 (top-to-bottom)
TRAVERSE out("CHILD") FROM Car
Choose all relations
SELECT out("MADE_IN) FROM ([1])
and from those, go bottom-to-top
TRAVERSE in("CHILD") FROM ([2])
Who's on top?
SELECT FROM ([3]) WHERE #class="Country"
Combined into one sql, it looks as ugly as this:
SELECT FROM (
TRAVERSE in("CHILD") FROM (
SELECT out("MADE_IN") FROM (
TRAVERSE out("CHILD") FROM Car
)
)
) WHERE #class="Country"
You could replace Car with any #rid in hierarchy1 to get a list of countries it or any part of it was made in.
There might be better solutions for sure. But at least this one should work, so I hope it will help.

Swap the order of items in a SQLite database

I retrieve an ordered list of items from a table of items in a Sqlite Database. How can I swap the id so the order of two items in the Sqlite database table?.
The id shouldn't determine position or ordering. It should be an immutable identifier.
If you need to represent order in a database you need to create another orderNumber column. A couple options are (1) either have values that span a range or (2) have a pointer to next (like a linked list).
For ranges: Spanning a range helps you avoid rewriting the orderNumber column for all items after the insert point. For example, in the range, insert first gets 1, insert 2nd gets max range, insert 3rd between first and second gets mid-range number - if you reposition you have to assign mid-points of the items it's between. One downside is if the list gets enough churn (minimized by a large span) you may have to rebalance the ranges. The pro of this solution is you can get the ordered list just by ordering by this column in the sql statement.
For linked list: If the database has a next column that points to the id that's after it in order, you need to update a couple rows to insert something. Upside is it's simple. Downside is you can't order in the sql statement - you're relying on the code getting the list to sort it.
One other variation is you could pull the ordered list data out of that table altogether. For example, you could have an ordered list table that has listid, itemid, orderedNumber. That allows you to have one or multiple logical ordered lists of the items in that table it references.
Some other references:
How to store ordered items which often change position in DB
Best way to save a ordered List to the Database while keeping the ordering
https://dba.stackexchange.com/questions/5683/how-to-design-a-database-for-storing-a-sorted-list

Search Logic removing records with no association from results when ordering by that association

I'm using search logic to filter and order my results but it removes records from my results when I order by a association and when that association is not always present for all records.
For example say I have a user model which can have one vehicle model but does not have to, if I have a results table where you can order by the users vehicles make I would hope all users without a vehicle record would be considered empty strings and therefore ordered all at the beginning followed by the other user records which have vehicles ordered by the make name.
Unfortunately all the user records which do not have a vehicle are removed from the results.
Is there anyway round this and still use search logic as I find it extremely useful
I think you'll have to explicitly assign a default vehicle that has an empty name