Is it possible to get all the parent of a particular role in SQL? - sql

I have a hierarchial (parent-child) role based structure to be used for authorization. I have a simple schema, which stores roles along with the id of their parent. Now I am given a role_id, from which I want to get all the parents of that role.
For example, I have a table like this:
ROLE_ID ROLENAME IS_PARENT PARENT_ROLE_ID
1 1 ABC CORP Y NULL
2 2 ABC EC Y 1
3 3 ABC WC Y 1
4 4 ABC NY Y 2
5 5 ABC OH Y 2
6 6 NY ORTH N 4
7 7 NY CARD N 4
8 8 OH ORTH N 5
9 9 OH CARD N 5
Now, when I am provided with a ROLE_ID of 8, the query should return me:
ROLE_ID
1
2
5
8
Since OH ORTH is a child of ABC OH. ABC OH is a child of ABC EC. ABC EC is a child of ABC CORP, I should get 1,5,2 and 1.
In the above example, there are only 4 levels. But, in actual situation, there might be many levels.
I tried googling solution to this problem and stumbled up here. But this is particular to Oracle, and it gives me syntax error when executing queries on Microsoft SQL Server.
Is this possible? I am using Microsoft SQL server on Microsoft Windows Azure.
I have limited knowledge of SQL. Please help

Yes it's possible. You can use recursive CTE for it.
http://msdn.microsoft.com/en-us/library/ms186243(v=sql.105).aspx
;WITH RCTE AS
(
SELECT ROLE_ID, PARENT_ROLE_ID FROM Table1
WHERE ROLE_ID = 8
UNION ALL
SELECT t.ROLE_ID, t.PARENT_ROLE_ID FROM RCTE r
INNER JOIN Table1 t on r.PARENT_ROLE_ID = t.ROLE_ID
)
SELECT * FROM RCTE
SQLFiddle DEMO

Related

how can I convert this SQL statement with nested IN clauses to a JOIN format

Here are the very simplified versions of my three tables.
Schools_Subjects Table
SchoolId
SubjectId
1
2
5
1
5
6
The above table contains only parent subject IDs.
Subjects Table
SubjectId
Name
ParentSubjectId
1
Science
{NULL}
2
Mathematics
{NULL}
3
Biology
1
4
Physics
1
5
Chemistry
1
6
History
{NULL}
7
Elementary Math
2
8
Calculus
2
Questions Table
QuestionId
Text
SubjectId
1
What is 2 + 2
7
2
Tell me the fastest animal name
3
3
Salt is composed of which two elements
5
4
How to divide 6 apples among 3 students
7
I want to fetch all the questions given a (or multiple) school ID. For example for schoolId:5, I have the below SQL query:
SELECT *
FROM Questions
WHERE SubjectId IN (
SELECT SubjectId
FROM Subjects
WHERE ParentSubjectId IN (
SELECT SubjectId
FROM Schools_Subjects
WHERE SchoolId = 5
)
)
My above query works but I want to change it into a JOIN format query.
I work on SQL Server, but a ANSI-SQL query will be highly appreciated.
If using Mysql:
SELECT Q.*
FROM Questions Q
JOIN (
SELECT S.SubjectId
FROM Subjects S
JOIN Schools_Subjects SS
ON S.ParentSubjectId = SS.SubjectId AND SS.SchoolId = 5
) t1
ON Q.SubjectID = t1.SubjectId
QuestionId Text SubjectId X
1 2 Tell me the fastest animal name 3 NA
2 3 Salt is composed of which two elements 5 NA
Which is the same results produced by your code

How to find the degree of connection in a social network using recursion

Imagine, you are looking at a social network graph of millions of users. Imagine Facebook users who are in different Facebook Groups. Let me give the following example:
We start with Jeff. Jeff has a degree of connection with himself of 0.
Rohit is in the same Facebook group as Jeff, so his degree of connection with Jeff is 1.
Linda is in a facebook group with Rohit, but not in one with Jeff. Her degree connection with Jeff is, therefore 2.
This same phenomenon goes on and on. Now we want to create a query in SQL that can find all users in the user table that have a degree of connection with Jeff of 3 or less. We have the following 2 tables:
user
name
person_id
Jeff
1
Rohit
2
Linda
3
Sid
4
Jin
5
group_in
group_id
person_id
1
1
1
2
2
2
2
3
3
3
3
4
4
4
4
5
What query could find and return all the person_ids and degrees_of_connection for all users with a degrees_of_connection <= 3 with Jeff using just these two tables? The output should show that Jeff, Rohit, Linda, and Sid are all within 3 degrees of connectivity. Whereas Jin would not be included in the results as he is 4 degrees of connection away
You may try the following which uses a recursive cte to find the degree of connection between users. The final projection uses joins to retrieve the respective user names.
WITH user_connections(person_id_1,person_id_2,group_id,no_con) AS (
SELECT
p1.person_id,
p2.person_id ,
p2.group_id ,
case when p2.person_id is null then 0 else 1 end as no_con
from group_in p1
left join group_in p2 on p1.group_id = p2.group_id and p1.person_id < p2.person_id
UNION ALL
SELECT
p1.person_id_1,
p3.person_id,
p3.group_id ,
1+no_con
from user_connections p1
inner join group_in p2 on (
p2.group_id <> p1.group_id and
p2.person_id = p1.person_id_2 and
p1.person_id_2 is not null)
inner join group_in p3 on p3.group_id = p2.group_id and
p3.person_id <> p2.person_id
where no_con < 3
)
SELECT
con_name.person_id,
con_name.name,
uc.no_con as degrees_of_connection
FROM
users u
INNER JOIN user_connections uc ON u.person_id = uc.person_id_1
INNER JOIN users con_name on con_name.person_id = uc.person_id_2
WHERE u.name = 'Jeff';
person_id
name
degrees_of_connection
2
Rohit
1
3
Linda
2
4
Sid
3
Working Demo Fiddle
Let me know if this works for you.

How do I add rows in one table in specific conditions?

I work on an Oracle database.
I have a table (it is a join table) but this is how it looks:
CustomerID days_attached Startdate enddate team
1 7 01-01-2016 08-01-2016 A
1 2 09-01-2016 10-01-2016 B
1 8 01-02-2016 09-02-2016 A
2 1 01-02-2017 02-02-2016 C
2 8 08-05-2017 16-05-2017 C
I need to know how long a person is attached to a specific team. A person can be attached to a person for a X amount of days. That person could be in a team. For instance in this case, how long is a person attached to team A = 7+8 15 days.
How do I get this in a SQL statement?
Our app only supports SQL not PL/sql .
I expect an output like:
CustomerID days_attached team
1 15 A
1 2 B
2 9 C
select customer, team, sum(dayattached) from table_name group by customer, team
hopefully this will help u

inserting sql with loop

I have the table PERSONAL
ID_PERS NAME
---------------
11 azerty
22 uiop
and the table TOURNE_LABEL
ID_TOUR NAME
--------------
1 w
2 p
3 v
I want to loop over all of person and then join it with tourne and insert to a new table.
I have created empty table LS_PDA
ID_PERS ID_TOURN
-------------------
11 1
11 2
11 3
22 1
22 2
22 3
how can I do that ?
SQL is all about set based operations. If you're thinking about a loop, chances are you're heading in the wrong direction. For this problem, you could cross-join the tables, thus producing all the possible combinations, and use the insert-select syntax:
INSERT INTO ls_pda
SELECT id_pres, id_tour
FROM personal
CROSS JOIN tourne_label

linked tables in firebird, discard records that have a specific value in a one to many linked table

I have two tables in a firebird 1.5 database, the tables are client and notes, in the notes table there can be multiple records for each corresponding record in Client table, and sometimes none.
The tables are structured like
Client
Client_id name
-----------------
1 Sam
2 Lee
3 Steve
4 Linda
5 Sue
6 Jill
7 Jack
Notes
Notes_id client_id Note
------------------------------
1 1 New
2 1 do not send
3 2 old
4 2 likes
5 4 do not send
6 5 new
7 5 Cats and Dogs
8 5 drives
I would like to run a select statement that would only return records from the Client table where there is no note named ‘do not send’ linked to the client in the notes table. So with the above examples the select statement would only return the following records from the client table.
Client_id name
-----------------
2 Lee
3 Steve
5 Sue
6 Jill
7 Jack
Is this possible? Any assistance with this would be appreciated.
Regards Alan
Below are three queries that will do the task:
SELECT
c.*
FROM
client c
WHERE
NOT EXISTS(SELECT * FROM notes n WHERE n.client_id = c.client_id
AND n.note = 'do not send')
or
SELECT
c.*, n.client_id
FROM
client.c LEFT JOIN
(SELECT client_id FROM notes WHERE note = 'do not send') n
ON c.client_id = n.client_id
WHERE
n.client_id IS NULL
or
SELECT
c.*
FROM
client c
WHERE
NOT c.client_id IN (SELECT client_id FROM notes n
WHERE n.note = 'do not send')