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
department
和 location
。也许在这种情况下是 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 多行没有问题。)
基本上,我有 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
department
和 location
。也许在这种情况下是 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 多行没有问题。)