SQL Server Forums
Profile | Register | Active Topics | Members | Search | Forum FAQ
 
Register Now and get your question answered!
Username:
Password:
Save Password
Forgot your Password?

 All Forums
 General SQL Server Forums
 Script Library
 Cascading delete and finding table reference level
 New Topic  Reply to Topic
 Printer Friendly
Author Previous Topic Topic Next Topic  

SwePeso
Patron Saint of Lost Yaks

Sweden
30277 Posts

Posted - 02/16/2008 :  13:25:46  Show Profile  Visit SwePeso's Homepage  Reply with Quote
This function will generate all DELETE statements in correct order to perform a CASCADING delete.
For self-joined tables, it will generate the T-SQL code to "unwind" the table, also in correct order!
CREATE FUNCTION dbo.fnCascadingDelete
(
	@Schema NVARCHAR(128) = NULL,
	@Table NVARCHAR(128) = NULL
)
RETURNS	@Return TABLE
	(
		RowID INT PRIMARY KEY CLUSTERED,
		IsSelfJoin TINYINT NOT NULL,
		HasPk TINYINT NOT NULL,
		[SQL] NVARCHAR(4000) NOT NULL
	)
AS
BEGIN
	DECLARE	@Constraints TABLE
		(
			RowID INT NOT NULL,
			Indent SMALLINT NOT NULL,
			[Catalog] NVARCHAR(128) NOT NULL,
			[Schema] NVARCHAR(128) NOT NULL,
			[Table] NVARCHAR(128) NOT NULL,
			[Column] NVARCHAR(128),
			pkCatalog NVARCHAR(128),
			pkSchema NVARCHAR(128),
			pkTable NVARCHAR(128),
			pkColumn NVARCHAR(128),
			pkType NVARCHAR(128),
			pkSize INT,
			IsSelfJoin TINYINT NOT NULL,
			HasPk TINYINT NOT NULL
		)

	INSERT	@Constraints
		(
			RowID,
			Indent,
			[Catalog],
			[Schema],
			[Table],
			[Column],
			pkCatalog,
			pkSchema,
			pkTable,
			pkColumn,
			pkType,
			pkSize,
			IsSelfJoin,
			HasPk
		)
	SELECT	RowID,
		Indent,
		[Catalog],
		[Schema],
		[Table],
		[Column],
		pkCatalog,
		pkSchema,
		pkTable,
		pkColumn,
		pkType,
		pkSize,
		SelfJoin,
		CASE
			WHEN [Column] IS NULL THEN 0
			ELSE 1
		END
	FROM	dbo.fnTableTree(@Schema, @Table)

	IF @@ROWCOUNT = 0
		RETURN

	DECLARE	@SQL TABLE
		(
			ID INT IDENTITY(1, 1),
			RowID INT PRIMARY KEY CLUSTERED,
			IsSelfJoin TINYINT NOT NULL,
			HasPk TINYINT NOT NULL,
			[SQL] NVARCHAR(4000) NOT NULL
		)

	DECLARE	@Indent SMALLINT,
		@RowID INT,
		@ID INT,
		@TSQL NVARCHAR(4000),
		@RowSQL NVARCHAR(4000),
		@EndSQL NVARCHAR(4000),
		@pkColumn NVARCHAR(128),
		@IsSelfJoin TINYINT,
		@HasPk TINYINT

	DECLARE	@Unwind TABLE
		(
			RowID INT NOT NULL,
			StepID INT IDENTITY(0, 1) PRIMARY KEY NONCLUSTERED,
			[SQL] NVARCHAR(4000)
		)

	WHILE NOT EXISTS (SELECT * FROM @SQL WHERE RowID = 1)
		BEGIN
			SELECT TOP 1	@RowID = c.RowID,
					@ID = c.RowID,
					@Indent = c.Indent,
					@TSQL = N'',
					@EndSQL = N'',
					@IsSelfJoin = c.IsSelfjoin,
					@HasPk = c.HasPk
			FROM		@Constraints AS c
			LEFT JOIN	@SQL AS s ON s.RowID = c.RowID
			WHERE		s.RowID IS NULL
			ORDER BY	c.Indent DESC,
					c.RowID DESC

			WHILE @ID > 0
				BEGIN
					IF @Indent = 0
						SELECT	@RowSQL = N'DELETE t' + CAST(@RowID AS NVARCHAR(12)),
							@RowSQL = @RowSQL + N' FROM ' + QUOTENAME(c.[Catalog]) + N'.' + QUOTENAME(c.[Schema]) + N'.' + QUOTENAME(c.[Table]) + N' AS t' + CAST(@ID AS NVARCHAR(12)),
							@EndSQL = N' WHERE t' + CAST(@ID AS NVARCHAR(12)) + '.' + QUOTENAME(COALESCE(c.[Column], '%0')) + N' = ''%1''',
							@IsSelfJoin = @IsSelfJoin | c.IsSelfJoin
						FROM	@Constraints AS c
						WHERE	c.RowID = @ID
					ELSE
						SELECT	@RowSQL = N' INNER JOIN ' + QUOTENAME(c.[Catalog]) + N'.' + QUOTENAME(c.[Schema]) + N'.' + QUOTENAME(c.[Table]),
							@RowSQL = @RowSQL + N' AS t' + CAST(@ID AS NVARCHAR(12)) + N' ON t' + CAST(@ID AS NVARCHAR(12)) + N'.' + QUOTENAME(c.[Column]),
							@pkColumn = QUOTENAME(c.pkColumn),
							@IsSelfJoin = @IsSelfJoin | c.IsSelfJoin
						FROM	@Constraints AS c
						WHERE	c.RowID = @ID

					SELECT TOP 1	@ID = c.RowID,
							@Indent = c.Indent,
							@RowSQL = @RowSQL + N' = t' + CAST(c.RowID AS NVARCHAR(12)) + N'.' + @pkColumn,
							@IsSelfJoin = @IsSelfJoin | c.IsSelfJoin
					FROM		@Constraints AS c
					WHERE		c.RowID < @ID
							AND c.Indent < @Indent
					ORDER BY	c.Indent DESC,
							c.RowID DESC

					IF @@ROWCOUNT = 0
						SET	@ID = 0

					SET	@TSQL = @RowSQL + @TSQL
				END

			INSERT	@SQL
				(
					RowID,
					IsSelfJoin,
					HasPk,
					[SQL]
				)
			VALUES	(
					@RowID,
					@IsSelfJoin,
					@HasPk,
					@TSQL + @EndSQL
				)

			IF @IsSelfJoin = 1
				BEGIN
					DECLARE	@Yak NVARCHAR(160),
						@Catalog NVARCHAR(128),
						@Column NVARCHAR(128)

					SELECT	@Yak  = pkType + COALESCE('(' + CAST(pkSize AS NVARCHAR(12)) + ')', ''),
						@Catalog = [Catalog],
						@Schema = [Schema],
						@Table = [Table],
						@Column = [Column],
						@Catalog = [Catalog],
						@Table = [Table],
						@pkColumn = pkColumn
					FROM	@Constraints
					WHERE	RowID = @RowID

SET	@RowSQL = 'DECLARE	@Lvl INT
SET	@Lvl = 0
DECLARE	@Stage TABLE (RowID INT IDENTITY(0, 1), Lvl INT, RowKey ' + @Yak + ')
INSERT @Stage (Lvl, RowKey) '
+ REPLACE(@TSQL + @EndSQL, 'DELETE t' + CAST(@RowID AS NVARCHAR(12)) + '', 'SELECT 0, t' + CAST(@RowID AS NVARCHAR(12)) + '.' + QUOTENAME(@Column) + '')
+ ' WHILE @@ROWCOUNT > 0
	BEGIN
		SET	@Lvl = @Lvl + 1

		INSERT		@Stage  (Lvl, RowKey)
		SELECT		@Lvl,
				t.' + QUOTENAME(@pkColumn) + '
		FROM		' + QUOTENAME(@Catalog) + '.' + QUOTENAME(@Schema) + '.' + QUOTENAME(@Table) + ' AS t
		INNER JOIN	@Stage AS s ON s.RowKey = t.' + QUOTENAME(@Column) + '
					AND s.Lvl = @Lvl - 1
		LEFT JOIN	@Stage AS cr ON cr.RowKey = t.' + QUOTENAME(@pkColumn) + '
		WHERE		cr.RowKey IS NULL
	END
SELECT ''DELETE FROM ' + QUOTENAME(@Catalog) + '.' + QUOTENAME(@Schema) + '.' + QUOTENAME(@Table) + ' WHERE ' + QUOTENAME(@pkColumn) + ' = '' + QUOTENAME(RowKey, '''''''')
FROM @Stage
WHERE RowID > 0
ORDER BY RowID DESC'

				INSERT	@Unwind
					(
						RowID,
						[SQL]
					)
				VALUES	(
						@RowID,
						@RowSQL
					)
				END
		END

	INSERT		@Return
			(
				RowID,
				IsSelfJoin,
				HasPk,
				[SQL]
			)
	SELECT		s.ID,
			s.IsSelfJoin,
			s.HasPk,
			CASE
				WHEN u.RowID IS NULL THEN s.[SQL]
				ELSE u.[SQL]
			END
	FROM		@SQL AS s
	LEFT JOIN	@Unwind AS u ON u.RowID = s.RowID
	ORDER BY	s.ID,
			u.StepID

	RETURN
END

E 12°55'05.25"
N 56°04'39.16"

Edited by - SwePeso on 02/18/2008 11:47:17

SwePeso
Patron Saint of Lost Yaks

Sweden
30277 Posts

Posted - 02/16/2008 :  13:26:44  Show Profile  Visit SwePeso's Homepage  Reply with Quote
And the "master" function here (which can be run individually to find table reference levels)
CREATE FUNCTION dbo.fnTableTree
(
	@Schema NVARCHAR(128) = NULL,
	@Table NVARCHAR(128) = NULL
)
RETURNS	@Tree TABLE
	(
		RowID INT IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
		Indent SMALLINT NOT NULL,
		[Catalog] NVARCHAR(128) NOT NULL,
		[Schema] NVARCHAR(128) NOT NULL,
		[Table] NVARCHAR(128) NOT NULL,
		[Column] NVARCHAR(128),
		[Type] NVARCHAR(128),
		[Size] INT,
		pkCatalog NVARCHAR(128),
		pkSchema NVARCHAR(128),
		pkTable NVARCHAR(128),
		pkColumn NVARCHAR(128),
		pkType NVARCHAR(128),
		pkSize INT,
		SelfJoin TINYINT NOT NULL
	)
AS
BEGIN
	DECLARE	@Temp TABLE
		(
			TempID INT IDENTITY(0, 1) PRIMARY KEY NONCLUSTERED,
			TempKey VARBINARY(8000),
			Indent SMALLINT,
			ConstraintID INT
		)

	DECLARE	@Constraints TABLE
		(
			ConstraintID INT IDENTITY(0, 1) PRIMARY KEY CLUSTERED,
			SelfJoin TINYINT NOT NULL DEFAULT 0,
			pkCatalog NVARCHAR(128) NOT NULL DEFAULT N'',
			pkSchema NVARCHAR(128) NOT NULL DEFAULT N'',
			pkTable NVARCHAR(128) NOT NULL DEFAULT N'',
			pkColumn NVARCHAR(128),
			pkType NVARCHAR(128),
			pkSize INT,
			fkCatalog NVARCHAR(128) NOT NULL,
			fkSchema NVARCHAR(128) NOT NULL,
			fkTable NVARCHAR(128) NOT NULL,
			fkColumn NVARCHAR(128),
			fkType NVARCHAR(128),
			fkSize INT
		)

	INSERT		@Constraints
			(
				fkCatalog,
				fkSchema,
				fkTable,
				fkColumn
			)
	SELECT		t.TABLE_CATALOG,
			t.TABLE_SCHEMA,
			t.TABLE_NAME,
			ccu.COLUMN_NAME
	FROM		INFORMATION_SCHEMA.TABLES AS t
	LEFT JOIN	INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc ON tc.TABLE_CATALOG = t.TABLE_CATALOG
				AND tc.TABLE_SCHEMA = t.TABLE_SCHEMA
				AND tc.TABLE_NAME = t.TABLE_NAME
				AND tc.CONSTRAINT_TYPE = 'PRIMARY KEY'
	LEFT JOIN	INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS ccu ON ccu.CONSTRAINT_CATALOG = tc.CONSTRAINT_CATALOG
				AND ccu.CONSTRAINT_SCHEMA = tc.CONSTRAINT_SCHEMA
				AND ccu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
	WHERE		t.TABLE_TYPE = 'BASE TABLE'
			AND OBJECTPROPERTY(OBJECT_ID(t.TABLE_CATALOG + N'.' + t.TABLE_SCHEMA + N'.' + t.TABLE_NAME), 'IsMSShipped') = 0
			AND (@Schema IS NULL OR @Schema = t.TABLE_SCHEMA)
			AND (@Table IS NULL OR @Table = t.TABLE_NAME)
	ORDER BY	t.TABLE_CATALOG,
			t.TABLE_SCHEMA,
			t.TABLE_NAME

	INSERT		@Temp
			(
				Indent,
				ConstraintID
			)
	SELECT		0,
			ConstraintID
	FROM		@Constraints
	ORDER BY	ConstraintID

	INSERT		@Constraints
			(
				SelfJoin,
				pkCatalog,
				pkSchema,
				pkTable,
				pkColumn,
				pkType,
				pkSize,
				fkCatalog,
				fkSchema,
				fkTable,
				fkColumn,
				fkType,
				fkSize
			)
	SELECT		CASE
				WHEN pk.TABLE_CATALOG = fk.TABLE_CATALOG AND pk.TABLE_SCHEMA = fk.TABLE_SCHEMA AND pk.TABLE_NAME = fk.TABLE_NAME THEN 1
				ELSE 0
			END,
			pk.TABLE_CATALOG,
			pk.TABLE_SCHEMA,
			pk.TABLE_NAME,
			pk.COLUMN_NAME,
			pt.DATA_TYPE,
			pt.CHARACTER_MAXIMUM_LENGTH,
			fk.TABLE_CATALOG,
			fk.TABLE_SCHEMA,
			fk.TABLE_NAME,
			fk.COLUMN_NAME,
			ft.DATA_TYPE,
			ft.CHARACTER_MAXIMUM_LENGTH
	FROM		INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS rc
	INNER JOIN	INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS pk ON pk.CONSTRAINT_CATALOG = rc.UNIQUE_CONSTRAINT_CATALOG
				AND pk.CONSTRAINT_SCHEMA = rc.UNIQUE_CONSTRAINT_SCHEMA
				AND pk.CONSTRAINT_NAME = rc.UNIQUE_CONSTRAINT_NAME
	INNER JOIN	INFORMATION_SCHEMA.COLUMNS AS pt ON pt.TABLE_CATALOG = pk.TABLE_CATALOG
				AND pt.TABLE_SCHEMA = pk.TABLE_SCHEMA
				AND pt.TABLE_NAME = pk.TABLE_NAME
				AND pt.COLUMN_NAME = pk.COLUMN_NAME
	INNER JOIN	INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS fk ON fk.CONSTRAINT_CATALOG = rc.CONSTRAINT_CATALOG
				AND fk.CONSTRAINT_SCHEMA = rc.CONSTRAINT_SCHEMA
				AND fk.CONSTRAINT_NAME = rc.CONSTRAINT_NAME
	INNER JOIN	INFORMATION_SCHEMA.COLUMNS AS ft ON ft.TABLE_CATALOG = fk.TABLE_CATALOG
				AND ft.TABLE_SCHEMA = fk.TABLE_SCHEMA
				AND ft.TABLE_NAME = fk.TABLE_NAME
				AND ft.COLUMN_NAME = fk.COLUMN_NAME
	ORDER BY	pk.TABLE_CATALOG,
			pk.TABLE_SCHEMA,
			pk.TABLE_NAME,
			pk.COLUMN_NAME,
			fk.TABLE_CATALOG,
			fk.TABLE_SCHEMA,
			fk.TABLE_NAME,
			fk.COLUMN_NAME

	UPDATE	@Temp
	SET	TempKey = CAST(TempID AS VARBINARY(4))

	DECLARE	@Indent SMALLINT

	SET	@Indent = 0

	WHILE @Indent < 2000 AND @@ROWCOUNT > 0 OR @Indent = 0
		BEGIN
			SET	@Indent = @Indent + 1

			INSERT		@Temp
					(
						TempKey,
						Indent,
						ConstraintID
					)
			SELECT		t.TempKey,
					@Indent,
					fk.ConstraintID
			FROM		@Temp AS t
			INNER JOIN	@Constraints AS pk ON pk.ConstraintID = t.ConstraintID
			INNER JOIN	@Constraints AS fk ON fk.pkCatalog = pk.fkCatalog
						AND fk.pkSchema = pk.fkSchema
						AND fk.pkTable = pk.fkTable
			WHERE		t.Indent = @Indent - 1
					AND NOT	(
							pk.pkCatalog = pk.fkCatalog
							AND pk.pkSchema = pk.fkSchema
							AND pk.pkTable = pk.fkTable
						)
			ORDER BY	fk.ConstraintID

			UPDATE	@Temp
			SET	TempKey = TempKey + CAST(TempID AS VARBINARY(4))
			WHERE	Indent = @Indent
		END

	INSERT		@Tree
			(
				Indent,
				SelfJoin,
				[Catalog],
				[Schema],
				[Table],
				[Column],
				[Type],
				[Size],
				pkCatalog,
				pkSchema,
				pkTable,
				pkColumn,
				pkType,
				pkSize
			)
	SELECT		t.Indent,
			c.SelfJoin,
			c.fkCatalog,
			c.fkSchema,
			c.fkTable,
			c.fkColumn,
			c.fkType,
			c.fkSize,
			NULLIF(c.pkCatalog, N''),
			NULLIF(c.pkSchema, N''),
			NULLIF(c.pkTable, N''),
			c.pkColumn,
			c.pkType,
			c.pkSize
	FROM		@Temp AS t
	INNER JOIN	@Constraints AS c ON c.ConstraintID = t.ConstraintID
	ORDER BY	t.TempKey,
			t.Indent

	RETURN
END

E 12°55'05.25"
N 56°04'39.16"

Edited by - SwePeso on 02/18/2008 10:40:42
Go to Top of Page

harsh_athalye
Flowing Fount of Yak Knowledge

India
5581 Posts

Posted - 02/18/2008 :  10:41:15  Show Profile  Visit harsh_athalye's Homepage  Click to see harsh_athalye's MSN Messenger address  Send harsh_athalye a Yahoo! Message  Reply with Quote
Peter,

This is really great function! But I had one suggestion. This function generates Delete statements equal to Number of FKs + 1. In some cases, this is not really required.

Consider for example the below sample script:

create table Test1
(
	a int primary key,
	b int constraint fk_test1 foreign key references Test1(a)
)

create table Test2
(
	a int primary key,
	b int constraint fk_test2 foreign key references Test1(a)
)

create table Test3
(
	a int primary key,
	b int constraint fk1_test3 foreign key references Test1(a),
	c int constraint fk2_test3 foreign key references Test2(a),
)


Here as can be seen Test3 has no incoming foreign key references hence it is an ideal candidate to start the deletion with.

Your function generates DELETE statements in correct order:

DELETE t4 FROM [Test].[dbo].[test1] AS t1 INNER JOIN [Test].[dbo].[test2] AS t3 ON t3.[b] = t1.[a] INNER JOIN [Test].[dbo].[test3] AS t4 ON t4.[c] = t3.[a] WHERE t1.[a] = '%1'

DELETE t5 FROM [Test].[dbo].[test1] AS t1 INNER JOIN [Test].[dbo].[test3] AS t5 ON t5.[b] = t1.[a] WHERE t1.[a] = '%1'

DELETE t3 FROM [Test].[dbo].[test1] AS t1 INNER JOIN [Test].[dbo].[test2] AS t3 ON t3.[b] = t1.[a] WHERE t1.[a] = '%1'

DELETE t2 FROM [Test].[dbo].[test1] AS t1 INNER JOIN [Test].[dbo].[test1] AS t2 ON t2.[b] = t1.[a] WHERE t1.[a] = '%1'

DELETE t1 FROM [Test].[dbo].[test1] AS t1 WHERE t1.[a] = '%1'


But in fact only 3 DELETEs are sufficient here:

Delete t3
From Test3 t3 JOIN Test1 t1 ON t3.b = t1.a
join Test2 t2 ON t3.c = t2.a
Where t3.a like '%1'

Delete t2
From Test2 t2 JOIN Test1 t1 ON t2.b = t1.a
Where t1.a like '%1'

Delete t1
From Test1 t1
Where t1.a like '%1'


Also, I could not understand why WHERE part is always applied to TEST1 and not any other table?

Harsh Athalye
India.
"The IMPOSSIBLE is often UNTRIED"

Edited by - harsh_athalye on 02/18/2008 10:41:41
Go to Top of Page

SwePeso
Patron Saint of Lost Yaks

Sweden
30277 Posts

Posted - 02/18/2008 :  10:44:59  Show Profile  Visit SwePeso's Homepage  Reply with Quote
Try the latest functions I just posted.
It has a column "HasPk" to tell if Pk is present.



E 12°55'05.25"
N 56°04'39.16"
Go to Top of Page

harsh_athalye
Flowing Fount of Yak Knowledge

India
5581 Posts

Posted - 02/18/2008 :  10:53:14  Show Profile  Visit harsh_athalye's Homepage  Click to see harsh_athalye's MSN Messenger address  Send harsh_athalye a Yahoo! Message  Reply with Quote
Peter,

There seems to be some coding error in fnCascadingDelete() function.
One of the code block included in this function's output was this:

DECLARE @Lvl INT  
SET @Lvl = 0  
DECLARE @Stage TABLE (RowID INT IDENTITY(0, 1), Lvl INT, RowKey int)  
INSERT @Stage (Lvl, RowKey) 
SELECT 0, t2.[b] 
FROM [Test].[dbo].[test1] AS t1 INNER JOIN [Test].[dbo].[test1] AS t2 
ON t2.[b] = t1.[a] 
WHERE t1.[a] = '%1' 

WHILE @@ROWCOUNT > 0   
BEGIN    
	SET @Lvl = @Lvl + 1      
	INSERT  @Stage  (Lvl, RowKey)    
	SELECT  @Lvl, t.ID    
	FROM  [Test].[dbo].[Table2] AS t INNER JOIN @Stage AS s ON s.RowKey = t.ParentID       
	AND s.Lvl = @Lvl - 1    
	LEFT JOIN @Stage AS cr ON cr.RowKey = t.ID    
	WHERE  cr.RowKey IS NULL   
END    

SELECT 'DELETE FROM [Test].[dbo].[Table2] WHERE [ID] = ' + QUOTENAME(RowKey, '''') + ''  FROM @Stage  ORDER BY RowID DESC



But this table2 does not exist in the database!

Harsh Athalye
India.
"The IMPOSSIBLE is often UNTRIED"
Go to Top of Page

SwePeso
Patron Saint of Lost Yaks

Sweden
30277 Posts

Posted - 02/18/2008 :  10:54:34  Show Profile  Visit SwePeso's Homepage  Reply with Quote
I see...
They are residues from my development environment. I will replace hard-coded names with dynamic names in a while.
Be patient!

Done!


E 12°55'05.25"
N 56°04'39.16"

Edited by - SwePeso on 02/18/2008 11:12:15
Go to Top of Page

harsh_athalye
Flowing Fount of Yak Knowledge

India
5581 Posts

Posted - 02/18/2008 :  11:23:37  Show Profile  Visit harsh_athalye's Homepage  Click to see harsh_athalye's MSN Messenger address  Send harsh_athalye a Yahoo! Message  Reply with Quote
Still there is some hard-coding which should be removed:

WHILE @@ROWCOUNT > 0   
BEGIN    
SET @Lvl = @Lvl + 1      
INSERT  @Stage  (Lvl, RowKey)    
SELECT  @Lvl,      t.ID    
FROM  [Test].[dbo].[test1] AS t    INNER JOIN @Stage AS s 
ON s.RowKey = t.ParentID AND s.Lvl = @Lvl - 1    
LEFT JOIN @Stage AS cr ON cr.RowKey = t.ID    
WHERE  cr.RowKey IS NULL   
END




Harsh Athalye
India.
"The IMPOSSIBLE is often UNTRIED"
Go to Top of Page

SwePeso
Patron Saint of Lost Yaks

Sweden
30277 Posts

Posted - 02/18/2008 :  11:36:40  Show Profile  Visit SwePeso's Homepage  Reply with Quote
Fixed.
Also fixed bug with misprinted output when executing the code.
quote:
Originally posted by harsh_athalye

SELECT 'DELETE FROM [Test].[dbo].[Table2] WHERE [ID] = ' + QUOTENAME(RowKey, '''') + ''  FROM @Stage  ORDER BY RowID DESC




E 12°55'05.25"
N 56°04'39.16"

Edited by - SwePeso on 02/18/2008 11:39:24
Go to Top of Page

p3tar
Starting Member

Croatia
4 Posts

Posted - 03/12/2008 :  00:05:23  Show Profile  Reply with Quote
Hi all.

I have a problem executing this function, error - Incorrect syntax near '%'. Do I need to replace "%1" in generated @SQL. An example of usage would be appreciated.

Thanks

Edited by - p3tar on 03/12/2008 00:07:24
Go to Top of Page

SwePeso
Patron Saint of Lost Yaks

Sweden
30277 Posts

Posted - 03/12/2008 :  02:26:03  Show Profile  Visit SwePeso's Homepage  Reply with Quote
Yes, you should replace '%1' with the value needed for your environment.
If you want to delete EmployeeID 245, replace %1 with 245.



E 12°55'05.25"
N 56°04'39.16"
Go to Top of Page

p3tar
Starting Member

Croatia
4 Posts

Posted - 03/12/2008 :  18:13:14  Show Profile  Reply with Quote
Thanks, I'm not good with string manipulation and dynamic sql. How should I replace it? With REPLACE() function or should I use Exec sp_executesql.....Thanks again

Edited by - p3tar on 03/12/2008 18:17:51
Go to Top of Page

SwePeso
Patron Saint of Lost Yaks

Sweden
30277 Posts

Posted - 03/13/2008 :  02:26:41  Show Profile  Visit SwePeso's Homepage  Reply with Quote
first replace and then either
exec
sp_executesql



E 12°55'05.25"
N 56°04'39.16"
Go to Top of Page

p3tar
Starting Member

Croatia
4 Posts

Posted - 03/13/2008 :  12:00:35  Show Profile  Reply with Quote
I have another problem, when I select SQL from cascading delete function for the table with four FKs relationships I get the correct SQL with the four delete statements, but when I assign that SQL to a variable so I can execute it later on I get only one delete statement for the main table.

WORKS:

SELECT SQL
FROM dbo.fnCascadingDelete ('dbo', 'SomeTable')

Result:
DELETE t4 FROM [DB].[dbo].[SomeTable] AS t1 INNER JOIN
[DB].[dbo].[ReferencingTable1] AS t4 ON t4.[ID] = t1.[ID] WHERE
t1.[ID] = '%1'
DELETE t3 FROM [DB].[dbo].[SomeTable] AS t1 INNER JOIN
[DB].[dbo].[ReferencingTable2] AS t3 ON t3.[ID] = t1.[ID] WHERE
t1.[ID] = '%1'
DELETE t2 FROM [DB].[dbo].[SomeTable] AS t1 INNER JOIN
[DB].[dbo].[ReferencingTable3] AS t2 ON t2.[ID] = t1.[ID] WHERE
t1.[ID] = '%1'
DELETE t1 FROM [DB].[dbo].[SomeTable] AS t1 WHERE t1.[ID] = '%1'

----------------------------------------------------------------------

DOESN'T WORK:

DECLARE @SQL nvarchar(4000)

SELECT @SQL = SQL
FROM dbo.fnCascadingDelete ('dbo', 'SomeTable')
--SELECT @SQL = REPLACE(@SQL, '%1', @ID)

SELECT @SQL
--Exec sp_executesql @SQL

Result:
DELETE t1 FROM [DB].[dbo].[SomeTable] AS t1 WHERE t1.[ID] = '%1'

What am I doing wrong? Thanks once more.

Edited by - p3tar on 03/13/2008 12:01:28
Go to Top of Page

SwePeso
Patron Saint of Lost Yaks

Sweden
30277 Posts

Posted - 03/14/2008 :  02:08:59  Show Profile  Visit SwePeso's Homepage  Reply with Quote
When you assign the output from a table function, you only get the last result.
Please remember that the function returns a resultset that can hold many records. A variable can only hold one column in one record.

What you can do, is to insert the output from the function in a temporary table and loop each row there.



E 12°55'05.25"
N 56°04'39.16"
Go to Top of Page

p3tar
Starting Member

Croatia
4 Posts

Posted - 03/16/2008 :  18:56:15  Show Profile  Reply with Quote
Thanks, Peso. Today I tryed to make this script work for me, and I succeeded with while loop. Is there any script for cascading set-null or set-default?

Edited by - p3tar on 03/16/2008 18:57:08
Go to Top of Page

qutesanju
Posting Yak Master

193 Posts

Posted - 03/23/2010 :  07:33:18  Show Profile  Reply with Quote
PESO-->please post latest function for this
Go to Top of Page

anji2726
Starting Member

India
1 Posts

Posted - 11/13/2013 :  09:39:51  Show Profile  Reply with Quote
Hi SwePeso,

Thanks for great functions.

I came across similar scenario which need to update all the datetime columns of a particular master table and its children's and grand children's...so on in a database.

For populating all the table hierarchies for a given master table(Ex: Dept) your first function works perfectly.But updating only the datetime columns I`ve tried to change your dynamic delete scripts to dynamic update scripts for a particular department
(EX: Update t3 SET [hiredate] = DATEADD(DAY,365,[hiredate]) FROM [Test].[dbo].[dept] AS t1 INNER JOIN [Test].[dbo].[emp] AS t3 ON t3.[dept] = t1.[deptno] WHERE t1.[deptno] = '%1')
.But its not working for me in below scenarios.

Where
If a table having more than one datetime columns in it.
If a table don`t have any datetime columns but its children's has datetime columns.

Please help me in generating the update scripts for all the datetime columns in all tables.



Go to Top of Page
  Previous Topic Topic Next Topic  
 New Topic  Reply to Topic
 Printer Friendly
Jump To:
SQL Server Forums © 2000-2009 SQLTeam Publishing, LLC Go To Top Of Page
This page was generated in 0.16 seconds. Powered By: Snitz Forums 2000