Value in one field as lookup from same table - sql

I'm certain this is very easy, but I am very poor at database stuff...
I have the following table in access 2003:
title | id
/root | 1
/root/x | 2
/root/x/y | 3
/root/x/y/z | 4
/root/x/a | 5
/root/x/a/b | 6
i.e. a bunch of nodes and id numbers - you can see that /root/x is the parent of /root/x/y. I'd like to create another table which has a list of all the nodes, along with the id's of their parents. i.e:
id | parent id
1 | -
2 | 1
3 | 2
4 | 3
5 | 2
6 | 5
The follwing will give me the id and the value of the parent:
select id, left(c.title, instrrev(c.title, "/")-1) as parentValue from nodeIDs
yields
id | parentNode
1 |
2 | /root
3 | /root/x
4 | /root/x/y
5 | /root/x
6 | /root/x/a
What is the extra step needed to return the id's of those parent nodes, rather than their values, i.e, return '1' instead of '/root' in that last table?
Many thanks

Something like this perhaps:
select c.id,
left(c.title, instrrev(c.title, "/")-1) as parentValue
, p.id as parentID
from nodeIDs c
left join
nodeIDs p
on left(c.title, instrrev(c.title, "/")-1) = p.title

Something along these lines, I think.
select t1.id,
left(t1.title, instrrev(t1.title, "/")-1) as parentNode,
t2.id as parentID
from nodeIDs t1
inner join nodeIDs t2 on (left(t1.title, instrrev(t1.title, "/")-1)) = t2.title
I don't have any easy way to test this. But the basic idea is that, having derived the title of the parent node, you can do an inner join on it to get the associated id number.

Related

PostgreSQL finding nearest parent value of a certain level

*I apologize, my tables displayed correctly when I was writing this question and after publishing the formatting looks off. trying to fix that now
I am trying to write a query in postgresql that would return, for any given child value, the nearest parent value that has reached a certain rank. Currently, I have this query, which displays the entire hierarchical path for any given child value-
WITH RECURSIVE tree AS (
SELECT "ChildDisplayID",
"ParentID",
"Rank",
1 as level
FROM table1
WHERE "ChildDisplayID" = {{some ChildID}}
UNION ALL
SELECT t1."ChildDisplayID",
t1."ParentID",
t1."Rank",
t.level + 1
FROM table1 t1
JOIN tree t ON t."ParentID" = t1."ChildDisplayID"
)
SELECT *
FROM tree
What I want to do is have in a single row that displays the child ID and the parent ID of the nearest parent whose rank is "Partner". For example, here is the output I am currently getting:
| ChildID | ParentID | Rank | Level |
|---------|----------|------|-------|
| 6 | 5 |Associate Manager| 1 |
| 5 | 4 |Manager| 2 |
| 4 | 3 |Associate Partner| 3 |
| 3 | 2 |Partner| 4 |
| 2 | 1 |Partner| 5 |
| 1 | |CEO| 6 |
Here is the output I want:
|ChildID | Nearest Partner | Rank |
|--------|----------|------|
|6 |3 | Partner |
What is the best way to do this?
You can put a stop condition on the first matching partner in the recursion, then filter the result:
WITH RECURSIVE tree AS (
SELECT "ChildDisplayID" as initialid, "ChildDisplayID", "ParentID", "Rank", 1 as level
FROM table1
WHERE "ChildDisplayID" = {{some ChildID}}
UNION ALL
SELECT t.initialid, t1."ChildDisplayID", t1."ParentID", t1."Rank", t.level + 1
FROM table1 t1
INNER JOIN tree t ON t."ParentID" = t1."ChildDisplayID"
WHERE t."Rank" <> 'Partner'
)
SELECT *
FROM tree
WHERE "Rank" = 'Partner'
It seems like you have a hierarchy where each child has just one parent, so there should be only one match, or no match at all.

Find SQL table rows where there are multiple different values

I want to be able to filter out groups where the values aren't the same. When doing the query:
SELECT
category.id as category_id,
object.id as object_id,
object.value as value
FROM
category,
object
WHERE
category.id = object.category
We get the following results:
category_id | object_id | value
-------------+-----------+-------
1 | 1 | 1
1 | 2 | 2
1 | 3 | 2
2 | 4 | 3
2 | 5 | 2
3 | 6 | 1
3 | 7 | 1
The goal: Update the query so that it yields:
category_id
-------------
1
2
In other words, find the categories where the values are different from the others in that same category.
I have tried many different methods of joining, grouping and so on, to no avail.
I know it can be done with multiple queries and then filter with a little bit of logic, but this is not the goal.
You can use aggregation:
SELECT o.category as category_id
FROM object o
GROUP BY o.category
HAVING MIN(o.value) <> MAX(o.value);
You have left the FROM clause out of your query. But as written, you don't need a JOIN at all. The object table is sufficient -- because you are only fetching the category id.

Flatten tree structure represented in SQL [duplicate]

This question already has an answer here:
SQL Server recursive self join
(1 answer)
Closed 3 years ago.
I'm using an engineering calculation package and trying to extract some information from it in a built in reporting tool that allows SQL query
An abbreviated example SQL tables are as follows:
Id | Description | Ref
---|---------------------
1 | system 1 |
3 | block 4 | 6
3 | block 4 | 1
5 | formula1 | 3
6 | f |
7 | something | 1
9 | cheese | 5
The "Ref" column identifies rows that are subrecords of other items.
What I want to do is run a query that will produce a list that will show all items that appear on a each page. As you can see from the table above "ID" is not the unique key; each item can appear in multiple locations within the table. In the example above:
ID 5 is a subitem of ID3
ID 3 is a subitem of ID 1 AND ID 6
ID 1 and ID 6 aren't subitems of anything
So effectively it is representing a tree structure:
ID 1
+-------- ID 7
|---- ID 3
+---- ID 5
+---- ID 9
ID 6
+---- ID 3
+---- ID 5
+---- ID 9
What I'm hoping to is work out which items appear under each top level item (so the end result should be a table where in the "Ref" column only top level items appear):
Id | Description | Ref
---|---------------------
1 | system 1 |
3 | block 4 | 6
3 | block 4 | 1
5 | formula1 | 1
5 | formula1 | 6
6 | f |
9 | cheese | 1
9 | cheese | 6
7 | something | 1
The tree structure can be a total of 5 levels deep
I've been trying to use left joins to build up a list of page references, but I think I'm also going to need to union results tables (because obviously rows like ID=9, ID=5, and ID = 6 have to be duplicated in the final results set). It starts to get a bit messy!
WITH A
AS (SELECT *
FROM [RbdBlocks]),
B
AS (SELECT [x].[Id],
[x].[Description],
[x].[Page] AS Page1,
[y].[Page] AS Page2,
FROM A AS x
LEFT OUTER JOIN
A AS y
ON y.Id = x.Page)
SELECT *
FROM B
The above gives me some of the nested references, but I'm not sure if there's a better way to get this data together, and to manage the recursion rather than just duplicating the set of queries 4 times?
Have a look at Recursive Common Table Expressions (CTEs). They should be able to accomplish exactly what you need.
Have a look at Example D on the SQL Docs page.
Basically what you'd do in your case is:
In the "anchor member" of the CTE, select all top-level items
In the "recursive member" of the CTE, join all of the nested children to the top-level item
Recursive CTEs are not really trivial to understand, so be sure to read the docs carefully.

Display two linked values for two id field pointing the same table

In my PostgreSQL database I have a table like this one:
id|link1|link2|
---------------
1 | 34 | 66
2 | 23 | 8
3 | 11 | 99
link1 and link2 fields are both pointing to the same table table2 which has id and descr fields.
I would make an SQL query that returns the same row the id and the descr value for the two field like this:
id|link1|link2|desc_l1|desc_l2|
-------------------------------
1 | 34 |66 | bla | sisusj|
2 | 23 | 8 | ghhj | yui |
3 | 11 | 99 | erd | bnbn |
I've try different queries, but everyone returns two rows per id instead of one.
How can I achieve these results in my PostgreSQL 9.04 database?
Normally, this query should work for you. Assume your first table name's table_name.
SELECT t.id, t.link1, t.link2,
l1.descr AS desc_l1,
l2.descr AS desc_l2
FROM table_name t
LEFT JOIN table2 l1
ON t.link1 = l1.id
LEFT JOIN table2 l2
ON t.link2 = l2.id;
you can use case here Like:
select link1,link2,
case
when link1='34' and link2='66' then 'bla'
when link1='23' and link2='8' then 'ghs'
when link1='11' and link2='99' then 'erd'
end as desc_li,
case
when link1='34' and link2='66' then 'sjm'
when link1='23' and link2='8' then 'yur'
when link1='11' and link2='99' then 'bnn'
end as desc_l2
from table1

SQL Server: Select hierarchically related items from one table

Say, I have an organizational structure that is 5 levels deep:
CEO -> DeptHead -> Supervisor -> Foreman -> Worker
The hierarchy is stored in a table Position like this:
PositionId | PositionCode | ManagerId
1 | CEO | NULL
2 | DEPT01 | 1
3 | DEPT02 | 1
4 | SPRV01 | 2
5 | SPRV02 | 2
6 | SPRV03 | 3
7 | SPRV04 | 3
... | ... | ...
PositionId is uniqueidentifier. ManagerId is the ID of employee's manager, referring PositionId from the same table.
I need a SQL query to get the hierarchy tree going down from a position, provided as parameter, including the position itself. I managed to develop this:
-- Select the original position itself
SELECT
'Rank' = 0,
Position.PositionCode
FROM Position
WHERE Position.PositionCode = 'CEO' -- Parameter
-- Select the subordinates
UNION
SELECT DISTINCT
'Rank' =
CASE WHEN Pos2.PositionCode IS NULL THEN 0 ELSE 1+
CASE WHEN Pos3.PositionCode IS NULL THEN 0 ELSE 1+
CASE WHEN Pos4.PositionCode IS NULL THEN 0 ELSE 1+
CASE WHEN Pos5.PositionCode IS NULL THEN 0 ELSE 1
END
END
END
END,
'PositionCode' = RTRIM(ISNULL(Pos5.PositionCode, ISNULL(Pos4.PositionCode, ISNULL(Pos3.PositionCode, Pos2.PositionCode)))),
FROM Position Pos1
LEFT JOIN Position Pos2
ON Pos1.PositionId = Pos2.ManagerId
LEFT JOIN Position Pos3
ON Pos2.PositionId = Pos3.ManagerId
LEFT JOIN Position Pos4
ON Pos3.PositionId = Pos4.ManagerId
LEFT JOIN Position Pos5
ON Pos4.PositionId = Pos5.ManagerId
WHERE Pos1.PositionCode = 'CEO' -- Parameter
ORDER BY Rank ASC
It works not only for 'CEO' but for any position, displaying its subordinates. Which gives me the following output:
Rank | PositionCode
0 | CEO
... | ...
2 | SPRV55
2 | SPRV68
... | ...
3 | FRMN10
3 | FRMN12
... | ...
4 | WRKR01
4 | WRKR02
4 | WRKR03
4 | WRKR04
My problems are:
The output does not include intermediate nodes - it will only output end nodes, i.e. workers and intermediate managers which have no subordinates. I need all intermediate managers as well.
I have to manually UNION the row with original position on top of the output. I there any more elegant way to do this?
I want the output to be sorted in hieararchical tree order. Not all DeptHeads, then all Supervisors, then all Foremen then all workers, but like this:
Rank | PositionCode
0 | CEO
1 | DEPT01
2 | SPRV01
3 | FRMN01
4 | WRKR01
4 | WRKR02
... | ...
3 | FRMN02
4 | WRKR03
4 | WRKR04
... | ...
Any help would be greatly appreciated.
Try a recursive CTE, the example on TechNet is almost identical to your problem I believe:
http://technet.microsoft.com/en-us/library/ms186243(v=sql.105).aspx
Thx, everyone suggesting CTE. I got the following code and it's working okay:
WITH HierarchyTree (PositionId, PositionCode, Rank)
AS
(
-- Anchor member definition
SELECT PositionId, PositionCode,
0 AS Rank
FROM Position AS e
WHERE PositionCode = 'CEO'
UNION ALL
-- Recursive member definition
SELECT e.PositionId, e.PositionCode,
Rank + 1
FROM Position AS e
INNER JOIN HierarchyTree AS d
ON e.ManagerId = d.PositionId
)
SELECT Rank, PositionCode
FROM HierarchyTree
GO
I had a similar problem to yours on a recent project but with a variable recursion length - typically between 1 and 10 levels.
I wanted to simplify the SQL side of things so I put some extra work into the logic of storing the recursive elements by storing a "hierarchical path" in addition to the direct manager Id.
So a very contrived example:
Employee
Id | JobDescription | Hierarchy | ManagerId
1 | DIRECTOR | 1\ | NULL
2 | MANAGER 1 | 1\2\ | 1
3 | MANAGER 2 | 1\3\ | 1
4 | SUPERVISOR 1 | 1\2\4 | 2
5 | SUPERVISOR 2 | 1\3\5 | 3
6 | EMPLOYEE 1 | 1\2\4\6 | 4
7 | EMPLOYEE 2 | 1\3\5\7 | 5
This means you have the power to very quickly query any level of the tree and get all descendants by using a LIKE query on the Hierarchy column
For example
SELECT * FROM dbo.Employee WHERE Hierarchy LIKE '\1\2\%'
would return
MANAGER 1
SUPERVISOR 1
EMPLOYEE 1
Additionally you can also easily get one level of the tree by using the ManagerId column.
The downside to this approach is you have to construct the hierarchy when inserting or updating records but believe me when I say this storage structure saved me a lot of pain later on without the need for unnecessary query complexity.
One thing to note is that my approach gives you the raw data - I then parse the result set into a recursive strongly typed structure in my services layer. As a rule I don't tend to format output in SQL.