加入Oracle表格的完全匹配和最接近的匹配

时间:2014-04-10 07:51:49

标签: sql oracle join

我正在尝试加入两个性能指标,系统统计信息和内存使用情况表。这些表中的条目有不同的时间表。我需要通过在两个表中找到System_Name的完全匹配来加入表,并且最接近WRITETIME。写入时间使用系统自己的时间概念,而不是标准的Oracle时间戳。

我可以从一个表中选择最近的时间戳,例如:

select "Unix_Memory"."WRITETIME", ABS ('1140408134015004' - "Unix_Memory"."WRITETIME") 
  as Diff from "Unix_Memory" 
  where "Unix_Memory"."WRITETIME" > '1140408104015004' order by Diff;

那里的常量将在我的脚本中进行参数化。

但是,当我尝试将其扩展为更大的查询时:

select "System"."System_Name", "System"."WRITETIME" as SysStamp,
from "System" 
join "Unix_Memory"  on "System"."System_Name" = "Unix_Memory"."System_Name" 
and "Unix_Memory"."WRITETIME" = ( 
select Stamp from (
select "Unix_Memory"."WRITETIME" as Stamp, 
ABS ( "System"."WRITETIME" - "Unix_Memory"."WRITETIME") as Diff 
  from "Unix_Memory" where "Unix_Memory"."WRITETIME" > '1140408104015004' and rownum = 1 order by Diff
  )
)
WHERE "System"."System_Name" in ('this','that', 'more')
and   "System"."WRITETIME"  > '1140408124015004';

我明白了:

Error at Command Line:38 Column:72
Error report:
SQL Error: ORA-00904: "System"."WRITETIME": invalid identifier
00904. 00000 -  "%s: invalid identifier"

我尝试了一些变化,但我没有接近。

2 个答案:

答案 0 :(得分:1)

不幸的是,列名仅在下一个嵌套级别中已知。因此,select Stamp from ...中会知道System.writetime,但select "Unix_Memory"."WRITETIME" as Stamp ...

中不再知道

无论如何,无论如何,你会选择一个相当随机的标记,第一个Unix_Memory"。" WRITETIME" > ' 1140408104015004'发现是精确的,因为rownum = 1在order by之前执行。你必须完全重写你的陈述。

编辑:这是使用MIN / MAX KEEP重写语句的一种可能性:

select 
  s.system_name, 
  s.writetime as sysstamp,
  min(um.id) keep (dense_rank first order by abs(s.writetime - um.writetime)) as closest_um_id
from system sys 
join unix_memory um  on s.system_name = um.system_name 
where s.system_name in ('this','that', 'more')
and s.writetime > '1140408124015004'
and um.writetime > '1140408104015004'
group by s.system_name, s.writetime
order by s.system_name, s.writetime;

如果你需要的不仅仅是unix_memory的ID,那么用另一个选择包围它:

select   
  sy.system_name, 
  sy.sysstamp,
  mem.*
from
(
  select 
    s.system_name, 
    s.writetime as sysstamp,
    min(um.id) keep (dense_rank first order by abs(s.writetime - um.writetime)) as closest_um_id
  from system sys 
  join unix_memory um  on s.system_name = um.system_name 
  where s.system_name in ('this','that', 'more')
  and s.writetime > '1140408124015004'
  and um.writetime > '1140408104015004'
  group by s.system_name, s.writetime
) sy
join unix_memory mem on mem.id = sy.closest_um_id
order by sy.system_name, sy.sysstamp;

答案 1 :(得分:1)

您必须在内部选择中声明系统表。

select "System"."System_Name", "System"."WRITETIME" as SysStamp,
from "System" 
join "Unix_Memory"  on "System"."System_Name" = "Unix_Memory"."System_Name" 
and "Unix_Memory"."WRITETIME" = ( 
select Stamp from (
select "Unix_Memory"."WRITETIME" as Stamp, 
ABS ( "System"."WRITETIME" - "Unix_Memory"."WRITETIME") as Diff 
  from "Unix_Memory" 
  -- THE NEXT LINE IS MISSING IN YOUR CODE
  INNER JOIN "System" ON "System.System_Name" = "Unix_Memory"."System_Name"
                     and "System"."WRITETIME"  > '1140408124015004'
  -- end of missing
  where "Unix_Memory"."WRITETIME" > '1140408104015004' and rownum = 1 order by Diff
  )
)
WHERE "System"."System_Name" in ('this','that', 'more')
and   "System"."WRITETIME"  > '1140408124015004';