CREATE TABLE Landmark
(
Indexc NUMBER
Birth DATE
Address VARCHAR2(50 BYTE)
City VARCHAR2(30 BYTE)
State CHAR(2 BYTE)
Zip VARCHAR2(15 BYTE)
...
Other properties
)
ALTER TABLE Landmark ADD (
CONSTRAINT Landmark_PK PRIMARY KEY (Indexc, Birth));
CREATE TABLE MapPoint
(
Indexc NUMBER
Longitude FLOAT(126)
Latitude FLOAT(126)
BuildDate DATE
)
ALTER TABLE MapPoint ADD (
CONSTRAINT MapPoint_FK FOREIGN KEY (Indexc) REFERENCES Landmark (Indexc));
Landmark表包含可以不时移动的地标列表。 MapPoint表保存这些地标的经度和纬度。只要地标的属性发生变化,就会在地标表中插入一个新行,该地标的新出生日期为地址。
我有一个脚本会在MapPoint表中为没有物理移动的所有地标将BuildDate设置为null,并且我正在尝试编写将重用最后一行地址的UDPATE语句。以下是我想要的,但不起作用,因为内部最多的子查询将不与update语句相关联。我得到ORA-00904:“lm2”。“索引”:标识符无效。
UPDATE Landmark lm1
SET (Address, City, State, Zip) = (
SELECT Address, City, State, Zip
FROM Landmark lm2
WHERE lm2.Indexc = lm1.Indexc
AND lm2.birth = (
SELECT MIN(Birth)
FROM (
SELECT Birth
FROM Landmark lm3
WHERE lm3.Indexc = lm2.Indexc
ORDER BY Birth DESC)
AND ROWNUM < 3))
WHERE Indexc IN (
SELECT Indexc
FROM MapPoint
WHERE BuildDate IS NULL);
之前的样本:
Indexc Birth Address City State Zip
------ ---------------------- ------------ ----------- ----- -----
45 8/16/2009 4:46:21 AM 123 Main St Springfield PA 84679
45 8/18/2009 7:20:27 PM 123 Main St Springfield PA 84679
45 8/20/2009 9:01:44 PM 456 Smith Ln Springfield PA 84153
45 10/31/2009 12:29:07 AM
示例之后:
Indexc Birth Address City State Zip
------ ---------------------- ------------ ----------- ----- -----
45 8/16/2009 4:46:21 AM 123 Main St Springfield PA 84679
45 8/18/2009 7:20:27 PM 123 Main St Springfield PA 84679
45 8/20/2009 9:01:44 PM 456 Smith Ln Springfield PA 84153
45 10/31/2009 12:29:07 AM 456 Smith Ln Springfield PA 84153
答案 0 :(得分:1)
这完美无缺。虽然它对于第n个最新项目来说不是那么可扩展。
UPDATE Landmark lm1
SET (Address, City, State, Zip) = (
SELECT Address, City, State, Zip
FROM Landmark lm2
WHERE lm2.Indexc = lm1.Indexc
AND lm2.birth = (
SELECT MAX(Birth)
FROM Landmark lm3
WHERE lm3.Indexc = lm2.Indexc
AND lm3.birth < (
SELECT MAX(Birth)
FROM Landmark lm4
WHERE lm4.Indexc = lm3.Indexc)))
WHERE Indexc IN (
SELECT Indexc
FROM MapPoint
WHERE BuildDate IS NULL)
AND Birth = (
SELECT MAX(Birth)
FROM Landmark lm2
WHERE lm2.Indexc = lm1.Indexc);
答案 1 :(得分:1)
此解决方案使用分析功能。代码看起来稍微多余,但成本较低,至少在我的测试数据库中,可能是因为子查询较少:
update landmark L1 set (address, city, state, zip) =
(select address, city, state, zip from
(select last_value(address ignore nulls) over (partition by cindex order by birth) address,
last_value(city ignore nulls) over (partition by cindex order by birth) city,
last_value(state ignore nulls) over (partition by cindex order by birth) state,
last_value(zip ignore nulls) over (partition by cindex order by birth) zip,
cindex, birth
from landmark) L2
where l1.cindex = l2.cindex and l2.birth = l1.birth)
where CIndex IN (
SELECT CIndex
FROM MapPoint
WHERE BuildDate IS NULL)
and address is null
基本上它是说,从表中获取所有行,并且对于每一行,如果它们不为空,则选择地址值,如果是,则选择最后一个非空值,然后为需要的行更新这些值。更新。
答案 2 :(得分:0)
我将“index”替换为“indexc”,因为索引在oracle中不是有效的列名。我认为这可以做你想要的事情:
UPDATE Landmark lm1
SET (Address, City, State, Zip) = (
SELECT Address, City, State, Zip
FROM Landmark lm2
WHERE lm2.Indexc = lm1.Indexc
AND lm2.birth = (
SELECT MAX(Birth)
FROM Landmark lm3
WHERE lm3.Indexc = lm2.Indexc
and lm3.birth < lm2.birth))
WHERE (indexc,birth) in (
select indexc, max(birth)
from Landmark
where Indexc IN (
SELECT Indexc
FROM MapPoint
WHERE BuildDate IS NULL));