重写SQL查询以获取记录ID和客户编号

时间:2014-08-02 13:18:06

标签: sql oracle

示例数据

+-------------------+-------------+-----------------+---------------------+
| RECORD_ID         | CUST_NO     | IsAccntClosed   | Code                |
+-------------------+-------------+-----------------+---------------------+
|159045             |   2439123   | N               |   13                |
+-------------------+-------------+-----------------+---------------------+
|159048             |   6376150   | Y               |   13                |
+-------------------+-------------+-----------------+---------------------+
|159048             |   9513035   | N               |   13                |
+-------------------+-------------+-----------------+---------------------+
|159049             |   2398524   | N               |   12                |
+-------------------+-------------+-----------------+---------------------+
|159049             |   6349269   | Y               |   12                |
+-------------------+-------------+-----------------+---------------------+
|159049             |   6350690   | Y               |   12                |
+-------------------+-------------+-----------------+---------------------+
|159049             |   6372163   | Y               |   12                |
+-------------------+-------------+-----------------+---------------------+
|159049             |   6393810   | Y               |   12                |
+-------------------+-------------+-----------------+---------------------+
|159049             |   6402062   | Y               |   12                |
+-------------------+-------------+-----------------+---------------------+
|159050             |   2677512   | Y               |   12                |
+-------------------+-------------+-----------------+---------------------+
|159050             |   6349382   | Y               |   12                |
+-------------------+-------------+-----------------+---------------------+
|159050             |   6378137   | Y               |   12                |
+-------------------+-------------+-----------------+---------------------+
|159051             |   2336197   | N               |   12                |
+-------------------+-------------+-----------------+---------------------+
|159051             |   6349293   | N               |   12                |
+-------------------+-------------+-----------------+---------------------+
|159051             |   6350682   | N               |   12                |
+-------------------+-------------+-----------------+---------------------+
|159051             |   6367895   | N               |   12                |
+-------------------+-------------+-----------------+---------------------+
|159060             |   yyyyyy    | Y               |   12                |
+-------------------+-------------+-----------------+---------------------+

IsAccntClosed列指示帐户是否已打开(Y)或帐户是否已关闭(Y)。

我需要为Record_Id满足以下条件之一的行选择Record_ID和cust_no:
1.只有一个客户账户是开放的,可能有一个或多个封闭客户 2.没有开放的客户,只有一个封闭的客户

预期产量:
159045 2439123
159048 9513035
159049 2398524
159060 yyyyyy

像这样的查询会将每一行作为一个单独的组,计数将变为1

select RECORD_ID, CUST_NO, IsAccntClosed, count(IsAccntClosed), Code
  from table1
 group by RECORD_ID, CUST_NO, IsAccntClosed, Code

有关如何编写此查询以获得预期输出的任何建议吗?

4 个答案:

答案 0 :(得分:1)

在下面我添加了另一条记录:

insert into tbl values (159060, 'zzzzzz', 'N', 12);

说明如果record_id只有一个打开的cust_no和一个关闭的cust_no会发生什么。请注意,在结果中,返回的cust_no是zzzzz,因为该帐户是开放的,您提到想要优先于已关闭,如果出现1:1的关系(在这种情况下zzzzzz应该接管yyyyyy,因为yyyyyy关闭而zzzzzz是开放的)

小提琴: http://sqlfiddle.com/#!4/5cb60/1/0

with one_open as
 (select record_id
    from tbl
   where IsAccntClosed = 'N'
   group by record_id
  having count(distinct cust_no) = 1),
one_closed as
 (select record_id
    from tbl
   where IsAccntClosed = 'Y'
   group by record_id
  having count(distinct cust_no) = 1),
bothy as
 (select record_id from one_open intersect select record_id from one_closed)
select *
  from tbl
 where (record_id in (select record_id from one_open) and
       IsAccntClosed = 'N')
    or (record_id not in (select record_id from one_open) and
       record_id in (select record_id from one_closed) and
       IsAccntClosed = 'Y' and
       record_id not in (select record_id from bothy))

答案 1 :(得分:1)

当IsAccntClosed为CHAR列时,你应该能够通过这样的查询得到你想要的东西:

SELECT a.record_id,
  (CASE
     WHEN a.CountOpen=1 THEN a.CustNoOpen
     ELSE                    a.CustNoClosed
  END) AS cust_no
FROM (
  SELECT b.record_id,
    MAX(CASE WHEN b.IsAccntClosed='N' THEN b.cust_no ELSE NULL END) AS CustNoOpen  ,
    SUM(CASE WHEN b.IsAccntClosed='N' THEN 1         ELSE 0    END) AS CountOpen   ,
    MAX(CASE WHEN b.IsAccntClosed='Y' THEN b.cust_no ELSE NULL END) AS CustNoClosed,
    SUM(CASE WHEN b.IsAccntClosed='Y' THEN 1         ELSE 0    END) AS CountClosed
  FROM table1 b
  GROUP BY b.record_id
) a
WHERE a.CountOpen=1 OR (a.CountOpen=0 AND a.CountClosed=1)

内部查询正在对表进行分组。它计算开立和关闭的账户,并且每个组中的任何已结账户和任意一个(随机)账户的一个(随机)cust_no。

外部查询过滤数据并清除所有内容,将打开或关闭的cust_no放在输出结果列中。

请注意,外部查询的WHERE条件具有附带效果,因为您正在查找只有一个打开或单个已关闭帐户的记录,那么内部查询已选择的随机cust_no现在是显著。

编辑:我修复了查询并在SQLFiddle上对其进行了测试。

答案 2 :(得分:0)

select
  record_id,
  cust_no
from (
  select
    record_id,
    cust_no,
    count(case when isAccntClosed='Y' then 1 else null end)
      over (partition by record_id) closed_accounts,
    count(case when isAccntClosed='N' then 1 else null end)
      over (partition by record_id) open_accounts
  from
    table1
  )
where (open_accounts = 1)
   or (open_accounts = 0 and closed_accounts = 1)

答案 3 :(得分:0)

您可以使用条件聚合执行此操作:

select RECORD_ID,
       (case when sum(case when IsAccntClosed = 'N' then 1 else 0 end) = 1
             then max(case when IsAccntClosed = 'N' then max(CUST_NO) end)
             else max(CUST_NO)
        end) as cust_no
from table1
group by RECORD_ID
having sum(case when IsAccntClosed = 'N' then 1 else 0 end) = 1 or
       (sum(case when IsAccntClosed = 'N' then 1 else 0 end) = 0 and
        sum(case when IsAccntClosed = 'Y' then 1 else 0 end) = 1
       )

使用子查询理解逻辑可能更容易:

select recordId,
       (case when numOpen > 0 then OpenCustNo else closedCustNo end) as CustNo
from (select t1.RecordId, sum(case when IsAccntClosed = 'N' then 1 else 0 end) as numOpen,
             sum(case when IsAccntOpen = 'N' then 1 else 0 end) as numClosed,
             max(case when IsAccntClosed = 'N' then cust_no end) as OpenCustNo,
             max(case when IsAccntClosed = 'Y' then cust_no end) as ClosedCustNo
      from table1 t1
      group by record_id
     ) r
where numOpen = 1 or numOpen = 0 and numClosed = 1;