Oracle 11g从N到1表选择公共表到1到N表,带有限制

时间:2017-10-27 08:29:15

标签: sql oracle select join

问题

我有这些表格和数据:

CREATE TABLE a (
    id   NUMBER(3) NOT NULL
);

ALTER TABLE a ADD CONSTRAINT a_pk PRIMARY KEY ( id );

CREATE TABLE b (
    id   NUMBER(6) NOT NULL,
    year NUMBER(4) NOT NULL,
    a_id NUMBER(3) NOT NULL
);

ALTER TABLE b ADD CONSTRAINT b_pk PRIMARY KEY ( id );

CREATE TABLE c (
    id         NUMBER(9) NOT NULL,
    start_date DATE NOT NULL,
    end_date   DATE NOT NULL,
    a_id       NUMBER(3) NOT NULL
);

ALTER TABLE c ADD CONSTRAINT c_pk PRIMARY KEY ( id );

ALTER TABLE b
    ADD CONSTRAINT b_a_fk FOREIGN KEY ( a_id )
        REFERENCES a ( id );

ALTER TABLE c
    ADD CONSTRAINT c_a_fk FOREIGN KEY ( a_id )
        REFERENCES a ( id );

Insert into A (ID) values ('1');
Insert into A (ID) values ('2');
Insert into A (ID) values ('3');

Insert into B (ID,YEAR,A_ID) values ('1','2017','1');
Insert into B (ID,YEAR,A_ID) values ('2','2017','2');
Insert into B (ID,YEAR,A_ID) values ('3','2013','3');
Insert into B (ID,YEAR,A_ID) values ('4','2014','3');
Insert into B (ID,YEAR,A_ID) values ('5','2017','3');
Insert into B (ID,YEAR,A_ID) values ('6','2013','1');

Insert into C (ID,START_DATE,END_DATE,A_ID) values ('1',to_date('01/01/13','DD/MM/RR'),to_date('01/01/14','DD/MM/RR'),'3');
Insert into C (ID,START_DATE,END_DATE,A_ID) values ('2',to_date('01/06/17','DD/MM/RR'),to_date('01/01/18','DD/MM/RR'),'3');
Insert into C (ID,START_DATE,END_DATE,A_ID) values ('3',to_date('01/01/14','DD/MM/RR'),to_date('01/06/14','DD/MM/RR'),'3');
Insert into C (ID,START_DATE,END_DATE,A_ID) values ('4',to_date('01/01/17','DD/MM/RR'),to_date('01/10/17','DD/MM/RR'),'1');
Insert into C (ID,START_DATE,END_DATE,A_ID) values ('5',to_date('01/04/13','DD/MM/RR'),to_date('01/10/13','DD/MM/RR'),'1');
Insert into C (ID,START_DATE,END_DATE,A_ID) values ('6',to_date('01/01/17','DD/MM/RR'),to_date('01/06/18','DD/MM/RR'),'2');

我需要每个B:B.id,A.id和C.id,其中C是第一个最早的start_date行,其中B.year位于C.start_date和C.end_date之间,如下所示:

BID AID CID
1   1   4
2   2   6
3   3   1
4   3   3
5   3   2
6   1   5

请帮助我找到答案或在哪里找到相关信息。

我知道嵌套选择并不能识别外面的表A,但我不知道如何为此制作一个有效的解决方案,或者我错过了一些非常简单的东西;我不知道。我希望你能帮助我。

解决方案

在社区的帮助下我有这样的事情:

select B.id BID, A.id AID, C.id CID
from B
    join A on B.A_id = A.id
    join C
    on C.A_id = A.id 
where B.year between extract (year from C.start_date) and extract(year from C.end_date)
order by B.id ASC , c.start_date asc;

它返回了:

BID AID CID
1   1   4
2   2   6
3   3   1
4   3   1
4   3   3
5   3   2
6   1   5

但真正的答案是:

select bid, aid, cid
from
  (select B.id bid, A.id aid, C.id cid, 
               row_number() over (partition by b.id order by c.start_date) rn
          from B
          join A on B.A_id = A.id
          join c on C.A_id = A.id
           and B.year between extract(year from c.start_date) 
                          and extract(year from c.end_date))
where rn = 1;

返回我正在搜索的内容。

感谢所有人,尤其是Ponder Stibbons,这让我有了这样做的方法。

2 个答案:

答案 0 :(得分:0)

您的DDL和查询存在太多问题。

避免使用oracle保留关键字作为列名。 end作为列名的那个永远不会运行。

year   NUMBER(4) NOT NULL,
start     DATE NOT NULL,
end       DATE NOT NULL,

而是使用类似year_t,start_t, end_t的东西或有意义的东西。

  

我想用B.id,A.id和C.id做一个选择,其中C是第一个   B.year位于C.start和C.end之间的行,每个B。

您不能使用and rownum < 1执行此操作。实际上rownum < 1永远不会返回任何行。

您使用的列名也是错误的。例如:您在b.start中没有使用order by

因此,考虑到这些更改,此查询将起作用。

select B.id, A.id, C.id
from B
    join A on B.A_id = A.id
    join C
    on C.A_id = A.id 
where B.year_t between to_number(to_char(C.start_t, 'YYYY')) and to_number(to_char(C.end_t, 'YYYY')) 
            order by c.start_t,B.id ASC ; 

但是,它不会给你

  

B.year位于C.start和C.end之间的第一行,每一行   B

使用数据澄清您在问题中究竟需要哪些样本记录。然后我会尝试回答。

答案 1 :(得分:0)

构建join,为每个id编号行并只占第一行:

select bid, aid, cid 
  from (select B.id bid, A.id aid, C.id cid, 
               row_number() over (partition by c.a_id order by b.year) rn
          from B
          join A on B.A_id = A.id
          join c on C.A_id = A.id
           and B.year between extract(year from c.start_date) 
                          and extract(year from c.end_date))
  where rn = 1;

测试:

create table a (id number(3));
create table b (id number(6), year number(4), a_id   number(3));
create table c (id number(9), start_date date, end_date date, a_id  number(3));

insert into a values (1);
insert into a values (2);

insert into b values (1, 1901, 1);
insert into b values (2, 1905, 1);
insert into b values (3, 1903, 1);
insert into b values (4, 1902, 2);

insert into c values (1, date '1902-01-01', date '1912-07-17', 1);
insert into c values (2, date '1900-02-18', date '1910-06-08', 2);

结果:

    BID  AID        CID
------- ---- ----------
      3    1          1
      4    2          2