2010-11-08 3 views
0

Вот упрощенная версия моей таблицы.Почему обновление не работает с внутренним соединением?

CREATE TABLE TBLAGENT(AGENTID NUMBER, NUMBERSENT NUMBER, AGENTNAME VARCHAR2(100)); 
INSERT INTO TBLAGENT VALUES(100,NULL,'KNIGHT'); 
INSERT INTO TBLAGENT VALUES(200,NULL,'SUPES'); 
INSERT INTO TBLAGENT VALUES(300,NULL,'SPIDEY'); 

CREATE TABLE TBLSERVICES(AGENTID NUMBER, SERVICES NUMBER); 
INSERT INTO TBLSERVICES VALUES(100,44); 
INSERT INTO TBLSERVICES VALUES(200,13); 
INSERT INTO TBLSERVICES VALUES(300,24); 
INSERT INTO TBLSERVICES VALUES(100,34); 
INSERT INTO TBLSERVICES VALUES(200,13); 
INSERT INTO TBLSERVICES VALUES(300,24); 

SELECT TA.AGENTID, SUM(SERVICES), TA.AGENTNAME, TA.NUMBERSENT 
     FROM TBLAGENT TA, TBLSERVICES TS 
     WHERE TA.AGENTID = TS.AGENTID 
     GROUP BY TA.AGENTID, TA.AGENTNAME, TA.NUMBERSENT 

Требование, чтобы обновить столбец NUMBERSENT в таблице tblAgent с SUM (Services) из таблицы tblServices.

Я придумал это заявление об обновлении.

/*Works*/ 
UPDATE tblagent t 
    SET t.numbersent = 
     (SELECT SUM(services) 
      FROM tblservices x 
     WHERE t.agentid = x.agentid 
     GROUP BY x.agentid) 

Когда я изменяю синтаксис этого оператора на синтаксис INNER JOIN, он терпит неудачу.

/*Throws an error*/ 
UPDATE tblagent t 
    SET t.numbersent = 
     (SELECT SUM(services) 
      FROM tblservices x INNER JOIN tblAgent t 
     ON t.agentid = x.agentid 
     GROUP BY x.agentid) 

Это подбрасывает об ошибке ORA-01427: однорядные подзапрос возвращает более одной строки

Почему бы второй оператор выдаст ошибку?

ответ

3

@Тони Эндрюс прав, и если вы все еще хотите использовать INNER JOIN вы должны написать следующее:

UPDATE tblagent t1 
    SET t1.numbersent = 
     (SELECT SUM(services) 
      FROM tblservices x INNER JOIN tblAgent t 
     ON t.agentid = x.agentid 
     GROUP BY x.agentid 
     having t1.agentid = x.agentid) 

(Для того, чтобы иметь верхнюю и внутреннюю DML одну общую колонну, чтобы не возвращать более одного строка)

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

3

Вы пытались запустить подзапрос самостоятельно, чтобы убедиться, что он возвращает только одну строку?

+0

+1. Это довольно самоочевидное сообщение об ошибке ... подзапрос должен возвращать одну строку, и он возвращает больше одного. – ceejayoz

0

Это не должно быть

(SELECT x.agentid, SUM(services) 
     FROM tblservices x INNER JOIN tblAgent t 
    ON t.agentid = x.agentid 
    GROUP BY x.agentid) 

если вы присоединяетесь по agentid или

(SELECT SUM(services) 
     FROM tblservices x INNER JOIN tblAgent t 
    ON t.agentid = x.agentid 
    ) 

, если вы не?

+0

№ Подзапрос должен возвращать только SUM (Services). – abhi

+0

... это то, что делает второй подзапрос. – SteveCav

1

На самом деле теперь, когда я думаю об этом, первая версия - это коррелированный подзапрос, второй - нет. Без данных, чтобы попробовать это, я не мог вам сказать, но это, вероятно, имеет к этому какое-то отношение.

2

Вы переназначаете t с INNER JOIN, поэтому внешний t не связан с UPDATE.

+0

Да, есть два несвязанных использования таблицы tblAgent. –

1

У вас есть две строки в tblAgent с тем же agentid. Это может ускользнуть от вашего уведомления, если нет agentid is NULL.

Для проверки:

select * from 
(
    SELECT count(*) c, agentid from tblAgent group by agentid 
) x 
where x.c > 1 

Если какие-либо строки возвращаются, это ваша проблема.

4

Давайте посмотрим на то, как 2 запросы работают более подробно:

Во-первых, тот, который работает:

/*Works*/ 
UPDATE tblagent t 
    SET t.numbersent = 
     (SELECT SUM(services) 
      FROM tblservices x 
     WHERE t.agentid = x.agentid 
     GROUP BY x.agentid) 

Очевидно, что подзапрос должен возвращать одно значение для использования в SET, так что давайте смотреть на что сам по себе:

 SELECT SUM(services) 
      FROM tblservices x 
     WHERE t.agentid = x.agentid 
     GROUP BY x.agentid 

Обратите внимание, что «T» псевдоним здесь коррелирует подзапроса к внешнему запросу - то есть он имеет одно конкретное значение, когда подзапрос вычисляется, например,

 SELECT SUM(services) 
      FROM tblservices x 
     WHERE 123 = x.agentid 
     GROUP BY x.agentid 

Поэтому, хотя результаты группы запросов по x.agentid, есть только в том, один x.agentid значения т.е. текущего значения t.agentid (например, 123). Так что это работает.

Теперь посмотрим на вложенный запрос второго запроса на его собственное:

 SELECT SUM(services) 
     FROM tblservices x INNER JOIN tblAgent t 
      ON t.agentid = x.agentid 
     GROUP BY x.agentid 

На этот раз t.agentid является не ссылка на внешний запрос, поэтому этот запрос не коррелируют с внешним запросом , Это может вернуть более 1 строки (просто запустить его и посмотреть), и поэтому не может быть безопасно использован в предложении SET внешнего запроса.

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