2015-07-10 2 views
0

Я отвечал на другой вопрос и столкнулся с каким-то странным результатом. Результаты использования агрегата продукта (без CLR) были разными при использовании в SELECT и UPDATE.UPDATE с результатом агрегата продукта без CLR

Это упрощен от первоначального вопроса минимально воспроизвести проблему:

GroupKey RowIndex A 
----------- ----------- ----------- 
25   1   5 
25   2   6 
25   3   NULL 
26   1   3 
26   2   4 
26   3   NULL 

Цель для каждого ключа группы для обновления A столбца каждой строки с RowIndex = 3 к произведению A столбцов каждая строка с RowIndex IN (1, 2), так что это будет производить следующие изменения:

GroupKey RowIndex A 
----------- ----------- ----------- 
25   3   30 
26   3   12 

так что это код, который я использовал:

UPDATE T SET 
    A = Products.Product 
FROM @Table T 
    INNER JOIN (
     SELECT 
      GroupKey, 
      EXP(SUM(LOG(A))) AS Product 
     FROM @Table 
     WHERE RowIndex IN (1, 2) 
     GROUP BY 
      GroupKey 
    ) Products 
     ON Products.GroupKey = T.GroupKey 
WHERE T.RowIndex = 3 
SELECT * FROM @Table WHERE RowIndex = 3 

Который затем произвел совсем по одному результаты:

GroupKey RowIndex A 
----------- ----------- ----------- 
25   3   29 
26   3   12 

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

GroupKey Product 
----------- ---------------------- 
25   30 
26   12 

Вот полный скрипт, с помощью которого можно легко играть. Я не могу понять, откуда это происходит.

DECLARE @Table TABLE (GroupKey INT, RowIndex INT, A INT) 
INSERT @Table VALUES (25, 1, 5), (25, 2, 6), (25, 3, NULL), (26, 1, 3), (26, 2, 4), (26, 3, NULL) 

SELECT * FROM @Table 

SELECT 
    GroupKey, 
    EXP(SUM(LOG(A))) AS Product 
FROM @Table 
WHERE RowIndex IN (1, 2) 
GROUP BY 
    GroupKey 

UPDATE T SET 
    A = Products.Product 
FROM @Table T 
    INNER JOIN (
     SELECT 
      GroupKey, 
      EXP(SUM(LOG(A))) AS Product 
     FROM @Table 
     WHERE RowIndex IN (1, 2) 
     GROUP BY 
      GroupKey 
    ) Products 
     ON Products.GroupKey = T.GroupKey 
WHERE T.RowIndex = 3 
SELECT * FROM @Table WHERE RowIndex = 3 

Вот некоторые ссылки я натолкнулась:

ответ

2

Я бы сказал, что это мило "ПРОДУКТ" совокупность по своей сути ненадежна, если вы хотите работать с int s - EXP и LOG определены только против float типа и таким образом мы получаем ошибки округления ползучими.

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

В качестве более простого примера того, как это может пойти не так:

select CAST(EXP(LOG(5)) as int) 

Может производить 4. EXP и LOG вместе выдают значение только менее 5, но, конечно, при преобразовании в int SQL Server всегда усекает, а не применяет любое округление.

+0

Конечно, это также означает, что 'round' поможет немного. Однако это все еще ненадежно. – Luaan

+0

Интересно, хотя в моем примере, если я просто изменяю тип данных своей таблицы на FLOAT, ошибка округления не возникает, но простой метод cast/convert для float до 'LOG' не помогает. –

+0

@JasonW - ошибка округления, но для * display *, 'float', достаточно близкий к' 30', будет преобразован в * строку * '30', тогда как когда мы попросим преобразовать этот' float' в ' int', вещи немного более строгие. –

Смежные вопросы