In my table I have rows, and each row has some data and its version. For example id col1 col2 col3 col4 priority 1 A NULL B NULL 1 1 NULL K NULL NULL 2 1 NULL C D NULL 3 the result should be: id col1 col2 col3 col4 1 A C D NULL what logic is used here? It's simple, when column is not-null, it overrides an old value otherwise nothing happens. Pseudocode (in C#) var resultTable = new List<Row>(); foreach (var group in table.GroupBy(x => x.ID).Select(g => g.OrderBy(x => x.Priority))) { var row = Row.GetEmpty(); foreach (var anotherRow in group) { foreach (var column in group.Columns) { if (column.GetValue(anotherRow) != null) column.SetValue(row, anotherRow); } } resultTable.Add(row); } How could it be done with standard SQL features? I saw someone who suggested use SQLCLR, but I want to avoid it if possible. ---------- I adopted a script from a link below, but it seems to work with known rows. Can it be done for an unknown rows (like `SELECT *` does)? I mean i have multiple tables, and I really don't want to use dynamic SQL or write tens of usp to implement `MergeTable1`, `MergeTable2` and so on. My try (doesn't work as expected): WITH CTE AS ( SELECT id, A, B, C, relevantid, MAX(relevantid) OVER( ORDER BY id ROWS UNBOUNDED PRECEDING ) AS grp FROM [Test].[dbo].[T] CROSS APPLY(VALUES(CASE WHEN [A] IS NOT NULL OR [B] IS NOT NULL OR [C] IS NOT NULL THEN id END)) AS A(relevantid) ), CTE2 AS ( SELECT id, MAX(A) OVER( PARTITION BY grp ORDER BY id ROWS UNBOUNDED PRECEDING ) A, MAX(B) OVER( PARTITION BY grp ORDER BY id ROWS UNBOUNDED PRECEDING ) B, MAX(C) OVER( PARTITION BY grp ORDER BY id ROWS UNBOUNDED PRECEDING) C FROM CTE ), CTE3 AS ( SELECT *, row_number() OVER (PARTITION BY id ORDER BY (SELECT 0)) Priority FROM CTE2 ), CTE4 AS ( SELECT *, MAX(Priority) OVER (PARTITION BY id ORDER BY (SELECT 0)) MaxPriority FROM CTE3 ) SELECT * FROM CTE4 WHERE Priority = MaxPriority ---------- Current script for a table: CREATE TABLE [dbo].[T]( [id] [int] NOT NULL, [A] [int] NULL, [B] [int] NULL, [C] [int] NULL, [Priority] [int] NOT NULL ) ON [PRIMARY] GO CREATE UNIQUE CLUSTERED INDEX [ClusteredIndex-20160204-122857] ON [dbo].[T] ( [id] ASC, [Priority] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] GO INSERT [dbo].[T] ([id], [A], [B], [C], [Priority]) VALUES (1, NULL, 3, 4, 1) GO INSERT [dbo].[T] ([id], [A], [B], [C], [Priority]) VALUES (1, 5, 6, NULL, 2) GO INSERT [dbo].[T] ([id], [A], [B], [C], [Priority]) VALUES (1, 8, NULL, NULL, 3) GO INSERT [dbo].[T] ([id], [A], [B], [C], [Priority]) VALUES (2, 634, 346, 359, 1) GO INSERT [dbo].[T] ([id], [A], [B], [C], [Priority]) VALUES (2, 34, NULL, 734, 2) GO desired result: id A B C 1 8 6 4 2 34 346 734