2016-03-08 51 views
3

对于所有人“OMG!他正在使用图像:O:O:O”人(原文发表于此):SQL(ORACLE):使用2个或更多相关/配对容器查询“指针”的内部查询

我有一个表:

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,非条件语句,变量或光标......)带来对于每一个日期d它自己的每一个ID,日期的一行以及具有VALUE的ID。如果日期没有其特定ID的值,则必须找到最近的日期。

即:

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

结果:

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

第二结果行具有不同的日期,因为还没有发现日期2016年6月3日和ID = 6的记录。这就是为什么带来最匹配的日期。噢!和最接近我的意思是,之前。不是在约会之后。因此,如果日期不匹配,则指定的日期日期或最近的日期。

我可以为每一行输入创建一个查询,最后从all'em创建一个UNION。但这不是一个解决问题的优雅方法。并且在每个循环上抛出查询都会启用PHP并不是一个选项。




原来的线程:

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

说,我要尽量简明,并在最后这个问题,但首先,让我暴露environtment:

  • 我有一个tipical日期/数据类型/值表。

enter image description here

  • 我用红线去日期变更块划分视觉。蓝色箭头标记“数据类型”ID(来自另一个表)列,另一个蓝色箭头标记与这些值相关的日期。 所以你有不同的type-id的日期块,每一个你有一个变化值(CAMBIO):绿色箭头。

现在,我能做什么?这给我的坎比奥值某些特定日期的查询:

enter image description here

注意:GRUPO是表中存在的另一列,我总是需要从这个GRUPO型,1的值。这是必要的。

下一步是,可能发生的情况是,对于指定的DATE,不存在表记录上的值。所以我必须找到最接近的一个。

我可以做这样的查询:

enter image description here

你可以第一个图像上看到,有对3月6日和3月5日没有记录,所以通过这个查询,我可以去最现有的最接近的价值,在这种情况下,与3月4日相同

与查询的问题是,我需要指定DIVISA_C柱为特定值,假设5和10。然后我colud经历这样的:

enter image description here

这对于作品不错现有的DIVISA_C ids上的结果,但如果我需要一个不包含在“日期块”(即:2016-03-04)中的ID,我们说6,那么我得不到这个DIVISA_C ID的结果,并且我需要才能得到它的结果,具体地说,就是我之前展示的最接近的日期。

如果我做的:

enter image description here

没有谈到这6 ID。与上次查询结果相同。 在这种情况下,我知道如何解决过的东西:

enter image description here

你看,我已经从内部查询到自DIVISA_C ID的WHERE增加了一个“指针”,基本上分从ourtsider/container查询到DIVISA_C。这会导致对于内部查询中的指定DATE,容器查询“IN列表”中的每个单个ID都会按预期方式带来最可能的关联行。因此,如果内部查询可以为指定的DIVISA_C标识解析指定的日期,它会带来记录。否则,为DIVISA_C id值带来最接近的日期。这是我所需要的。

NOTE:我在内部查询中添加了一些额外的过滤器,以与外部/容器查询保持一致。根本不是问题或变化。现在

,解释说,来这里的真正的问题:

- 现在我已经日期列表,并为每一个这些日期的,DIVISA_C ID的列表。我需要做一个查询,没有PL-SQL(所以没有FOR,没有IF,没有CURSORS等等),只是一个SELECT组合,它带给我预期的结果,基本上这是最后一个我已经向你展示了结果,但是与他们相关的DIVISA_C ID列表有很多日期。

要和榜样,我已经表现出了最后的查询可以像这样解释:

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

,这给我带来了3排,aproximated日期为每个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回路转单查询多达输入列表具有的行。

或者我可以创建每个单一的查询与列表上的输入行,并作出所有的联合国教育,以创建一个masive长字符串查询将给我精确的结果,我需要,但这不是选项。 我需要一个更更高雅的方式来解决这个问题,在这里我卡住了... :(

我虽然已经像这样的东西:

enter image description here

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

我以为创建一个INNER连接上的异常查询到同一个表,所以表反对自己有2个指针不知何故,并结合他们的情况......但我不知道该怎么办它正确...

你能给我点亮这个吗?

感谢所有人,对于长篇文章感到抱歉!但我认为通过图像解释它更加舒适。

Greetings,

Mark。

+0

http://meta.stackoverflow.com/questions/285551/why-may-i-not上传图片的代码时,要求提问/ 285557#285557 –

+0

@a_horse_with_no_name来吧。在这个特殊情况下,图片只是为了展示。没有用的其他任何东西。问题可以直接抛出,根本不显示任何示例。是帖子中最后一条粗体文字。那些在这里可以直观地证明我在问什么。 – Lightworker

+0

@Lightworker不是所有人都能看到图像(例如,它们被防火墙阻挡),所以通过使用它们,您可以在格式化文本中提供相同信息,从而防止某些人能够帮助您。 – Boneist

回答

2

使用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,如果你更舒适的(它可以缩短语法时帝维名单很长),喜欢这里:

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 
+0

男人......你太棒了!你真的有一个很棒的Oracle级别,就像你真正在这里展示的那样。请您花一点时间来解释一下它的工作原理和原理?也许编辑帖子并添加一些额外的信息/提示?我很想真正理解哪个是超越它的魔法...... :)也许row_number()部分,你如何命令它,以及正在做什么。还有你怎么做INNER JOIN呢。再次感谢!! – Lightworker

+1

对于每个元组(input_date,divisa),我正在检查日期的差异(input_date和fecha)。 Row_number()使用'partition by'子句“组织”这些差异,并用'order by'子句对这些行进行“排序”,因此与input_date最接近的日期的值最小。我们只对RN = 1的行感兴趣。链接到[rownumber()](https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions137.htm)文档,也请查看其他分析功能和例子。 –