arunatata
asked on
Converting Hierarchical Query from Oracle to MS SQL server 7
Hi,
I found a query that I need to convert to MS SQL server - however I understand that MS SQL does not support the "Decode......" or "Start with.....Connect by" clauses. How can I convert this query then? I am guessing I need to write a SP but have no idea where to begin or how. My query is used to list out all the details of permissions and projects a user has in our system.
This query is written against 3 tables - the first is called table KUser which has the user's details such as name, id, address, email etc. The second is KUserChild which is a recursive/hierarchical table - it relates to itself and has a parent-child relationship - this table has two columns - parentid and childid - the parentid can be a childid and viceversa. The third one is called Projects - which has the listing of the projects and participants. It has the fields P.Name
The query I have is as below:
Select G.ParentID, G.Name as "Group", Decode(P.Name, Null, '',P.Name) as "Project"
from KUser G, Projects P where G.Type=1 or G.Type>=2000
and g.deleted=0 and g.type=P.ProjID(+) and G.ParentID in
(Select ID from KUserChild start with Childid =2547 connect by Prior ParentID=ChildID) order by G.Name,P.Name
Please help.
I found a query that I need to convert to MS SQL server - however I understand that MS SQL does not support the "Decode......" or "Start with.....Connect by" clauses. How can I convert this query then? I am guessing I need to write a SP but have no idea where to begin or how. My query is used to list out all the details of permissions and projects a user has in our system.
This query is written against 3 tables - the first is called table KUser which has the user's details such as name, id, address, email etc. The second is KUserChild which is a recursive/hierarchical table - it relates to itself and has a parent-child relationship - this table has two columns - parentid and childid - the parentid can be a childid and viceversa. The third one is called Projects - which has the listing of the projects and participants. It has the fields P.Name
The query I have is as below:
Select G.ParentID, G.Name as "Group", Decode(P.Name, Null, '',P.Name) as "Project"
from KUser G, Projects P where G.Type=1 or G.Type>=2000
and g.deleted=0 and g.type=P.ProjID(+) and G.ParentID in
(Select ID from KUserChild start with Childid =2547 connect by Prior ParentID=ChildID) order by G.Name,P.Name
Please help.
Hi arunatata,
let's translate this part first :
Select ID from KUserChild start with Childid =2547 connect by Prior ParentID=ChildID
--since "connect by" does not exist in SQL server, i'd emulate this with a user-defined function
--this function retries chid records recursively
create function dbo.ufn_getChildUsers(@use rID int)
returns @t table(userID int, lvl int)
as
begin
declare @lvl int
insert @t values(userID, 1)
while @@rowcount > 0
begin
insert @t select a.ChildID, @lvl1+
from KUserChild a
inner join @t b on a.ParentID = b.ChildID and b.lvl = @lvl
set @lvl = @lvl+1
end
return
end
go
-- to check that it works, try
select * from dbo.ufn_getChildUsers(2547 ) a
--how to use it then
Select G.ParentID, G.Name as Group, Isnull(P.Name, '') as Project
From KUser G
Left Outer Join Projects P On g.type=P.ProjID
where G.Type=1 or G.Type>=2000 and g.deleted=0
and G.ParentID in (select userID from dbo.ufn_getChildUsers(2547 ))
or (better IMHO using a join)
Select G.ParentID, G.Name as Group, Isnull(P.Name, '') as Project
From KUser G
Left Outer Join Projects P On g.type=P.ProjID
Inner join dbo.ufn_getChildUsers(2547 ) U on G.parentID = U.userID
where G.Type=1 or G.Type>=2000 and g.deleted=0
let's translate this part first :
Select ID from KUserChild start with Childid =2547 connect by Prior ParentID=ChildID
--since "connect by" does not exist in SQL server, i'd emulate this with a user-defined function
--this function retries chid records recursively
create function dbo.ufn_getChildUsers(@use
returns @t table(userID int, lvl int)
as
begin
declare @lvl int
insert @t values(userID, 1)
while @@rowcount > 0
begin
insert @t select a.ChildID, @lvl1+
from KUserChild a
inner join @t b on a.ParentID = b.ChildID and b.lvl = @lvl
set @lvl = @lvl+1
end
return
end
go
-- to check that it works, try
select * from dbo.ufn_getChildUsers(2547
--how to use it then
Select G.ParentID, G.Name as Group, Isnull(P.Name, '') as Project
From KUser G
Left Outer Join Projects P On g.type=P.ProjID
where G.Type=1 or G.Type>=2000 and g.deleted=0
and G.ParentID in (select userID from dbo.ufn_getChildUsers(2547
or (better IMHO using a join)
Select G.ParentID, G.Name as Group, Isnull(P.Name, '') as Project
From KUser G
Left Outer Join Projects P On g.type=P.ProjID
Inner join dbo.ufn_getChildUsers(2547
where G.Type=1 or G.Type>=2000 and g.deleted=0
Note on logical operator precedence
AND as a higher precedence then OR in SQL Server, so
where G.Type=1 or G.Type>=2000 and g.deleted=0
is exactly the same than
where G.Type=1 or (G.Type>=2000 and g.deleted=0 )
if it's meant otherwise, you'll have to mak eit more explicit in your code using parens as follows
eg
where (G.Type=1 or G.Type>=2000) and g.deleted=0
AND as a higher precedence then OR in SQL Server, so
where G.Type=1 or G.Type>=2000 and g.deleted=0
is exactly the same than
where G.Type=1 or (G.Type>=2000 and g.deleted=0 )
if it's meant otherwise, you'll have to mak eit more explicit in your code using parens as follows
eg
where (G.Type=1 or G.Type>=2000) and g.deleted=0
ASKER
Hi Hilaire,
Thanks for the response. I have one question - what does the variable lvl do here?
Also it gives me the error "The name UserId is not permitted in this context. Only constants, expressions, or variables are allowed here. Column names are not permitted".
Thanks for the response. I have one question - what does the variable lvl do here?
Also it gives me the error "The name UserId is not permitted in this context. Only constants, expressions, or variables are allowed here. Column names are not permitted".
there was a missing "@" in the first insert and another typo in the second insert
drop function dbo.ufn_getChildUsers
go
create function dbo.ufn_getChildUsers(@use rID int)
returns @t table(userID int, lvl int)
as
begin
declare @lvl int
insert @t values(@userID, 1)
while @@rowcount > 0
begin
insert @t select a.ChildID, @lvl + 1
from KUserChild a
inner join @t b on a.ParentID = b.ChildID and b.lvl = @lvl
set @lvl = @lvl+1
end
return
end
go
as for the @lvl variable,
it's necessary to now the "level of recursion", of, if your prefer, how deep you are in the parent-child relationship.
after the first insert, the level is 1
at the second insert in the returned table, we insert all child records whose father has a level of 1
at the third insert, we insert all child records whose father has a level of 2
this part of the join
" and b.lvl = @lvl"
is to avoid inserting records already inserted in the previous loop.
HTH
Hilaire
drop function dbo.ufn_getChildUsers
go
create function dbo.ufn_getChildUsers(@use
returns @t table(userID int, lvl int)
as
begin
declare @lvl int
insert @t values(@userID, 1)
while @@rowcount > 0
begin
insert @t select a.ChildID, @lvl + 1
from KUserChild a
inner join @t b on a.ParentID = b.ChildID and b.lvl = @lvl
set @lvl = @lvl+1
end
return
end
go
as for the @lvl variable,
it's necessary to now the "level of recursion", of, if your prefer, how deep you are in the parent-child relationship.
after the first insert, the level is 1
at the second insert in the returned table, we insert all child records whose father has a level of 1
at the third insert, we insert all child records whose father has a level of 2
this part of the join
" and b.lvl = @lvl"
is to avoid inserting records already inserted in the previous loop.
HTH
Hilaire
ASKER
Hi Hilaire,
That definitely helped. Thanks for the explanation. However when I run the UDF its only returning one level - the very first thats inserted. What could be going wrong here?
Thanks,
A.
That definitely helped. Thanks for the explanation. However when I run the UDF its only returning one level - the very first thats inserted. What could be going wrong here?
Thanks,
A.
Please post table definition fo the KUserChild table
I'm a bit confused on the relationships
your code has fields ID, ChildUID, ParentID
I kept only childID and parentID, so I might have a wrong join in the 2nd insert
Hilaire
I'm a bit confused on the relationships
your code has fields ID, ChildUID, ParentID
I kept only childID and parentID, so I might have a wrong join in the 2nd insert
Hilaire
ASKER
My mistake - it was a typo in the earlier post - my table has only the fields ParentID and ChildID. There is no third field. The table fields are ParentID, ChildID - both int 4.
ASKER CERTIFIED SOLUTION
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
ASKER
Thanks Hilaire - that worked!!I appreciate all the help you gave me on this query.
Regards,
A.
Regards,
A.
DECODE seems to correspond to COALESCE
[START WITH ... CONNECT BY] seems to equate to a WHERE clause
-- Dan