Упрощение UPDATE для таблиц, представляющих наборы мощности - PullRequest
1 голос
/ 10 марта 2012

У меня есть 2 таблицы, которые я пытаюсь использовать для выполнения некоторых вычислений. Моя первая таблица (которая в основном представляет собой набор мощности 'ABC' и не включающий NONE) выглядит следующим образом:

TABLE: test3
rowID    v1      v2      v3      combo    initialValue
1        NULL    NULL    M170_4  C        NULL
2        NULL    M170_3  NULL    B        NULL
3        NULL    M170_3  M170_4  BC       NULL
4        M170_2  NULL    NULL    A        NULL
5        M170_2  NULL    M170_4  AC       NULL
6        M170_2  M170_3  NULL    AB       NULL
7        M170_2  M170_3  M170_4  ABC      NULL

Мне нужно обновить столбец initialValue для каждой строки.

У меня есть еще одна таблица:

TABLE: my_data_db
ID      WEIGHT    v1      v2      v3
1       1.34      0.10    NULL    NULL
2       0.53      0.75    NULL    0.75
3       1.24      0.25    0.10    0.25
4       0.95      NULL    1.00    0.10
5       0.72      0.75    NULL    0.10
6       0.145     1.00    1.00    0.75
...
AND SO ON

Для каждой строки в test3 Мне нужно вычислить сумму произведений соответствующих строк в my_data_db примерно так:

DECLARE @total FLOAT
SET @total = 4898.947426

UPDATE test3 SET initialValue = 
(
    SELECT SUM(v3 * WEIGHT / @total) FROM my_data_db
)
WHERE combo = 'C'

UPDATE test3 SET initialValue = 
(
    SELECT SUM(v2 * WEIGHT / @total) FROM my_data_db
)
WHERE combo = 'B'

UPDATE test3 SET initialValue = 
(
    SELECT SUM(v2 * v3 * WEIGHT / @total) FROM my_data_db
)
WHERE combo = 'BC'


UPDATE test3 SET initialValue = 
(
    SELECT SUM(v1 * WEIGHT / @total) FROM my_data_db
)
WHERE combo = 'A'

UPDATE test3 SET initialValue = 
(
    SELECT SUM(v1 * v2 * WEIGHT / @total) FROM my_data_db
)
WHERE combo = 'AB'

UPDATE test3 SET initialValue = 
(
    SELECT SUM(v1 * v3 * WEIGHT / @total) FROM my_data_db
)
WHERE combo = 'AC'

UPDATE test3 SET initialValue = 
(
    SELECT SUM(v1 * v2 * v3 * WEIGHT / @total) FROM my_data_db
)
WHERE combo = 'ABC'

Что я не могу понять, так это упростить мои UPDATE s, чтобы мне не приходилось иметь одно обновление на строку. Мой код UPDATE, приведенный выше, хотя и уродлив, не слишком сложен, но реальная проблема заключается в том, что у меня будут таблицы, подобные test3, которые содержат более миллиона строк, и все с уникальными комбинациями соответствующих столбцов. Кроме того, я бы не хотел использовать цикл CURSOR или WHILE, если в этом нет необходимости. Мое решение, использующее CURSOR (см. Предыдущий пост, упомянутый ниже), не масштабируется, когда мои таблицы набора мощности становятся огромными.

Спасибо.

(ПРИМЕЧАНИЕ: это продолжение: Избегание курсоров для обновления многих записей с использованием триггера )

1 Ответ

1 голос
/ 11 марта 2012

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

;
WITH
  test3_with_keys AS (
    SELECT
      RowID,
      key1 = CASE WHEN v1 IS NULL THEN 0 ELSE 1 END,
      key2 = CASE WHEN v2 IS NULL THEN 0 ELSE 1 END,
      key3 = CASE WHEN v3 IS NULL THEN 0 ELSE 1 END
    FROM @test3
  ),
  my_data_db_with_keys AS (
    SELECT
      WEIGHT,
      v1,
      v2,
      v3,
      key1 = CASE WHEN v1 IS NULL THEN 0 ELSE 1 END,
      key2 = CASE WHEN v2 IS NULL THEN 0 ELSE 1 END,
      key3 = CASE WHEN v3 IS NULL THEN 0 ELSE 1 END
    FROM @my_data_db
  ),
  calculated AS (
    SELECT
      t.RowID,
      initialValue = SUM(
        ISNULL(NULLIF(t.key1, 0) * d.v1, 1) *
        ISNULL(NULLIF(t.key2, 0) * d.v2, 1) *
        ISNULL(NULLIF(t.key3, 0) * d.v3, 1) *
        d.WEIGHT / @total
      )
    FROM test3_with_keys t
      INNER JOIN my_data_db_with_keys d ON t.key1 <= d.key1
                                       AND t.key2 <= d.key2
                                       AND t.key3 <= d.key3
    GROUP BY
      t.rowID
  )
UPDATE test3
SET initialValue = c.initialValue
FROM calculated c
WHERE test3.RowID = c.RowID;

Примечание: предполагается, что значения RowID являются уникальными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...