PL/SQL 根据不同 table 之间的相等性,使用一个 table 中的列数据更新 table

PL/SQL Update table using column data from one table, based on equality between different tables

基本上,我有 2 tables: EMPLOYEES, DBPZIP.

我需要更新来自 table EMPLOYEES 的 ZIP 列,基于两个语句使用来自 DBPZIP 的 ZIP 列:

EMPLOYEES LOCATION 必须等于 DBPZIP LOCATION 和 DBPZIP DEPARTMENT 必须是 'Store'

到目前为止我尝试了两种方法:

create or replace PROCEDURE           insertZip IS

BEGIN

 UPDATE EMPLOYEES
  SET EMPLOYEES.ZIP =               ( SELECT DPBZIP.POSTCODE
                                      FROM DPBZIP
                                      WHERE DPBZIP.DEPARTMENT = 'Store')

  WHERE DPBZIP.LOCATION = EMPLOYEES.LOCATION;

END;

第二种方式:

create or replace PROCEDURE           insertZip IS

  UPDATE EMPLOYEES
  SET EMPLOYEES.ZIP =               ( SELECT DPBZIP.POSTCODE
                                      FROM DPBZIP
                                      WHERE DPBZIP.DEPARTMENT = 'Store'
                                      AND DPBZIP.LOCATION = EMPLOYEES.LOCATION);

END;

当我将两个 DBPZIP 都放在 select 语句中时,我得到单行子查询 returns 不止一行。

如果我把一个放在外面,我会得到无效的标识符。

第一种方式: 它在语法上不正确,因为 EMPLOYEES 别名不存在于 UPDATE 语句的范围内。

第二种方式: 您的单行子查询 returns 多于一行,因为在 SQL 语句中使用“=”,您需要在等式右侧有一个值。假设一个位置 (DBZIP.LOCATION) returns 只有一个 (DBZIP.POSTCODE) 您可以通过添加谓词 ROWNUM = 1 或在 select 子句中添加 DISTINCT 来限制返回的行。

我不确定为什么您的程序中有 COMMIT 语句。如果您只更新一行,那并不是一个特别好的主意。其次,除了@Kamil 指出的问题之外,您的查询还有另一个问题;即使您限制了子查询 return 的行数,只要 DBZIP 中没有相应的记录, EMPLOYEES.zip 就会被设置为 NULL departmentlocation。也许在这种情况下是 acceptable,但我会按如下方式重写查询。

UPDATE employees e
   SET e.zip = ( SELECT MAX(d.postcode) FROM dpbzip d
                  WHERE d.department = 'Store'
                    AND d.location = e.location )
 WHERE EXISTS ( SELECT 1 FROM dpbzip d
                 WHERE d.department = 'Store'
                   AND d.location = e.location );

请注意,我在上面使用了 table 别名,因此我不必一遍又一遍地键入 table 名称。另请注意,我正在使用聚合(在本例中为 MAX())以确保我 return 在子查询中只有一行。 (WHERE EXISTS 子句中的子查询可以 return 多行没有问题。)