-- Rollup rows, concatenating row values into a new column DROP TABLE #TestCREATE TABLE #Test (TestID INT IDENTITY (1,1), Section INT, Word VARCHAR(20))INSERT INTO #Test (Section, Word) VALUES (1, 'A'),(1, 'day'), (1, 'in'),(1, 'the'),(1, 'life'),(1, 'of'),(1, 'Ivan'),(1, 'Denisovich'), (2, 'Silent'),(2, 'Spring') ;WITH PreparedData AS ( SELECT *, SectionID = ROW_NUMBER() OVER(PARTITION BY Section ORDER BY TestID), -- sets order of words in sentence SectionSize = COUNT(*) OVER(PARTITION BY Section) -- used to detect last word of sentence FROM #Test), Concatenator AS ( SELECT TestID, Section, Word, -- source columns SectionID, SectionSize, Sentence = CAST(Word AS VARCHAR(100)) -- "working" columns FROM PreparedData WHERE TestID = 1 UNION ALL SELECT t.TestID, t.Section, t.Word, t.SectionID, t.SectionSize, Sentence = CAST(CASE WHEN t.SectionID = 1 THEN ISNULL(t.Word, '') ELSE l.Sentence + ' ' + ISNULL(t.Word, '') END AS VARCHAR(100)) FROM PreparedData t INNER JOIN Concatenator l ON l.TestID + 1 = t.TestID)SELECT TestID, Section, SentenceFROM ConcatenatorWHERE SectionID = SectionSize
SELECT Sections.Section, Concatenated.sentenceFROM ( SELECT DISTINCT Section FROM #Test ) SectionsCROSSAPPLY ( SELECT SPACE(1) + Word FROM #Test T WHERE T.Section = Sections.Section ORDER BY T.TestID FOR XML PATH (''), TYPE ) Concatenator (xml_string)CROSSAPPLY ( SELECT STUFF(Concatenator.xml_string.value('(./text())[1]', 'VARCHAR(MAX)'), 1, 1, SPACE(0)) ) Concatenated (sentence);
USE tempdb;GODROP TABLE dbo.Test;GOCREATE TABLE dbo.Test ( data INTEGER NOT NULL, );GOCREATE CLUSTERED INDEX c ON dbo.Test (data);GO-- Lots of duplicated valuesINSERT dbo.Test WITH (TABLOCK) (data)SELECT TOP (5000000) ROW_NUMBER() OVER (ORDER BY (SELECT 0)) / 117329FROM master.sys.columns C1, master.sys.columns C2, master.sys.columns C3;GO
SET STATISTICS TIME ON;-- 1591ms CPUSELECT DISTINCT dataFROM dbo.Test;-- 15ms CPUWITH RecursiveCTEAS ( SELECT data = MIN(T.data) FROM dbo.Test T UNION ALL SELECT R.data FROM ( -- A cunning way to use TOP in the recursive part of a CTE :) SELECT T.data, rn = ROW_NUMBER() OVER (ORDER BY T.data) FROM dbo.Test T JOIN RecursiveCTE R ON R.data < T.data ) R WHERE R.rn = 1 )SELECT *FROM RecursiveCTEOPTION (MAXRECURSION 0);SET STATISTICS TIME OFF;GODROP TABLE dbo.Test;
(43 row(s) affected)SQL Server Execution Times: CPU time = 2938 ms, elapsed time = 3052 ms.(43 row(s) affected)SQL Server Execution Times: CPU time = 0 ms, elapsed time = 3 ms.