Столбцы в строки Две таблицы в перекрестном применении - PullRequest
2 голосов
/ 04 мая 2019

Использование SQL Server У меня есть две таблицы, ниже пример Таблица № T1 в БД имеет более миллиона строк, Таблица № T2 имеет 100 строк.Обе таблицы имеют формат столбца, и мне нужно развернуть строки и объединить обе.

Можно ли получить все это за один запрос с помощью Cross Apply и удалить cte?

#T1

#T2

Output

Это мой код, у меня правильный вывод, ноэто самый эффективный способ сделать это, учитывая количество строк?

with cte_sizes
as
(
 select SizeRange,Size,ColumnPosition
 from #T2
 cross apply (
              values(Sz1,1),(Sz2,2),(Sz3,3),(Sz4,4)
             ) X (Size,ColumnPosition)
 )

 select a.ProductID,a.SizeRange,c.Size,isnull(x.Qty,0) as Qty
 from #T1 a
 cross apply (
              values(a.Sale1,1),(a.Sale2,2),(a.Sale3,3),(a.Sale4,4)
              ) X (Qty,ColumnPosition)
 inner join cte_sizes c 
 on c.SizeRange = a.SizeRange 
 and c.ColumnPosition = x.ColumnPosition

У меня также есть код, и я рассмотрел это, но действительно ли это CROSS APPLY лучший метод?

with cte_sizes
as
(
   select 1 as SizePos
  union all
   select SizePos + 1 as SizePos
   from cte_sizes
   where SizePos < 4
)

select a.ProductID
      ,a.SizeRange
      ,(case when b.SizePos = 1 then c.Sz1
             when b.SizePos = 2 then c.Sz2
             when b.SizePos = 3 then c.Sz3
             when b.SizePos = 4 then c.Sz4 end
       ) as Size
      ,isnull((case when b.SizePos = 1 then a.Sale1
                    when b.SizePos = 2 then a.Sale2
                    when b.SizePos = 3 then a.Sale3
                    when b.SizePos = 4 then a.Sale4 end
              ),0) as Qty

 from #T1 a
 inner join #T2 c on c.SizeRange = a.SizeRange
 cross join cte_sizes b

1 Ответ

1 голос
/ 04 мая 2019

Это дикое предположение, но мой волшебный хрустальный шар сказал мне, что вы можете искать что-то вроде этого:

Для этого нам совсем не нужен ваш стол #TS.

WITH Unpivoted2 AS
(
    SELECT t2.SizeRange,A.* FROM #t2 t2
    CROSS APPLY(VALUES(1,t2.Sz1)
                     ,(2,t2.Sz2)
                     ,(3,t2.Sz3)
                     ,(4,t2.Sz4)) A(SizePos,Size)
) 
SELECT t1.ProductID
      ,Unpivoted2.SizeRange
      ,Unpivoted2.Size
      ,Unpivoted1.Qty
FROM #t1 t1
CROSS APPLY(VALUES(1,t1.Sale1)
                 ,(2,t1.Sale2)
                 ,(3,t1.Sale3)
                 ,(4,t1.Sale4)) Unpivoted1(SizePos,Qty)
LEFT JOIN Unpivoted2 ON Unpivoted1.SizePos=Unpivoted2.SizePos AND t1.SizeRange=Unpivoted2.SizeRange
ORDER BY t1.ProductID,Unpivoted2.SizeRange;

Результат:

+-----------+-----------+------+------+
| ProductID | SizeRange | Size | Qty  |
+-----------+-----------+------+------+
| 123       | S-XL      | S    | 1    |
+-----------+-----------+------+------+
| 123       | S-XL      | M    | 12   |
+-----------+-----------+------+------+
| 123       | S-XL      | L    | 13   |
+-----------+-----------+------+------+
| 123       | S-XL      | XL   | 14   |
+-----------+-----------+------+------+
| 456       | 8-14      | 8    | 2    |
+-----------+-----------+------+------+
| 456       | 8-14      | 10   | 22   |
+-----------+-----------+------+------+
| 456       | 8-14      | 12   | NULL |
+-----------+-----------+------+------+
| 456       | 8-14      | 14   | 24   |
+-----------+-----------+------+------+
| 789       | S-L       | S    | 3    |
+-----------+-----------+------+------+
| 789       | S-L       | M    | NULL |
+-----------+-----------+------+------+
| 789       | S-L       | L    | 33   |
+-----------+-----------+------+------+
| 789       | S-L       | XL   | NULL |
+-----------+-----------+------+------+

Идея вкратце:

Cte вернет ваш #T2 в непивотной структуре. Каждый столбец с именем (чего следует избегать) возвращается в виде одной строки с индексом, указывающим позицию.

SELECT сделает то же самое с #T1 и присоединится к cte против этого набора.

ОБНОВЛЕНИЕ: после большого количества комментариев ...

Если я правильно понимаю (и изменения в первоначальном вопросе), описанный выше подход работает отлично, но вы хотите знать, что было лучше по производительности.

Первый ответ на вопрос "Какой самый быстрый подход?" Гони своих лошадей Эрик Липперт .

Полезно знать 1: CTE - не более чем синтаксический сахар . Это позволит один раз напечатать подзапрос и использовать его как таблицу, но это никак не повлияет на то, как движок будет работать с этим.

Полезно знать 2: Огромная разница, используете ли вы APPLY или JOIN. Первый вызовет подисточник один раз в строке, используя значения текущей строки. Второй должен сначала создать два набора, а затем присоединиться к ним по некоторому условию. Там нет общего "что лучше" ...

Для вашей проблемы: поскольку есть один очень большой набор и один очень маленький набор, все зависит от , когда вы уменьшаете большой набор с помощью любого вида фильтра. Чем раньше, тем лучше.

И самое главное: это - в любом случае - признак плохой структуры - когда вы найдете имя нумерации (что-то вроде phone1, phone2, phoneX). Самая дорогая работа будет заключаться в том, чтобы преобразовать ваши 4 именных столбца в несколько выделенных строк. Это должно быть сохранено в нормализованном формате ...

Если вам все еще нужна помощь, я бы попросил вас задать новый вопрос.

...