получить данные столбца в хранимой процедуре при обращении схемы - PullRequest
0 голосов
/ 03 февраля 2010

В БД SQL 2008 есть 2 таблицы данных, которые мне нужно использовать для построения результата в хранимой процедуре. Таблица 1 выглядит примерно так.

date         name  hour   amount   price 
------------------------------------------
2009-10-12   tom   12     20       15.43 
2009-10-13   fred  16     -10      6.98

Таблица 2 выглядит следующим образом. Обратите внимание, что каждый час находится в отдельном столбце по сравнению со всеми часами в одном столбце таблицы 1.

date         name   H12     H16
--------------------------------
2009-10-12   tom    15.75   0
2009-10-13   fred   0       12.54

Мне нужно написать хранимую процедуру, которая заканчивается результатом, который выглядит следующим образом.

date         name   hour   amount   price   result     actualsold 
---------------------------------------------------------------------
2009-10-12   tom    12     20       15.43   positive   15.75  
2009-10-13   fred   16    -10       6.98    negative   12.54

Я могу получить большую часть результата, который мне нужен для этого. , , да, легкая часть.

SELECT date, 
       name, 
       hour, 
       amount, 
       price, 
       case 
         when amount > 0 then 'positive' 
         when amount < 0 then 'negative' 
       end as result
FROM Table1

Как получить значение из таблицы 2 и добавить его в столбец фактически проданного (желательно без использования курсора)?

У меня нет контроля над схемами таблиц. БД работает на SQL 2008 ENT.

Ответы [ 4 ]

2 голосов
/ 04 февраля 2010

Я думаю, что наилучшим способом является либо объединение против 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)
0 голосов
/ 03 февраля 2010

Не проверено:

SELECT A.date, 
       A.name, 
       A.hour, 
       A.amount, 
       A.price, 
       case 
         when A.amount > 0 then 'positive' 
         when A.amount < 0 then 'negative' 
       end as result,
       (SELECT case A.hour when 1 then B.H1
                           when 2 then B.H2
                           ...
                           when 24 then B.H24 end
          FROM Table2 B
         WHERE A.date = B.date AND A.name = B.name) as actualsold
FROM Table1 A

Предполагается, что у вас есть столбцы для всех часов (H1, ..., H24).Если у вас есть только H12 и H16, вы можете уменьшить список case.

0 голосов
/ 03 февраля 2010

Используйте оператор UNPIVOT, чтобы вернуть Table2 в нормализованную форму (не проверено)

SELECT date,
       name,
       hour,
       Amount
FROM   Table2
UNPIVOT (Amount FOR [hour] IN ([H1], [H2], [H3], [H4], ... etc ...)) AS unpvt;
0 голосов
/ 03 февраля 2010

Вы сказали, что можете изменить схему таблицы, но можете ли вы создавать представления? Если возможно, я бы создал представление для исправления структуры второй таблицы, например:

CREATE VIEW vw_Table2 AS
SELECT date, name, 12 as hour, H12 as sold
UNION ALL
SELECT date, name, 16 as hour, H16 as sold

Оттуда вы можете структурировать свой запрос следующим образом:

SELECT t1.date, 
    t1.name, 
    t1.hour, 
    t1.amount, 
    t1.price, 
    case 
     when t1.amount > 0 then 'positive' 
     when t1.amount < 0 then 'negative' 
    end as result,
    v2.sold as actualsold
FROM Table1 as t1
JOIN vw_Table2 as v2 ON
    v2.date = t1.date
    AND v2.name = t1.name
    AND v2.hour = t1.hour
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...