Next Stored Procedure in MSSQL2005 moves a Node (with all its children) in a left-right tree (Preorder Tree Traversal). It can be moved in the same tree or to another tree. The two tables are what you need to understand the Stored Procedure. The Stored Procedure uses one Function (you can easily copy paste the code from the function into the SP).

treestructures Preorder Tree Traversal (left/right tree) Moving Node by index MSSQL2005

trees Preorder Tree Traversal (left/right tree) Moving Node by index MSSQL2005

sp_movetreestructure :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
/****** 
 * Object:  StoredProcedure [dbo].[sp_MoveTreeStructure]    
 * Script Date: 08/16/2008 19:45:40 
 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[sp_MoveTreeStructure]
	@TreeStructureId INT,		-- TreeStructure (Node) to be moved
	@ParentTreeStructureId INT,	-- Target TreeStructure to be moved to
	@INDEX INT				-- Place where TreeStructure should be moved to
AS
BEGIN
	SET NOCOUNT ON;
 
	SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
 
	DECLARE @TranName VARCHAR(20);
	SELECT @TranName = 'MoveTreeStructure';
 
	BEGIN TRANSACTION @TranName
 
	BEGIN TRY	
 
		DECLARE @OriginalVolume INT
		DECLARE @DiffTarget INT
 
		DECLARE @OriginalLeft INT
		DECLARE @OriginalRight INT
		DECLARE @OriginalTreeId INT
 
		DECLARE @TargetLeft INT
		DECLARE @TargetRight INT
		DECLARE @TargetTreeId INT
		DECLARE @TargetTreeStructureId INT
 
		DECLARE @LastPlace bit
		SET   	@LastPlace = 0
 
		/******************************************************/	
 
		/**
		 * If @ParentTreeStructureId is NULL, we asume that 
		 * movement takes place under the same Folder
		 */
 
			IF (@ParentTreeStructureId IS NULL)
				BEGIN
					SELECT @ParentTreeStructureId = dbo.fn_Edumatic3_GetParentTreeStructure(@TreeStructureId)
				END
 
		/******************************************************/	
 
 
		/**
		 * If Movement is under same ParentTreeStructure and forward, 
		 * then Index needs to be +1
		 * For example, if the first child wants to be moved to 
		 * second place, you would give an index of 1
		 * saying the node wants to be inserted between first 
		 * and second child. Because the moved node is the
		 * first child, it really needs to be inserted between child 2 
		 * and 3. Child 2 will become child 1, the inserted
		 * child (used to be child 1) will become child 2 and child 3 
		 * stays 3. Difficult to explain... Draw it and you'll see.
		 */
 
			IF @ParentTreeStructureId = dbo.fn_Edumatic3_GetParentTreeStructure(@TreeStructureId) 
				AND	@INDEX >= [dbo].[fn_Edumatic3_GetIndexOf](@TreeStructureId)
				BEGIN
					SET @INDEX = @INDEX + 1
				END
 
		/******************************************************/	
 
		/**
		 * Retrieve the original left/right and tree values
		 */
 
			SELECT	@OriginalLeft = LeftValue, @OriginalRight = RightValue, @OriginalTreeId = TreeId
			FROM	TreeStructures 
			WHERE	TreeStructureId = @TreeStructureId
 
		/******************************************************/	
 
		/**
		 * Retrieve the target left/right and tree values. 
		 * Here there's an exception to be caught.
		 * If the node is to be moved to the last place, 
		 * the @TargetTreeStructureId will be -1. We look for the
		 * Node before which the moved node will be inserted. 
		 * In this case there's is no last Node.
		 * If this happens, we take the last Node and insert the 
		 * Node to be moved after this last node instead of before.
		 */
 
			SET @TargetTreeStructureId = dbo.[fn_Edumatic3_GetChildTreeStructure](@ParentTreeStructureId, @INDEX)
 
			IF @TargetTreeStructureId <> -1
				BEGIN
					-- Retrieve the target left/right and tree values
					SELECT	@TargetLeft = LeftValue, 
							@TargetRight = RightValue, 
							@TargetTreeId = TreeId
					FROM	TreeStructures 
					WHERE	TreeStructureId = @TargetTreeStructureId
				END
			ELSE
				BEGIN
					SET @TargetTreeStructureId = dbo.[fn_Edumatic3_GetChildTreeStructure](@ParentTreeStructureId, (@Index-1))
 
					SELECT	@TargetLeft = LeftValue, 
							@TargetRight = RightValue, 
							@TargetTreeId = TreeId
					FROM	TreeStructures 
					WHERE	TreeStructureId = @TargetTreeStructureId
 
					SET   	@LastPlace = 1
				END
 
			SET   	@OriginalVolume = @OriginalRight - @OriginalLeft + 1
 
		/******************************************************/	
 
		/**
		 * Setting the Left and Right Values of TreeStructure 
		 * that needs to be replaced to - Left/Right Value
		 * This needs to be done because these Left and Right 
		 * values may not be changed by queries further down
		 * the road. At the end they are being made positive again. 
		 * Draw some cases if you want this to be clearder to you.
		 */
 
			UPDATE	TreeStructures 
			SET   	LeftValue = -LeftValue,
					RightValue = -RightValue
			WHERE	TreeId = @OriginalTreeId
					AND LeftValue >= @OriginalLeft
					AND RightValue <= @OriginalRight
 
		/******************************************************/	
 
		/**
		 * If the Node is not inserted to the last place, 
		 * then we insert it before the TargetTreeStructure
		 * If it is to be inserted to the last place, 
		 * we insert it after the TargetTreeStructure
		 */
		IF @LastPlace = 0
			BEGIN
				-- Update + volume left/right >= target
				UPDATE	TreeStructures 
				SET   	LeftValue = LeftValue + @OriginalVolume
				WHERE	TreeId = @TargetTreeId 
						AND LeftValue >= @TargetLeft
 
				UPDATE	TreeStructures 
				SET   	RightValue = RightValue + @OriginalVolume  
				WHERE	TreeId = @TargetTreeId 
						AND RightValue >= @TargetLeft
 
				SET   	@DiffTarget = @TargetLeft - @OriginalLeft
			END
		ELSE
			BEGIN
				-- Update + volume left/right >= target
				UPDATE	TreeStructures 
				SET   	LeftValue = LeftValue + @OriginalVolume
				WHERE	TreeId = @TargetTreeId 
						AND LeftValue > @TargetRight
 
				UPDATE	TreeStructures 
				SET   	RightValue = RightValue + @OriginalVolume  
				WHERE	TreeId = @TargetTreeId 
						AND RightValue > @TargetRight
 
				SET   	@DiffTarget = @TargetRight + 1 - @OriginalLeft
			END
 
		/******************************************************/	
 
		/**
		 * For debugging purposes
		 */
 
				--	SELECT	LTRIM(STR(@OriginalVolume)) AS OrignalVolume, 
				--			LTRIM(STR(@OriginalLeft)) AS OriginalLeft,
				--			LTRIM(STR(@OriginalRight)) AS OriginalRight,
				--			LTRIM(STR(@TargetLeft)) AS TargetLeft,
				--			LTRIM(STR(@TargetRight)) AS TargetRight,
				--			LTRIM(STR(@LastPlace)) AS LastPlace,
				--			LTRIM(STR(@Index)) AS [Index],
				--			LTRIM(STR(@DiffTarget)) AS DiffTarget,
				--			LTRIM(STR(@TargetTreeStructureId)) AS TargetTreeStructureId
 
		/******************************************************/
 
		/**
		 * Updating the left and right values of the volume that needs to be transported.
		 * They become non negative again.
		 */
 
			UPDATE	TreeStructures 
			SET   	LeftValue = -LeftValue + @DiffTarget, 
					RightValue = -RightValue + @DiffTarget,
					TreeId = @TargetTreeId
			WHERE	LeftValue <= -@OriginalLeft 
					AND RightValue >= -@OriginalRight 
					AND TreeId = @OriginalTreeId
 
		/******************************************************/
 
		/**
		 * Closing the gap in the original tree (can be the same as target tree)
		 */
 
			UPDATE	TreeStructures 
			SET   	LeftValue = LeftValue - @OriginalVolume
			WHERE	TreeId = @OriginalTreeId
					AND LeftValue > @OriginalRight
 
			UPDATE	TreeStructures 
			SET   	RightValue = RightValue - @OriginalVolume
			WHERE	TreeId = @OriginalTreeId
					AND RightValue > @OriginalRight
 
		/******************************************************/
 
		COMMIT TRANSACTION @TranName
 
		/******************************************************/
 
	END TRY
 
	BEGIN CATCH
 
		/* 	
		 *	If an error occured we Roll Back the transaction 
		 *	and raise an error that VS can catch 
		*/
 
		ROLLBACK TRANSACTION @TranName
		RAISERROR 50001 'Error while trying to move. Rollback has been executed.'
 
		/******************************************************/
	END CATCH
END

fn_edumatic3_getchildtreestructure:
Gets the id of the child node at a give index of a given parent node.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/****** 
 * Object:  UserDefinedFunction [dbo].[fn_GetChildTreeStructure]    
 * Script Date: 08/16/2008 14:03:45 
******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[fn_Edumatic3_GetChildTreeStructure] 
(
	@ParentTreeStructureId INT,
	@INDEX INT
)
RETURNS INT
AS
BEGIN
	DECLARE @TreeStructureId INT
	DECLARE @RightValue INT
	DECLARE @RootLeftValue INT
	DECLARE @RootRightValue INT
	DECLARE @TreeId INT
 
	SELECT	@RootLeftValue = LeftValue, 
			@RootRightValue = RightValue, 
			@TreeId = TreeId
	FROM 	TreeStructures
	WHERE	TreeStructureId = @ParentTreeStructureId
 
	SELECT	@RightValue = RightValue, 
			@TreeStructureId = TreeStructureId 
	FROM 	TreeStructures 
	WHERE	TreeId = @TreeId AND 
			LeftValue = @RootLeftValue + 1
 
	WHILE (@RightValue < (@RootRightValue - 1) AND @INDEX > 0) 
		BEGIN
			SELECT	@RightValue = RightValue, 
					@TreeStructureId = TreeStructureId 
			FROM 	TreeStructures 
			WHERE	TreeId = @TreeId AND 
					LeftValue = @RightValue + 1	
 
			SET   	@INDEX = @INDEX -1	
		END
 
	IF @INDEX <> 0
		-- Either negative index was passed or index was bigger than number of childs
		BEGIN
			SET @TreeStructureId = -1
		END
 
	RETURN @TreeStructureId
 
END
pixel Preorder Tree Traversal (left/right tree) Moving Node by index MSSQL2005
No TweetBacks yet. (Be the first to Tweet this post)