Альтернатива на случай, когда?

У меня есть таблица в SQL, где результаты выглядят примерно так:

Number  |  Name     |  Name 2 
1       |  John     |  Derek  
1       |  John     |  NULL   
2       |  Jane     |  Louise 
2       |  Jane     |  NULL   
3       |  Michael  |  Mark   
3       |  Michael  |  NULL    
4       |  Sara     |  Paul    
4       |  Sara     |  NULL    

Я хочу сказать, что если Number=1, верните Name 2 в новый столбец Name 3, чтобы результаты выглядели так:

Number  |  Name     |  Name 2  |  Name 3
1       |  John     |  Derek   |  Derek
1       |  John     |  NULL    |  Derek
2       |  Jane     |  Louise  |  Louise
2       |  Jane     |  NULL    |  Louise
3       |  Michael  |  Mark    |  Mark
3       |  Michael  |  NULL    |  Mark
4       |  Sara     |  Paul    |  Paul
4       |  Sara     |  NULL    |  Paul

Проблема в том, что я не могу сказать, что если Number=1, вернуть Name 2 в Name 3, потому что в моей таблице>100 000 записей. Мне нужно сделать это автоматически. Больше похоже на "если число совпадает, вернуть имя 2 в имя 3". Я пытался использовать оператор CASE, но не смог понять это. Есть какой-либо способ сделать это?

5 ответов

Решение

Решение 2, с задержкой (если у вашей версии сервера sql есть функция задержки)

SELECT
    Number, Name, Name2,
    isnull(Name2, lag(Name2) OVER (PARTITION BY Number order by number)) Name3
FROM @sample; 

Опытным путем это, кажется, работает:

SELECT
    Number, Name, [Name 2],
    MAX([Name 2]) OVER (PARTITION BY Number) [Name 3]
FROM yourTable; 

Идея здесь, если я правильно истолковал ваши требования, заключается в том, что вы хотите сообщить о NULL значение второго имени для всех записей в качестве значения третьего имени.

Решение 3, с группой по

with maxi as(
SELECT Number, max(Name2) name3
FROM @sample
group by number, name
)
SELECT f1.*, f2.name3
FROM @sample f1 inner join maxi f2 on f1.number=f2.number

Вы можете попробовать это:

Решение 1, с row_number

declare @sample table (Number integer, Name varchar(50), Name2 varchar(50))
insert into @sample

select 1       ,  'John'     ,  'Derek' union all 
select 1       ,  'John'     ,  NULL   union all 
select 2       ,  'Jane'     ,  'Louise' union all 
select 2       ,  'Jane'     ,  NULL  union all 
select 3       ,  'Michael'  ,  'Mark' union all   
select 3       ,  'Michael'  ,  NULL   union all  
select 4       ,  'Sara'    , 'Paul'  union all   
select 4       ,  'Sara'     , NULL ; 

with tmp as ( 
select *, row_number() over(partition by number order by number) rang 
from @sample 
)
select f1.Number, f1.Name, f1.Name2, f2.Name2 as Name3
from tmp f1 inner join tmp f2 on f1.Number=f2.Number  and f2.rang=1 

Решение 4, с перекрестным применением

SELECT *
FROM @sample f1 cross apply
(
select top 1 f2.Name2 as Name3 from @sample f2 
where f2.number=f1.number and f2.Name2 is not null
) f3
Другие вопросы по тегам