Я спросил об этом в обмене стека dba, но мне не повезло. Кросс-проводка.
SQLFIDDLE
Я близок к тому, чтобы понять это, но я просто застрял в стене. Я пытаюсь понять пост Аарона Бетранда и применить его к ситуации, с которой я столкнулся, когда у меня есть таблица изменений, которая сильно дублируется из-за ошибки предыдущего дизайна, которую я наследую. Образец набора данных по своей сути идентичен моему реальному набору данных, за исключением того, что SortOrder обычно будет значением datetime, а не целым числом. Код, который я пробовал, находится здесь:
; with main as (
select *, ROW_NUMBER() over (partition by ID, Val, sortorder order by ID,
SortOrder) as "Rank",
row_number() over (partition by ID, val order by ID, sortorder) as "s_rank"
from
(values (1, 'A', 1), (1, 'A', 1), (1, 'B', 2), (1, 'C', 3), (1, 'B', 4),
(1, 'A', 5), (1, 'A', 5), (2, 'A', 1), (2, 'B', 2), (2, 'A', 3),
(3, 'A', 1), (3, 'A', 1), (3, 'A', 2)
) as x("ID", "VAL", "SortOrder")
group by id, val, SortOrder
--order by ID, "SortOrder"
),
cte_rest as (
select *
from main
where "s_rank" > 1
)
select *
from main
left join cte_rest rest
on main.id = rest.id
and main.s_rank > 1
and main.SortOrder = rest.SortOrder
--where not exists (select 1 from cte_rest r where r.id = main.id and r.val <> main.VAL and main.s_rank < s_rank)
order by main.ID, main.SortOrder
Результаты почти действительны;однако в последнем ряду освещается ситуация, которую я не смог отчитать: дата меняется, значение не меняется. Я хочу, чтобы последняя запись была исключена, поскольку это не истинное изменение значения.
╔════╦═════╦═══════════╦══════╦════════╦══════╦══════╦═══════════╦══════╦════════╗
║ ID ║ VAL ║ SortOrder ║ Rank ║ s_rank ║ ID ║ VAL ║ SortOrder ║ Rank ║ s_rank ║
╠════╬═════╬═══════════╬══════╬════════╬══════╬══════╬═══════════╬══════╬════════╣
║ 1 ║ A ║ 1 ║ 1 ║ 1 ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║
║ 1 ║ B ║ 2 ║ 1 ║ 1 ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║
║ 1 ║ C ║ 3 ║ 1 ║ 1 ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║
║ 1 ║ B ║ 4 ║ 1 ║ 2 ║ 1 ║ B ║ 4 ║ 1 ║ 2 ║
║ 1 ║ A ║ 5 ║ 1 ║ 2 ║ 1 ║ A ║ 5 ║ 1 ║ 2 ║
║ 2 ║ A ║ 1 ║ 1 ║ 1 ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║
║ 2 ║ B ║ 2 ║ 1 ║ 1 ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║
║ 2 ║ A ║ 3 ║ 1 ║ 2 ║ 2 ║ A ║ 3 ║ 1 ║ 2 ║
║ 3 ║ A ║ 1 ║ 1 ║ 1 ║ NULL ║ NULL ║ NULL ║ NULL ║ NULL ║
║ 3 ║ A ║ 2 ║ 1 ║ 2 ║ 3 ║ A ║ 2 ║ 1 ║ 2 ║
╚════╩═════╩═══════════╩══════╩════════╩══════╩══════╩═══════════╩══════╩════════╝
Мой коллега предложил этот код, и хотя я могу следить за его поступлением, я не могуне понимаю, почему первый пример кода не работает. Мне кажется, что это потребовало бы много дополнительного разбора, и с большим набором данных я бы беспокоился о влиянии на производительность.
WITH cte1
AS (SELECT [id]
, [val]
, [sortorder]
, ROW_NUMBER() OVER(PARTITION BY [id]
, [val]
, [sortorder]
ORDER BY [id]
, [sortorder]) AS "rankall"
FROM (VALUES
( 1, 'A', 1 ),
( 1, 'A', 1 ),
( 1, 'B', 2 ),
( 1, 'C', 3 ),
( 1, 'B', 4 ),
( 1, 'A', 5 ),
( 1, 'A', 5 ),
( 2, 'A', 1 ),
( 2, 'B', 2 ),
( 2, 'A', 3 ),
( 3, 'A', 1 ),
( 3, 'A', 1 ),
( 3, 'A', 2 )) AS x("id", "val", "sortorder")),
ctedropped
AS (SELECT [id]
, [val]
, [sortorder]
, ROW_NUMBER() OVER(PARTITION BY [id]
, [val]
, [sortorder]
ORDER BY [id]
, [sortorder]) AS "rankall"
FROM cte1
WHERE [cte1].[rankall] > 1)
SELECT [cte1].[id]
, [cte1].[val]
, [cte1].[sortorder]
FROM cte1
WHERE NOT EXISTS
(
SELECT *
FROM [ctedropped]
WHERE [cte1].[id] = [ctedropped].[id] AND
[cte1].[val] = [ctedropped].[val] AND
[cte1].[rankall] = [ctedropped].[rankall]
)
ORDER BY [cte1].[id]
, [cte1].[sortorder];