SQL (ORACLE): 内部查询有 2 个或更多 related/paired 容器查询 "pointers"

SQL (ORACLE): inner-query with 2 or more related/paired container-query "pointers"

对于所有 "OMG! HE IS USING IMAGES :O :O :O" 人(原始 POST 在此之下):

我有一个 table:

date1 | id1 | value
date1 | id2 | value
date1 | id3 | value
date1 | id4 | value
-------------------
date2 | id1 | value
date2 | id2 | value
date2 | id5 | value
date2 | id7 | value
-------------------
date3 | id4 | value
date3 | id5 | value
date3 | id10 | value
date3 | id11 | value
-------------------
...
-------------------
dateN | id1 | value
dateN | id2 | value
dateN | id3 | value
dateN | id4 | value

有这样的输入:

date: X - ids: 2, 3
date: Y - ids: 4
date: Z - ids: 2, 4, 5
...

需要一个查询(非 PL、非条件、变量或游标...)为每个日期和它自己的每个 ID、一行日期和带有特定 VALUE 的 ID .如果日期没有其特定 ID 的值,则必须找到最近的日期。

即:

date: 06/03/2016 - ids: 5, 6

结果:

06/03/2016|5|value
04/03/2016|6|value

第二个结果行有不同的日期,因为没有找到日期为 06/03/2016 且 ID=6 的记录。这就是为什么带来最接近的匹配日期。哦!,最接近我的意思是,之前。不在日期之后。因此,如果日期不匹配,则指定相同的指定日期或最近的日期。

我可以为输入的每一行创建一个查询,最后从所有行中创建一个 UNION。但这不是解决它的优雅方法。并且在每个循环打开时抛出查询 PHP 也不是一个选项。




原帖:

早上好,首先请原谅我的英语不好,因为我来自西班牙。

说到这里,我会在最后尽量简洁地回答这个问题,但首先让我暴露一下环境:

现在,我能做什么?为我提供某个特定日期的 CAMBIO 值的查询:

注意:GRUPO 是存在于table 上的另一个列,我总是需要来自这个grupo-type 的值,1。这是必要的。

下一步是,对于指定的日期,table 记录中可能不存在值。所以我必须找到最近的一个。

我可以这样查询:

您可以在第一张图片上看到没有 3 月 6 日或 3 月 5 日的记录,因此通过此查询,我可以找到最接近的现有值,在本例中为同一个 3 月 4 日。

这些查询的问题是,我需要将 DIVISA_C 列指定为特定值,比方说 5 和 10。然后我通过这个:

这对结果中现有的 DIVISA_C id 很有效,但是如果我需要一个不包含在 "date-block" 中的 ID(即:2016-03-04),让我们说6,然后我没有得到这个 DIVISA_C id 的结果,并且 我需要 得到它的结果,具体地说,就是我所展示的最接近的日期之前。

如果我这样做:

这个 6 ID 没有任何结果。与上次查询相同的结果。 这样的话,我也知道怎么解决了:

你看,我在内部查询到自身 DIVISA_C id 的 WHERE 上添加了一个 "pointer",它基本上指向 DIVISA_C 来自 [=146] =]查询。这导致对于内部查询的指定日期,对于容器查询 "IN list" 中的每个 ID,都会按预期带来最可能的关联行。因此,如果内部查询可以为指定的 DIVISA_C id 解析指定的日期,它会带来记录。否则,为 DIVISA_C id 值带来最接近的日期。这正是我所需要的。

注意: 我在内部查询中添加了一些额外的过滤器以与 outside/container 查询保持一致。根本不是问题或需要考虑的变化。

现在,解释一下,真正的问题来了:

- 现在我有一个日期列表,对于每个日期,都有一个 DIVISA_C id 列表。我需要做一个查询,没有 PL-SQL(所以没有 FOR,没有 IF,没有 CURSORS,等等......),只是一个 SELECT 组合,结果是预期,这基本上是我向您展示的最后一个结果,但是对于很多日期及其相关的 DIVISA_C ids 列表。

举个例子,我展示的最后一个查询可以这样解释:

date: 06/03/2016 - divisa_c ids: 5, 6, 10

在这种情况下,这为我带来了 3 行每个 ID 的近似日期,因为 3 月 6 日没有任何 DIVISA_C ID 的记录。

现在我有一个完整的输入列表,只需一个查询即可解决,即:

date: 06/03/2016 - divisa_c ids: 5, 6, 10
date: 05/02/2016 - divisa_c ids: 5
date: 03/02/2016 - divisa_c ids: 5, 6
date: 01/01/2016 - divisa_c ids: 6, 10
date: 31/12/2015 - divisa_c ids: 4, 6, 10, 12
date: 24/10/2015 - divisa_c ids: 3, 4, 5, 11
...

当然,我可以在每个 PHP 循环中针对输入列表的行数进行一次查询。

或者我可以用列表中的输入行创建每个查询,然后将所有行联合起来,以创建一个巨大的长字符串查询,它会准确地给出我需要的结果,但这不是一个选项。 我需要用更优雅的方式解决它,我卡在这里了...:(

虽然我遇到过这样的事情:

你看,外部 WHERE 上的某种 "linked" 数据包,导致内部查询为每个关联日期和内部查询解析 DIVISA_C IN 列表中的所有行,DATE 也是一个指针......但是你可以想象这不起作用,因为内部查询通过 FECHA =(子查询......)链接在 where 中,并且没有意义的数据包我在此之后写道...

我想在外部查询上创建一个 INNER JOIN 到完全相同的 table,因此 table 以某种方式针对自身有 2 个指针并将它们组合起来以适应这种情况...但我不知道如何正确地做...

你能给我解释一下吗?

感谢大家,抱歉这么久post!不过我觉得用图片来解释更符合table

你好,

马克.

使用 row_number() 查找最近几天的值。在 with 子句中定义输入参数,在我的测试数据中我使用了 ('2016-03-04', (5)), ('2016-03-06', (5)), ('2016-03 -07',(5、6、10))。 Id 不是必需的,为了清楚起见我添加了它:

with t as ( 
  select 1 id, date '2016-03-04' fecha, 5 divisa from dual union all 
  select 2 id, date '2016-03-06' fecha, 5 divisa from dual union all 
  select 3 id, date '2016-03-07' fecha, 5 divisa from dual union all 
  select 3 id, date '2016-03-07' fecha, 6 divisa from dual union all 
  select 3 id, date '2016-03-07' fecha,10 divisa from dual )
select * from (
  select cd.*, t.fecha input_fecha, t.divisa input_divisa,
         row_number() over (partition by t.fecha, t.divisa order by t.fecha-cd.fecha) rn
    from cotizaciones_div cd 
    join t on cd.divisa_c = t.divisa and cd.grupo = 1 and cd.fecha<=t.fecha)
  where rn=1 order by input_fecha, input_divisa

要定义输入参数,您也可以使用 sys.odcinumberlist 类型,如果它更适合您(当 divisa 列表很长时,它可以缩短语法),例如这里:

  select 1 id, date '2016-03-04' fecha, column_value as divisa 
    from table(sys.odcinumberlist(5)) union all 
  select 2 id, date '2016-03-06' fecha, column_value as divisa 
    from table(sys.odcinumberlist(5)) union all 
  select 3 id, date '2016-03-07' fecha, column_value as divisa 
    from table(sys.odcinumberlist(5, 6, 10)) 

测试数据及输出:

create table cotizaciones_div (codigo number(8), divisa_o number(3), divisa_c number(3), 
  fecha date, cambio number(12, 4), grupo number(3));

insert into cotizaciones_div values ( 1000,  4, 11, date '2016-01-01', 0.5123, 8);
insert into cotizaciones_div values ( 2273, 15,  6, date '1998-12-31', 0,      1);
insert into cotizaciones_div values (63289,  4,  5, date '2016-03-04', 1.0998, 1);
insert into cotizaciones_div values (63297,  4, 10, date '2016-03-04', 7.4622, 1);
insert into cotizaciones_div values (63290,  4, 11, date '2016-03-04', 0.7738, 1);
insert into cotizaciones_div values (63309,  4,  5, date '2016-03-07', 1.1016, 1);
insert into cotizaciones_div values (63317,  4, 10, date '2016-03-07', 7.4619, 1);
insert into cotizaciones_div values (63310,  4, 11, date '2016-03-07', 0.7724, 1);

   CODIGO DIVISA_O DIVISA_C FECHA               CAMBIO GRUPO INPUT_FECHA INPUT_DIVISA
--------- -------- -------- ----------- -------------- ----- ----------- ------------
    63289        4        5 2016-03-04          1,0998     1 2016-03-04             5
    63289        4        5 2016-03-04          1,0998     1 2016-03-06             5
    63309        4        5 2016-03-07          1,1016     1 2016-03-07             5
     2273       15        6 1998-12-31          0,0000     1 2016-03-07             6
    63317        4       10 2016-03-07          7,4619     1 2016-03-07            10