| Author |
Topic |
|
crichard1983
Starting Member
11 Posts |
Posted - 2009-11-09 : 11:38:43
|
HiI'm trying to understand why I get this error when trying to update the records returned by a Common Table expression :Derived table 'MB' is not updatable because a column of the derived table is derived or constant.Basically, this is part of the code which will update all the child sections of a root menu item if the section level of the root item is modified.Here is my code :WITH MenuBranch (Id, [Name], Parent, [Level], [Root]) AS( SELECT section_id, name_en, parent_section, section_level, section_id FROM sections WHERE parent_section = 0 UNION ALL SELECT sec.section_id, sec.name_en, sec.parent_section, sec.section_level, [Root] FROM sections sec INNER JOIN MenuBranch ON sec.parent_section = MenuBranch.Id ) UPDATE MB SET [Level] = [Level] + @level_delta FROM (SELECT * FROM MenuBranch WHERE [Root] = @section_id) AS MB; Could anyone please point me in the right direction ? I guess it's the [Root] field in the second select that is posing a problem, but is there an alternative ? Is there an error in my code, or should I place the results in a temp table or use a cursor and the original table instead to execute my updates, and use the CTE only to get the id's of the child sections ?Thank you |
|
|
visakh16
Very Important crosS Applying yaK Herder
52326 Posts |
Posted - 2009-11-09 : 11:41:39
|
| can i ask purpose of updating the level of cte outside? shouldnt that be done in recursive part itself? the error happens because cte has a derived field |
 |
|
|
crichard1983
Starting Member
11 Posts |
Posted - 2009-11-09 : 11:43:52
|
| Thanks for the reply. I'm sorry, this is the first time I've used a CTE. How would I perform the update inside the recursive part. Could you please provide an example ? |
 |
|
|
visakh16
Very Important crosS Applying yaK Herder
52326 Posts |
Posted - 2009-11-09 : 11:46:32
|
| i will do that..but before that can you tell purpose of doing this? |
 |
|
|
crichard1983
Starting Member
11 Posts |
Posted - 2009-11-09 : 11:50:20
|
| I have a table to manage a menu structure for a website.SECTION_IDSECTION_LEVELPARENT_SECTIONetc.I am building a content management system to manage the menu structure.If a person should update the hierarchy of a menu entry, I want all child menus to follow.Ex.JobsAbout UsCF101-Elements-- Army-- Navy-- Air ForceIf I move Elements from under CF101 and move it to be under About Us, I want the Army, Navy and AirForce submenus to follow the Elements menu. Therefore, all their section_level fields must be updated at the same time.I hope this is a clear explanation.Thank you |
 |
|
|
visakh16
Very Important crosS Applying yaK Herder
52326 Posts |
Posted - 2009-11-09 : 11:58:48
|
| yup..for that you dont need this update you just need to update the Elements parent id alone. |
 |
|
|
crichard1983
Starting Member
11 Posts |
Posted - 2009-11-09 : 12:01:11
|
| I'm sorry, I don't understand. Where would I do my update ? Could you post an example please ? Thank you. |
 |
|
|
visakh16
Very Important crosS Applying yaK Herder
52326 Posts |
Posted - 2009-11-09 : 12:07:45
|
| what you need is just to pass id of node under which you want to move Elements and also its id and set its parent as the former id. |
 |
|
|
crichard1983
Starting Member
11 Posts |
Posted - 2009-11-09 : 12:22:20
|
| But how ? That's what I'm trying to do with the above code. Please post a code example. Thank you |
 |
|
|
visakh16
Very Important crosS Applying yaK Herder
52326 Posts |
Posted - 2009-11-09 : 12:31:13
|
| how you decide where you want to move from front end? can you explain the user action part? |
 |
|
|
crichard1983
Starting Member
11 Posts |
Posted - 2009-11-09 : 12:40:38
|
| Select parent of section from a dropdown list. I can email you a screenshot if you want. |
 |
|
|
visakh16
Very Important crosS Applying yaK Herder
52326 Posts |
Posted - 2009-11-09 : 12:44:57
|
ok..so what you need is to pass the id of selected item from dropdown and use a sp likeCREATE PROC changeparent@New_Parent_ID int,@Item_ID intASUPDATE tableSET PARENT_SECTION=@New_Parent_IDWHERE SECTION_ID=@Item_ID |
 |
|
|
crichard1983
Starting Member
11 Posts |
Posted - 2009-11-09 : 13:02:23
|
I know how to do all that. My initial question was regarding the CTE. What the CTE does is return the id's of all the child sections of the section which I am updating the parent for. Since I am updating the parent, all it's children must have their section level adjusted if the new parent is higher up or lower down. The CTE returns all the children IDs. I was hoping to execute an update statement on each of the children as stated in my code above. But I get the error (not updatable). I want to know if I can update a CTE, or if I must use the CTE results in a cursor to run an update on the original table. Here is my full SP for your understanding.ALTER PROCEDURE [dbo].[usp_updatesection] @section_id INT, @parent_section INT, @name_en NVARCHAR(255), @name_fr NVARCHAR(255), @display_order INT, @active BIT, @link_en NVARCHAR(255), @link_fr NVARCHAR(255), @new_page BIT, @parent_changed BITASBEGIN DECLARE @section_level AS INT DECLARE @old_section_level as INT DECLARE @new_section_level as INT DECLARE @level_delta as INT IF @parent_changed = 0 BEGIN IF @parent_section = 0 BEGIN SET @section_level = 1; END ELSE BEGIN SELECT @section_level = section_level + 1 FROM sections WHERE section_id = @parent_section; END BEGIN UPDATE sections SET section_level = @section_level ,parent_section = @parent_section ,name_en = @name_en ,name_fr = @name_fr ,display_order = @display_order ,active = @active ,link_en = @link_en ,link_fr = @link_fr ,new_page = @new_page WHERE section_id = @section_id; END END ELSE BEGIN -- determine section_level delta with new parent SELECT @old_section_level = section_level FROM sections WHERE section_id = @section_id; SELECT @new_section_level = section_level + 1 FROM sections WHERE section_id = @parent_section; SET @level_delta = @new_section_level - @old_section_level; -- find all child sections of this section (recursively for all children) -- update section_level of all children (add delta to current section_level) -- CTE (Common Table Expression : http://blogs.msdn.com/simonince/archive/2007/10/17/hierarchies-with-common-table-expressions.aspx WITH MenuBranch (Id, [Name], Parent, [Level], [Root]) AS ( SELECT section_id, name_en, parent_section, section_level, section_id FROM sections WHERE parent_section = 0 UNION ALL SELECT sec.section_id, sec.name_en, sec.parent_section, section_level, [Root] FROM sections sec INNER JOIN MenuBranch ON sec.parent_section = MenuBranch.Id ) UPDATE MB SET [Level] = [Level] + @level_delta FROM (SELECT * FROM MenuBranch WHERE [Root] = @section_id) AS MB; -- update info of this section IF @parent_section = 0 BEGIN SET @section_level = 1 END ELSE BEGIN SELECT @section_level = section_level + 1 FROM sections WHERE section_id = @parent_section END BEGIN UPDATE sections SET section_level = @section_level ,parent_section = @parent_section ,name_en = @name_en ,name_fr = @name_fr ,display_order = @display_order ,active = @active ,link_en = @link_en ,link_fr = @link_fr ,new_page = @new_page WHERE section_id = @section_id END ENDEND |
 |
|
|
visakh16
Very Important crosS Applying yaK Herder
52326 Posts |
Posted - 2009-11-09 : 13:05:22
|
| you need update original table based on cte recursion to get child nodes |
 |
|
|
crichard1983
Starting Member
11 Posts |
Posted - 2009-11-09 : 13:07:15
|
Ok. I've finally figured it out. Here is the portion of code :WITH MenuBranch (Id, [Name], Parent, [Level], [Root]) AS ( SELECT section_id, name_en, parent_section, section_level, section_id FROM sections WHERE parent_section = 0 UNION ALL SELECT sec.section_id, sec.name_en, sec.parent_section, section_level, [Root] FROM sections sec INNER JOIN MenuBranch ON sec.parent_section = MenuBranch.Id ) UPDATE sections SET section_level = section_level + @level_delta WHERE section_id IN (SELECT section_id FROM MenuBranch WHERE [Root] = @section_id); |
 |
|
|
|