This query lists questions that have been closed as duplicates of another question that has since been deleted. Such questions should be either deleted or, if they have good answers or are otherwise of decent quality, reopened. Note that non-locked questions with no answers and a negative score will be automatically deleted by the RemoveDeadQuestions script after 30 days, as indicated by the "Roombable?" column. By default, the results will be sorted with the most recently closed questions first. You can click the column headings to change the sort order. For example, questions with a high answer score may be good candidates for reopening (or for a historical lock), while questions with a high score but no answers may simply need a new dupe target (see http://meta.stackexchange.com/q/291824).
Q&A for people interested in the history and origins of science and mathematics
-- step 1: find IDs of dupes with deleted targets CREATE TABLE #DeletedDupes ( PostId INT NOT NULL, RelatedPostId INT NOT NULL ) INSERT INTO #DeletedDupes SELECT BrokenLink.PostId, BrokenLink.RelatedPostId FROM PostLinks as BrokenLink LEFT JOIN Posts as TargetPost ON TargetPost.Id = BrokenLink.RelatedPostId WHERE BrokenLink.LinkTypeId = 3 AND TargetPost.Id IS NULL AND NOT EXISTS ( SELECT 1 FROM PostLinks as OtherLink JOIN Posts as OtherTarget ON OtherTarget.Id = OtherLink.RelatedPostId WHERE OtherLink.LinkTypeId = 3 AND OtherLink.PostId = BrokenLink.PostId ) -- step 2: determine current site host name for migration matching DECLARE @sitename NVARCHAR(MAX) = DB_NAME() SET @sitename = REPLACE(@sitename, 'StackExchange.Mathoverflow', 'Mathoverflow') SET @sitename = REPLACE(@sitename, 'StackExchange.Ubuntu', 'AskUbuntu') SET @sitename = REPLACE(@sitename, 'StackExchange.Audio', 'StackExchange.Video') SET @sitename = REPLACE(@sitename, 'StackExchange.Garage', 'StackExchange.Mechanics') SET @sitename = REPLACE(@sitename, 'StackExchange.Moderators', 'StackExchange.CommunityBuilding') SET @sitename = REPLACE(@sitename, 'StackExchange.Photography', 'StackExchange.Photo') SET @sitename = REPLACE(@sitename, 'StackExchange.Programmers', 'StackExchange.SoftwareEngineering') SET @sitename = REPLACE(@sitename, 'StackOverflow.Br', 'StackOverflow.Pt') DECLARE @tld NVARCHAR(3) = (CASE WHEN @sitename LIKE 'Mathoverflow%' THEN 'net' ELSE 'com' END) DECLARE @newurlprefix NVARCHAR(MAX) = 'https://' + LOWER(CASE WHEN CHARINDEX('.', @sitename, 0) = 0 THEN @sitename ELSE RIGHT(@sitename, LEN(@sitename) - CHARINDEX('.', @sitename, 0)) + '.' + LEFT(@sitename, CHARINDEX('.', @sitename, 0) - 1) END) + '.' + @tld DECLARE @oldurlprefix NVARCHAR(MAX) = '' SELECT @oldurlprefix = CONCAT(value, '.', @oldurlprefix) FROM STRING_SPLIT(@sitename, '.') SET @oldurlprefix = 'http://' + LOWER(@oldurlprefix) + @tld CREATE TABLE #UrlPrefixes ( UrlPrefix NVARCHAR(MAX) NOT NULL ) INSERT INTO #UrlPrefixes VALUES (@newurlprefix), (@oldurlprefix) -- step 2.5: compile list of migration record patterns to match CREATE TABLE #MigrationPatterns ( PostId INT NOT NULL, Pattern NVARCHAR(MAX) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL ) INSERT INTO #MigrationPatterns SELECT PostId, 'from ' + UrlPrefix + '/questions/' + Cast(RelatedPostId as NVARCHAR) + '/%' FROM #DeletedDupes, #UrlPrefixes -- step 3: filter out dupes of migrated posts CREATE TABLE #MigratedDupes ( PostId INT NOT NULL ) DECLARE sites CURSOR FOR SELECT name FROM sys.databases WHERE name NOT IN ('master', 'tempdb', 'model', 'msdb', 'Data.StackExchange') DECLARE @sitedbname AS nvarchar(max) DECLARE @query AS nvarchar(max) OPEN sites FETCH NEXT FROM sites INTO @sitedbname WHILE @@FETCH_STATUS = 0 BEGIN SET @query = ' USE [' + @sitedbname + '] INSERT INTO #MigratedDupes SELECT Match.PostId FROM #MigrationPatterns as Match JOIN PostHistory as Migration ON Migration.Text LIKE Match.Pattern WHERE Migration.PostHistoryTypeId IN (17, 36) ' EXEC sp_executesql @query FETCH NEXT FROM sites INTO @sitedbname END CLOSE sites DEALLOCATE sites -- step 4: merge and uniquify results, add aggregate columns CREATE TABLE #FilteredDupes ( PostId INT NOT NULL, AnswerScore INT NULL, LockEventId INT NULL ) INSERT INTO #FilteredDupes SELECT BrokenLink.PostId as PostId, MAX(Answer.Score) as AnswerScore, MAX(LockEvent.Id) as LockEventId FROM #DeletedDupes as BrokenLink LEFT JOIN Posts as Answer ON Answer.PostTypeId = 2 AND Answer.ParentId = BrokenLink.PostId LEFT JOIN PostHistory as LockEvent ON LockEvent.PostHistoryTypeId IN (14, 15) AND LockEvent.PostId = BrokenLink.PostId WHERE BrokenLink.PostId NOT IN (SELECT PostId FROM #MigratedDupes) GROUP BY BrokenLink.PostId -- step 5: format results nicely SELECT BrokenLink.PostId as [Post Link], SourcePost.ViewCount as Views, SourcePost.Score, SourcePost.AnswerCount as Answers, BrokenLink.AnswerScore as AScore, (CASE WHEN SourcePost.AcceptedAnswerId IS NULL THEN '' ELSE 'Accepted' END) as Accepted, SourcePost.ClosedDate as Closed, (CASE WHEN LockEventId IS NOT NULL AND (SELECT PostHistoryTypeId FROM PostHistory WHERE Id = LockEventId) = 14 THEN 'No (Post Locked)' WHEN SourcePost.AnswerCount = 1 THEN 'No (1 answer)' WHEN SourcePost.AnswerCount > 1 THEN 'No (' + Cast(SourcePost.AnswerCount as VARCHAR) + ' answers)' WHEN SourcePost.Score = 0 THEN 'If downvoted' WHEN SourcePost.Score > 0 THEN 'If downvoted x' + Cast(SourcePost.Score+1 as VARCHAR) ELSE 'Yes, on ' + Convert(VARCHAR(10), DateAdd(Day, 30, SourcePost.CreationDate), 126) END) as [Roombable?], SourcePost.Tags as [Tags] FROM #FilteredDupes as BrokenLink JOIN Posts as SourcePost ON SourcePost.Id = BrokenLink.PostId ORDER BY SourcePost.ClosedDate DESC