#sql-server #tsql
#sql-server #tsql
Вопрос:
У меня есть код в следующем примере.
legacy_id phone_type phone_number
1 f 1234567890
1 b 1233854100
1 f 4110256565
2 f 0707070770
2 b 7895120044
Я хочу, чтобы данные заканчивались следующим образом.
legacy_id f_phone_number_1 b_phone_number_1 f_phone_number_2
1 1234567890 1233854100 4110256565
2 0707070770 7895120044
Мой первоначальный подход работает, но я надеялся, что есть более эффективный способ сделать это.
Select fill.legacy_id, max(fill.f_phone_number_1),max(fill.b_phone_number_1),max(fill.f_phone_number_2)
from
(
Select
a.legacy_id as legacy_id, a.phone_type as phone_type,
case
when a.phone_type = 'F' then a.phone_number and
dense_rank() over (partition by a.legacy_id, a.phone_type order by a.legacy_id, a.phone_type, a.phone_number) = 1
else null
end as f_phone_number_1,
case
when a.phone_type = 'F' then a.phone_number and
dense_rank() over (partition by a.legacy_id, a.phone_type order by a.legacy_id, a.phone_type, a.phone_number) = 2
else null
end as f_phone_number_2,
case
when a.phone_type = 'b' then a.phone_number and
dense_rank() over (partition by a.legacy_id, a.phone_type order by a.legacy_id, a.phone_type, a.phone_number) = 1
else null
end as b_phone_number_1
from table a
group by a.legacy_id, a.phone_type, a.phone_number
) fill
group by fill.legacy_id
Есть ли более эффективный способ приблизиться к этому?
Комментарии:
1. похоже, вы должны иметь возможность выполнять поворот с помощью динамического sql. Это потребовало бы меньше кода и было бы масштабируемым, но производительность действительно зависела бы.
2. Не может быть масштабируемым, поскольку этот выбор будет использоваться для вставки в таблицу. Хотя мне нравится идея pivot.
3. Возможно, вы захотите переместить это в codereview.stackexchange.com также
Ответ №1:
Если вам не нужно переходить на динамический режим, условная агрегация должна сделать свое дело
Declare @YourTable table (legacy_id int,phone_type varchar(25),phone_number varchar(25))
Insert Into @YourTable values
(1,'f','1234567890'),
(1,'b','1233854100'),
(1,'f','4110256565'),
(2,'f','0707070770'),
(2,'b','7895120044')
Select legacy_id
,f_phone_number_1 = max(case when phone_type='f' and RowNr=1 Then phone_number else '' end)
,b_phone_number_1 = max(case when phone_type='b' and RowNr=1 Then phone_number else '' end)
,f_phone_number_2 = max(case when phone_type='f' and RowNr=2 Then phone_number else '' end)
,b_phone_number_2 = max(case when phone_type='b' and RowNr=2 Then phone_number else '' end)
From (
Select *
,RowNr=Row_Number() over (Partition By legacy_id,phone_type Order By (Select NULL) )
From @YourTable
) A
Group By legacy_id
ВОЗВРАТ
legacy_id f_phone_number_1 b_phone_number_1 f_phone_number_2 b_phone_number_2
1 4110256565 1233854100 1234567890
2 0707070770 7895120044
Комментарии:
1. Улучшается ли производительность при использовании row_number() по сравнению с dense_rank()? На данный момент ваш скрипт похож на мой.
2. @LetUsSeng выполняет только 1 проход здесь в подзапросе. Не помешало бы попробовать.
3. Спасибо, я попробую.
4. Я попробовал, и мне это нравится. Это чище, чем то, что я придумал. Спасибо.
5. @LetUsSeng Рад помочь, просто любопытно, почему вы отменили выбор в качестве ответа?