Я думаю, что наилучшим способом является либо объединение против UNPIVOT, либо перекрестное объединение таблиц 2 с числами с помощью оператора CASE, чтобы вытащить столбцы. Ни один из способов не всегда является явным победителем, несмотря на то, насколько хорошим может быть синтаксис UNPIVOT.
Иногда перекрестное соединение превосходит UNPIVOT, а иногда наоборот. Вот метод перекрестного соединения, который работает даже в SQL 2000:
SELECT
A.date,
A.name,
A.hour,
A.amount,
A.price,
result =
CASE
WHEN A.amount > 0 THEN 'positive'
WHEN A.amount < 0 THEN 'negative'
END,
actualsold =
CASE A.hour
WHEN 12 THEN B.H12
WHEN 16 THEN B.H16
END
FROM
Table1 A
INNER JOIN Table2 B ON A.date = B.date and A.name = B.name
Это неявное частичное перекрестное объединение, поскольку в Table1 имеется много строк на дату и имя, а в Table2 - только одна строка на дату и имя. Таким образом, каждая строка в Таблице 2 повторяется много раз в соединении, но мы используем разные столбцы из каждого.
Отключение будет аналогичным, если поместить запрос UNPIVOT в производную таблицу или CTE:
SELECT
A.date,
A.name,
A.hour,
amount,
A.price,
result =
CASE
WHEN A.amount > 0 THEN 'positive'
WHEN A.amount < 0 THEN 'negative'
END,
B.actualsold
FROM
Table1 A
INNER JOIN (
SELECT *
FROM (SELECT date, name, [12] = H12, [16] = H16 FROM Table2) X
UNPIVOT (actualsold FOR hour IN ([12], [16])) U
) B ON A.date = B.date and A.name = B.name AND A.hour = B.hour
Планы выполнения для двух вышеупомянутых запросов очень похожи, хотя метод перекрестного соединения немного проще, но это ничего не доказывает в отношении фактической производительности, пока не будут проверены реальные данные в полных таблицах с большим количеством строк. UNPIVOT выполняет дополнительное LOOT LOOP JOIN, а метод перекрестного соединения - нет.
Один потенциальный недостаток метода UNPIVOT состоит в том, что если вы хотите указать критерии для ограничения диапазонов дат и имен, вам, вероятно, потребуется сделать это в двух местах, чтобы сервер не разворачивал всю таблицу опасности (хотя это может быть достаточно умным, чтобы этого не делать, я не знаю). В то время как большой оператор CASE с 24 условиями является громоздким, UNPIVOT имеет собственную неловкость для преобразования имен столбцов в просто числа.
Вот код настройки для любого, кто хотел бы видеть эти запросы в действии:
USE tempdb
CREATE TABLE Table1 (
date smalldatetime,
name varchar(10),
hour int,
amount int,
price decimal(15,2)
)
CREATE TABLE Table2 (
date smalldatetime,
name varchar(10),
H12 decimal(15,2),
H16 decimal(15,2),
)
INSERT Table1 VALUES ('20091012', 'tom', 12, 20, 15.43)
INSERT Table1 VALUES ('20091013', 'fred', 16, -10, 6.98)
INSERT Table2 VALUES ('20091012', 'tom', 15.75, 0)
INSERT Table2 VALUES ('20091013', 'fred', 0, 12.54)