This question already has an answer here:
TSQL A recursive update?
(1 answer)
Closed 9 years ago.
with T1 as
( select tree.* from tree where parent_id = 2
union all
select tree.* from tree
join T1 on (tree.parent_id=T1.id)
)
select * from T1
This query selects all children nodes in a hierarchical tree.
What I need to do is, with all the results returned from the query above, is update a field called [level] by an increment of 1.
I have tried myself with a few permutations but I get errors about not being able to update a derived table
; with T1 as
(
select tree.*
from tree
where parent_id = 2
union all
select tree.*
from tree
join T1
on tree.parent_id=T1.id
)
update tree
set level = level + 1
where id in
(
select id
from t1
)
Related
I have a table 'temp' which has id and its immediate parent's id as columns. The table is as follows:
1
/ \
2 3
/|\ \
4 5 6 7
/
8
Hierarchy of nodes can be represented in tree structure as above.
Now, I want to list all the ancestor or parent nodes of each node present at all levels in pivoted table using recursive cte which has levels (like Level1, Level2 and so on) as its attributes. To get this output, I have calculated all the parent nodes in non pivoted table with level of each node with respect to its parent. The sql query for which is below:
WITH ctetable as
(
SELECT S.id, S.parent, 1 as level
FROM temp as S where S.parent is not null
UNION ALL
SELECT S2.id, p.parent, p.level + 1
FROM ctetable AS p JOIN temp as S2 on S2.parent = p.id
)
SELECT * FROM ctetable ORDER BY id;
The output of above query is shown below:
But, I want to pivot the recursive cte which contains the parent id under at each level of a particular node. Say, for id=4, it should display parent id 4, 2 and 1 under Level3, Level2 and Level1 respectively. For this I wrote the following query:
WITH ctetable as
(
SELECT S.id, S.parent, 1 as level
FROM temp as S where S.parent is not null
UNION ALL
SELECT S2.id, p.parent, p.level + 1
FROM ctetable AS p JOIN temp as S2 on S2.parent = p.id
)
SELECT
myid,
[pn].[1] AS [Level1],
[pn].[2] AS [Level2],
[pn].[3] AS [Level3]
FROM
(
SELECT [a].id,
[a].id as myid,
[a].level
FROM ctetable AS [a]
) AS [hn] PIVOT(max([hn].id) FOR [hn].level IN([1],[2],[3])) AS [pn]
But, the output table is not the desired one as it contains the same id repeated as parent id under each level for a particular node instead it should contain all the parents of that node under various levels. The output i got after executing the above query is shown below:
Can anybody help me out with this....
If you have a known or maximum number of levels, and assuming I did not reverse your desired results.
Also Best if you post sample data and desired results as text, not as an image
Example
Declare #YourTable Table ([id] int,[parent] int)
Insert Into #YourTable Values
(1,null)
,(2,1)
,(3,1)
,(7,3)
,(4,2)
,(5,2)
,(6,2)
,(8,4)
;with cteP as (
Select id
,Parent
,PathID = cast(10000+id as varchar(500))
From #YourTable
Where Parent is Null
Union All
Select id = r.id
,Parent = r.Parent
,PathID = cast(concat(p.PathID,',',10000+r.id) as varchar(500))
From #YourTable r
Join cteP p on r.Parent = p.id)
Select ID
,B.*
From cteP A
Cross Apply (
Select Level1 = xDim.value('/x[1]','int')-10000
,Level2 = xDim.value('/x[2]','int')-10000
,Level3 = xDim.value('/x[3]','int')-10000
,Level4 = xDim.value('/x[4]','int')-10000
,Level5 = xDim.value('/x[5]','int')-10000
From (Select Cast('<x>' + replace(PathID,',','</x><x>')+'</x>' as xml) as xDim) as X
) B
Order By PathID
Returns
EDIT - Added +10000
I added the +10000 so that the sequence will be maintained
I was using below query in sql server to update the table "TABLE" using the same table "TABLE". In sql server the below query is working fine.But in DB2 its getting failed.Not sure whether I need to make any change in this query to work in DB2.
The error I am getting in DB2 is
ExampleExceptionFormatter: exception message was: DB2 SQL Error:
SQLCODE=-204, SQLSTATE=42704
This is my input Data and there you can see ENO 679 is repeating in both round 3 and round 4.
My expected output is given below. Here I am taking the ID and round value from round 4 and updating rownumber 3 with the ID value from rownumber 4.
My requirement is to find the ENO which is exist in both round 3 and round 4 and update the values accordingly.
UPDATE TGT
SET TGT.ROUND = SRC.ROUND,
TGT.ID = SRC.ID
FROM TABLE TGT INNER JOIN TABLE SRC
ON TGT.ROUND='3' and SRC.ROUND='4' and TGT.ENO = SRC.ENO
Could someone help here please. I tried something like this.But its not working
UPDATE TABLE
SET ID = (SELECT t.ID
FROM TABLE t, TABLE t2
WHERE t.ENO = t2.ENO AND t.ROUND= ='4' AND t2.ROUND='3'
) ,
ROUND= (SELECT t.ROUND
FROM TABLE t, TABLE t2
WHERE t.ENO = t2.ENO AND t.ROUND= ='4' AND t2.ROUND='3')
where ROUND='3'
You may try this. I think the issue is you are not relating your inner subquery with outer main table
UPDATE TABLE TB
SET TB.ID = (SELECT t.ID
FROM TABLE t, TABLE t2
WHERE TB.ENO=t.ENO ---- added this
and t.ENO = t2.ENO AND t.ROUND= ='4' AND t2.ROUND='3'
) ,
TB.ROUND= (SELECT t.ROUND
FROM TABLE t, TABLE t2
WHERE TB.ENO=t.ENO --- added this
and t.ENO = t2.ENO AND t.ROUND= ='4' AND t2.ROUND='3')
where tb.ROUND='3'
Try this:
UPDATE MY_SAMPLE TGT
SET (ID, ROUND) = (SELECT ID, ROUND FROM MY_SAMPLE WHERE ENO = TGT.ENO AND ROUND = 4)
WHERE ROUND = 4 AND EXISTS (SELECT 1 FROM MY_SAMPLE WHERE ENO = TGT.ENO AND ROUND = 4);
The difference with yours is that the correlated subquery has to be a row-subselect, it has to guarantee zero or one row (and will assign nulls in case of returning zero rows). The EXISTS subquery excludes rows for which the correlated subquery will not return rows.
This question already has answers here:
Delete duplicate records in SQL Server?
(10 answers)
Closed 6 years ago.
I got the problem that on one table it sometimes makes a double entry. I want to delete the doubled entry. I only want to delete a row when both values are the same than on another row. How is this possible?
My DB structure:
Example for the double entries:
One way to do it is using exists:
DELETE t0
FROM Password_Department t0
WHERE EXISTS
(
SELECT 1
FROM Password_Department t1
WHERE t0.PasswordFK = t1.PasswordFK
AND t0.DepartmentFK = t1.DepartmentFK
AND t0.Id > t1.Id
)
If you prefer the row number method -
delete x
from (
select *,
rn = row_number() over (partition by DepartmentFK, PasswordFK order by Id)
from Password_Department
) x
where rn > 1
After you deleted the duplicate entries, you should add a unique constraint on PasswordFK and DepartmentFK:
ALTER TABLE Password_Department
ADD Constraint UC_Password_Department UNIQUE (PasswordFK , DepartmentFK)
This question already has answers here:
SQL group_concat function in SQL Server [duplicate]
(4 answers)
Closed 8 years ago.
select id, productid, optionid
from tableA
where productid = 1
result (id, productid, optionid)
1 1 1
2 1 2
3 1 5
I would like the result to be (productid, optionids):
1 1,2,5
Naturally, I would think the query below should produce the above result
select productid, optionid
from tableA
group by productid
But what function do I put optionid in?
You can use FOR XML PATH (with some help from STUFF function) to do that. You cannot group as there's sadly no aggregate function for concatenating strings.
select distinct a.productid,
stuff((select ','+cast(s.optionid as varchar(10))
from tableA s
where s.productid = a.productid
for XML path('')),1,1,'')
from tableA a
SQL Fiddle demo
I have an adjacent list hierarchy model that makes up a topic structure
ID Parent_Id Topic_Name
1 Null Topic 1
2 Null Topic 2
3 2 Topic 3
4 3 Topic 4
5 2 Topic 5
6 Null Topic 6
I want to specify a topic id and then copy it to a new topic id at a certain position and retain the levels / structure underneath
So in my example I could specify topic topic_id 2 with pos_id 1 and it would create
ID Parent_Id Topic_Name
1 Null Topic 1
7 Null Topic 2
8 7 Topic 3
9 8 Topic 4
10 7 Topic 5
2 Null Topic 2
3 2 Topic 3
4 3 Topic 4
5 2 Topic 5
6 Null Topic 6
topic_id being the node to copy and pos_id is the node to insert the copy after
Auto numbering is on for the ID, but I can't guarantee that subnodes will always be the next id number up from the parent.
topic_id being the node to copy and pos_id is the node to insert the copy after
I think you can do this in a single statement. Here is the idea.
First, expand the data for all parents (at whatever level) for each id. This uses a recursive CTE.
Then, go back to the original list and choose only those who are descendants of 2.
Then assign a new id to each of the ids found in this group. The following query gets that maximum id and adds a row_number() constant to it.
Then, for each record in the subtree, lookup the new id's in the record, and then insert the results.
The following query takes this approach. I haven't tested it:
with Parents as (
select id, parent_id, 1 as level
from AdjList al
union all
select cte.id, cte.Parent_id, level+1
from AdjList al join
cte
on cte.Parent_id = al.id
),
LookingFor as (
select *
from AdjList
where id in (select id from Parents where id = 2)
),
NewIds as (
select id, const.maxid + ROW_NUMBER() over (order by (select NULL)) as newid
from (select distinct id
from LookingFor
) t cross join
(select MAX(id) as maxid, from AdjList) const
)
insert into AdjList(Id, Parent_id, Topic_Name)
select ni1.newid, coalesce(ni2.NEWID, 1), lf.Topic_Name
from LookingFor lf left outer join
NewIds ni1
on lf.id = ni1.id left outer join
NewIds ni2
on lf.Parent_Id = ni2.id
where ni1.newid is not null
You might want to have a look at Nested Treesets wich would be way better for your purpose I think.
Great explanation here:
http://en.wikipedia.org/wiki/Nested_set_model