根据某些条件限制记录的更好方法

时间:2018-11-26 18:34:39

标签: sql oracle

我尝试了几种不同的查询来将结果集限制在所需的范围内,但是我一直缺少一些东西。

在我的示例中,我有三种文档类型:注册,标题和凭证。如果ASSET_ID的记录为DOC TYPE =标题,但又有一条记录为DOC_TYPE = Voucher,则我不想显示Voucher行。但是,如果ASSET_ID仅具有凭证行,那么我想显示记录。第三个条件是,如果同一个asset_id具有两个或更多凭证行,那么我只想显示一个。

以下是使用虚拟数据的示例:

ASSET_ID    DOC_TYPE        State
101         Registration    TX
102         Title           AL
103         Title           NY
104         Title           CA
104         Voucher     
105         Title           CA
106         Voucher
106         Title           MD
107         Voucher
107         Voucher

我想到了两种方法。我的第一个想法是编写一个查询,将其从结果中完全删除:

SELECT * FROM assets WHERE doc_type <> 'Voucher'

然后我要去UNION另一个查询,该查询只提取凭证doc_type:

SELECT asset_id, doc_type, state FROM assets WHERE doc_type <> 'Voucher'
UNION
SELECT * FROM (SELECT DISTINCT(asset_id), doc_type, state FROM assets WHERE 
doc_type = 'Voucher')

我最终要做的是编写联合查询来引用原始查询,以查找满足第一个查询中未包含的条件的值。但这感觉写查询的方式效率极低:

SELECT asset_id, doc_type, state FROM assets WHERE doc_type <> 'Voucher'
UNION
SELECT DISTINCT(asset_id), doc_type, state FROM assets WHERE doc_type = 
'Voucher' AND asset_id NOT IN (SELECT asset_id, doc_type, state FROM assets  
WHERE doc_type <> 'Voucher')

以上方法有效,但是我假设有一种比我建议的方法更清洁的方法来处理此问题。有什么建议吗?

1 个答案:

答案 0 :(得分:1)

也许是这样?

SQL> with assets (asset_id, doc_type, state) as
  2    (select 101, 'registration', 'tx' from dual union all
  3     select 102, 'title'       , 'al' from dual union all
  4     select 103, 'title'       , 'ny' from dual union all
  5     select 104, 'title'       , 'ca' from dual union all
  6     select 104, 'voucher'     , null from dual union all
  7     select 105, 'title'       , 'ca' from dual union all
  8     select 106, 'voucher'     , null from dual union all
  9     select 106, 'title'       , 'md' from dual union all
 10     select 107, 'voucher'     , null from dual union all
 11     select 107, 'voucher'     , null from dual
 12    ),
 13  inter as
 14    (select asset_id, doc_type, state,
 15       row_number() over (partition by asset_id
 16                          order by decode(doc_type, 'title', 1, 'voucher', 2)) rn
 17     from assets
 18    )
 19  select asset_id, doc_type, state
 20  from inter
 21  where rn = 1
 22  order by asset_id;

  ASSET_ID DOC_TYPE     ST
---------- ------------ --
       101 registration tx
       102 title        al
       103 title        ny
       104 title        ca
       105 title        ca
       106 title        md
       107 voucher

7 rows selected.

SQL>