If you deal with a table that has foreign key to itself, circular references may appear. The query that lists all rows with circular references is listed at the page.
Sometimes it is necessary to list only representatives of each set of circular referenced rows. In the following query the first select statement orders representatives by its IDs; the second one — by the latest create time, inputed to another table.
USE [Example] GO -- create tables CREATE TABLE [dbo].[List] ([ID] [int] IDENTITY(1,1) NOT NULL ,[Name] [varchar](50) NULL ,[ParentID] [int] NULL ,CONSTRAINT [PK_List] PRIMARY KEY CLUSTERED ([ID] ASC)); GO CREATE TABLE [dbo].[ListTime] ([ID] [int] IDENTITY(1,1) NOT NULL ,[ListID] [int] NOT NULL ,[CurrentDate] [datetime] NOT NULL ,CONSTRAINT [PK_ListTime] PRIMARY KEY CLUSTERED ([ID] ASC)); GO ALTER TABLE [dbo].[ListTime] ADD CONSTRAINT [DF_ListTime_CurrentDate] DEFAULT (SYSDATETIME()) FOR [CurrentDate]; ALTER TABLE [dbo].[ListTime] WITH CHECK ADD CONSTRAINT [FK_ListTime_List] FOREIGN KEY([ListID]) REFERENCES [dbo].[List] ([ID]); GO -- insert values INSERT INTO [dbo].[List] VALUES ('text 1', 3) ,('text 2', NULL) ,('text 3', 1) ,('text 4', 7) ,('text 5', 4) ,('text 6', 5) ,('text 7', 6) ,('text 8', 9) ,('text 9', 8) ,('text 10', 11) ,('text 11', 13) ,('text 12', 13) ,('text 13', 13) INSERT INTO [dbo].[ListTime] VALUES (1, '2013-12-01') ,(2, '2013-12-02') ,(3, '2013-12-03') ,(4, '2013-12-04') ,(5, '2013-12-05') ,(6, '2013-12-06') ,(7, '2013-12-07') GO -- temporary table for all pairs DECLARE @Pairs TABLE ([ID] int ,[ParentID] int); WITH Pairs ([ID], [ParentID]) AS ( SELECT [ID], [ParentID] FROM [List] WHERE [ParentID] IS NOT NULL UNION ALL SELECT t1.[ID], t2.[ParentID] FROM List t1 INNER JOIN Pairs t2 ON t1.[ParentID] = t2.[ID] AND t1.[ParentID] <> t1.[ID] AND t2.[ParentID] <> t2.[ID] ) INSERT INTO @Pairs SELECT * FROM Pairs -- test all ordered pairs SELECT * FROM @Pairs -- uncomment in order to see all circular references --WHERE [id] = [parentid] ORDER BY [id] -- select representatives from each loop by minimum id SELECT DISTINCT MIN(t1.[ParentID]) FROM @Pairs AS t1 WHERE t1.[ID] IN (SELECT s1.[ID] FROM @Pairs AS s1 WHERE s1.[ID] = s1.[ParentID]) GROUP BY t1.[ID] -- select representatives from each loop by maximum time from referenced table SELECT DISTINCT (SELECT TOP(1) s1.[ParentID] FROM @Pairs AS s1 LEFT OUTER JOIN dbo.[ListTime] AS s2 ON s1.[ParentID] = s2.[ListID] WHERE s1.id = t1.id ORDER BY ISNULL(s2.[CurrentDate], DATEADD(MS, s1.[ParentID], '1900-01-01')) DESC) AS [Origin] FROM @Pairs AS t1 WHERE t1.[ID] = t1.[ParentID]
- All used IP-addresses, names of servers, workstations, domains, are fictional and are used exclusively as a demonstration only.
- Information is provided «AS IS».