带有连接的内部查询中的order by子句

时间:2013-10-04 18:08:06

标签: sql plsql oracle11g

create table items(item_pk integer, pgid integer, prod_id integer, PRIMARY KEY(item_pk));
create table products(prod_id integer, version  integer, pgid  integer, flag char(1), PRIMARY KEY(prod_id));

insert into items(item_pk,  pgid) values (1,  21);
insert into items(item_pk, pgid) values(2,  31);
insert into products(prod_id, version, pgid, flag) values (11, 101,  21, 'Y');
insert into products(prod_id, version, pgid, flag) values (22, 101,  21, 'N');
insert into products(prod_id, version, pgid, flag) values(33, 101, 31, 'N');

   declare 
    prod_version NUMBER := :1 ;  
    begin  
    update items i set i.prod_id = ( 
     select p.prod_id from products p where 
     p.version = prod_version and p.pgid = i.pgid and rownum =1 
     order by p.flag desc
    ) where i.xyz is null
    commit; end;    

产品表有两个条目 - 伪(flag ='Y')和实际(flag ='N')。

如果没有伪产品,需要获取实际产品。

上述查询导致编译错误。 内部查询可能会返回多个记录,但我只需要第一个记录(即'Y'记录。如果找不到'Y'rec,需要'N'rec)。

3 个答案:

答案 0 :(得分:0)

有点矫枉过正但应该有效:

select prod_id
from (
    select p.prod_id, ROW_NUMBER() OVER (ORDER BY p.flag DESC) as rn
    from products p
    where p.version = prod_version and p.pgid = i.pgid
    )
where rn=1

答案 1 :(得分:0)

您需要在更新查询中选择其他选项。我想它需要像这样;

update items i set i.prod_id = ( 
  select prod.id from (
    select p.prod_id,rownum rn from products p where 
    p.version = prod_version and p.pgid = i.pgid
  order by p.flag desc) x 
    where x.rn=1
) where i.xyz is null

答案 2 :(得分:0)

我没有任何ide可用来检查我的语法。我是从文本编辑器这样做的,所以可能存在错误。

我总是尽量避免在查询中使用任何类型的rownum,所以这可以使用子查询来处理'N'值。

declare 
   prod_version NUMBER := :1 ;  
begin  
  update items i set i.prod_id = (select p.prod_id
                                    from products p
                                   where p.version = prod_version
                                     and p.pgid = i.pgid
                                     and (p.flag = 'Y' 
                                          or (p.flag = 'N' and 0 = (select count(*)
                                                                  from products p2
                                                                 where p2.version = prod_version
                                                                   and p2.pgid = i.pgid
                                                                   and p2.flag = 'Y')
                                              )
                                          )
                                 )
  where i.xyz is null
  commit;
end;

但是,您总是可以使用plsql并执行类似的操作。

declare
  temp_prod_id number;
  prod_version NUMBER := :1 ; 

begin
  for v_rec in (select id, pgid from items where xyz is null) loop
    begin
      select prod_id into temp_prod_id from products p
       where p.version = prod_version
         and p.pgid = v_rec.pgid
         and p.flag = 'Y';
    exception
    when no_data_found then
      select prod_id into temp_prod_id from products p
       where p.version = prod_version
         and p.pgid = v_rec.pgid
         and p.flag = 'N';
  -- this assumes there's always an 'N' record if not wrap this select with exception handling.
    end;

    update items i set i.prod_id = temp_prod_id
    where items.id = v_rec.id;
    commit;
  end loop;
end;

就像我上面说过的那样,我可以自由地处理这个,所以请仔细检查语法。