Программирование >>  Преобразование значений null 

1 ... 23 24 25 [ 26 ] 27 28 29 ... 219


select

e.ename,

e.sal

from

emp e, emp bonus eb

where

e.empno = eb.empno

e.deptno = 10

ENAME

CLARK

2450

KING

5000

MILLER

1300

MILLER

1300

Теперь видно, почему значение TOTALSAL неверно: заработная плата служащего MILLER учитывается дважды. Окончательное результирующее множество, которое требовалось получить, на самом деле вот такое:

DEPTNO TOTAL SAL TOTAL BONUS 10 8750 2135

Решение

Необходимо быть очень аккуратным при совместном использовании агрегатных функций и объединений. Обычно избежать ошибок, обусловленных дублированием строк, возникающим при объединении, можно двумя способами: или просто использовать в вызове агрегатной функции ключевое слово DISTINCT, чтобы в вычислении участвовали только уникальные экземпляры значений, или сначала провести агрегацию (во вложенном запросе), а потом объединение. Во втором случае мы избежим ошибки при вычислении, поскольку агрегация будет выполнена еще до объединения, что полностью устраняет проблему. В приведенных ниже решениях используется ключевое слово DISTINCT. В разделе Обсуждение рассматривается, как с помощью вложенного запроса выполнить агрегацию до объединения.

MySQL и PostgreSQL

Суммируем только уникальные (DISTINCT) заработные платы:

1 select deptno,

2 sum(distinct sal) as total sal,

3 sum(bonus) as total bonus

4 from (

5 select e.empno,

6 e.ename,

7 e.sal,

8 e.deptno,

9 e.sal*case when eb.type = 1 then .1

10 when eb.type = 2 then .2

11 else .3



12 end as bonus

13 from emp e, emp bonus eb

14 where e.empno = eb.empno

15 and e.deptno = 10

16 ) x

17 group by deptno

DB2, Oracle и SQL Server

Эти платформы поддерживают предыдущее решение, но для них также можно использовать альтернативное решение с применением оконной функции SUM OVER:

1 select distinct deptno,total sal,total bonus

2 from (

3 select e.empno,

4 e.ename,

5 sum(distinct e.sal) over

6 (partition by e.deptno) as total sal,

7 e.deptno,

8 sum(e.sal*case when eb.type = 1 then .1

9 when eb.type = 2 then .2

10 else .3 end) over

11 (partition by deptno) as total bonus

12 from emp e, emp bonus eb

13 where e.empno = eb.empno

14 and e.deptno = 10

15 ) x

Обсуждение

MySQL и PostgreSQL

Второй запрос в разделе Задача данного рецепта осуществляет объединение таблиц EMP и EMP BONUS, в результате чего возвращаются две строки для служащего MILLER, что и обусловливает ошибочность значения суммы в EMP.SAL (заработная плата этого служащего суммируется дважды). Решение состоит в суммировании только уникальных значений EMP.SAL, возвращаемых запросом. Следующий запрос является альтернативным решением. Здесь сначала вычисляется сумма заработных плат всех служащих 10-го отдела, затем эта строка объединяется с таблицей EMP, которая в дальнейшем объединяется с таблицей EMP BONUS. Запрос ниже применим для всех СУБД:

select d.deptno,

d.total sal,

sum(e.sal*case when eb.type = 1 then .1 when eb.type = 2 then .2 else .3 end) as total bonus

from emp e,

emp bonus eb, (



7934 MILLER

8750

2135

7934 MILLER

8750

2135

7782 CLARK

8750

2135

7839 KING

8750

2135

Функция для работы с окнами SUM OVER вызывается дважды. В первый раз - для вычисления суммы уникальных заработных плат для заданного сегмента или группы. В данном случае сегмент - это 10-й отдел (DEPTNO 10), и сумма уникальных заработных плат для DEPTNO 10 составляет 8750. Следующий вызов SUM OVER осуществляет вычисление суммы премий того же сегмента. Окончательное результирующее множество (значения столбцов TOTALSAL и TOTALBO-NUS) формируется путем суммирования уникальных значений заработных плат и премий.

select deptno, sum(sal) as total sal

from emp

where deptno = 10

group by deptno ) d

where e.deptno = d.deptno

and e.empno = eb.empno

group by d.deptno,d.total sal

DEPTNO TOTAL SAL TOTAL BONUS

10 8750 2135

DB2, Oracle и SQL Server

В этом альтернативном решении используется оконная функция SUM OVER. Данный запрос занимает строки 3-14 примера раздела Решение и возвращает следующее результирующее множество:

select e.empno,

e.ename,

sum(distinct e.sal) over

(partition by e.deptno) as total sal,

e.deptno,

sum(e.sal*case when eb.type = 1 then .1 when eb.type = 2 then .2 else .3 end) over (partition by deptno) as total bonus from emp e, emp bonus eb where e.empno = eb.empno and e.deptno = 10

EMPNO ENAME TOTAL SAL DEPTNO TOTAL BONUS



1 ... 23 24 25 [ 26 ] 27 28 29 ... 219

© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика