选择给定条件的行

时间:2016-03-16 21:05:04

标签: sql oracle window-functions

Oracle sql表名为" TEST"

id  amount  date
1   0   1/2/2015
2   100 1/2/2015
3   2   5/10/2016
4   55  5/10/2016

我想选择有两行具有相同日期的行,其中一个量为0而另一个量大于0,而金额较低的行也具有最低的ID。

这是我到目前为止所做的,但我不确定如何确保0金额的行也具有两行的较低ID。

select * from TEST
where id in(    
select id   
(select id,
       created_dt,
       sum(case when amount=0 then 1 else case when amount>0 then 2 end end) 
       over (partition by d.created_dt) as checkAmount
from TEST)
where checkAmount = 3)

3 个答案:

答案 0 :(得分:0)

我将您的意图解释为只保留那些有两行符合您已经尝试的查询的日期组。如果您的问题是关于符合条件的行对,那么这种方法就不是您需要的方法。

根据您的金额范围,您可以使用缩放系数将ID和金额合并为一个值:

 Title Cell
 File Info Cell
 Time Date Cell

 Data1, Data 2
 Data1, Data 2
 Data1, Data 2
 Data1, Data 2
 Data1, Data 2
 Data1, Data 2
 Data1, Data 2
 Data1, Data 2
 Data1, Data 2
 Data1, Data 2
 Data1, Data 2
 Data1, Data 2
 Data1, Data 2
 Data1, Data 2
 ....(continues for around 800 rows)

 Second Table Title Cell
 Col1Title, Col2Title, ColTitle, Col4Title ....(continues for around 50 columns)
 Data 3,    Data4,     Data 5,   Data6 ....(continues for around 50 columns)
 Data 3,    Data4,     Data 5,   Data6 ....(continues for around 50 columns)
 Data 3,    Data4,     Data 5,   Data6 ....(continues for around 50 columns)
 Data 3,    Data4,     Data 5,   Data6 ....(continues for around 50 columns)
 Data 3,    Data4,     Data 5,   Data6 ....(continues for around 50 columns)
 Data 3,    Data4,     Data 5,   Data6 ....(continues for around 50 columns)
 Data 3,    Data4,     Data 5,   Data6 ....(continues for around 50 columns)    
 Data 3,    Data4,     Data 5,   Data6 ....(continues for around 50 columns)
 ...(Continues for around 1500 rows)
 End of CSV

同样,你可以尝试这个(作为最终条件的替代品)虽然它可能会导致溢出而不需要小心。这个想法应该仍然合理:

select created_dt, min(id), max(id), max(amount)
from TEST
group by created_dt
having
        count(*) = 2 and min(amount) = 0 and max(amount) > 0
    and min(10000 * id + amount) = min(10000 * id)

另一种可能聪明的方式:

    and max(id) * max(amount) = max(id * amount)

或者最安全和最简单的,这两个选项中的任何一个:

    and min(id) = max(case when amount = 0 then id else -id end)

完整的查询是:

    and min(id) + min(amount) = min(id + amount)
    and max(id) + max(amount) = max(id + amount)

编辑:将所有数据放在一行可能确实是一个优势,但我意识到您可能希望将其保留在两行中。如果您只是返回这些值而不是其他列,那么它仍然很容易获得。 请注意,如果有必要,您仍然可以使用ID来连接它们。

select created_dt, min(id), max(id), max(amount)
from TEST
group by created_dt
having
        count(*) = 2 and min(amount) = 0 and max(amount) > 0
    and min(id) + min(amount) = min(id + amount)

此查询可以在没有with data as ( select created_dt, min(id) as min_id, max(id) as max_id, max(amount) as max_amount from TEST group by created_dt having count(*) = 2 and min(amount) = 0 and max(amount) > 0 and min(id) + min(amount) = min(id + amount) ) select split.* from data cross apply ( values (created_dt, min_id, 0), (created_dt, max_id, max_amount) ) split(created_dt, id, amount) withcross apply的情况下编写,前提是这些查询不是您可以使用的任何工具。

答案 1 :(得分:0)

Oracle安装程序

CREATE TABLE test ( id,  amount, dt ) AS
SELECT  1,   0, DATE '2016-02-01' FROM DUAL UNION ALL -- Valid
SELECT  2, 100, DATE '2016-02-01' FROM DUAL UNION ALL -- Valid
SELECT  3,   2, DATE '2016-10-05' FROM DUAL UNION ALL -- Non-zero group
SELECT  4,  55, DATE '2016-10-05' FROM DUAL UNION ALL -- Non-zero group
SELECT  5,   5, DATE '2016-01-01' FROM DUAL UNION ALL -- +ve before zero
SELECT  6,   0, DATE '2016-01-01' FROM DUAL UNION ALL -- +ve before zero
SELECT  7,  -5, DATE '2016-01-01' FROM DUAL UNION ALL -- -ve
SELECT  8,   0, DATE '2016-01-02' FROM DUAL UNION ALL -- More than 2 rows
SELECT  9,   1, DATE '2016-01-02' FROM DUAL UNION ALL -- More than 2 rows
SELECT 10,   2, DATE '2016-01-02' FROM DUAL UNION ALL -- More than 2 rows
SELECT 11,   0, DATE '2016-01-03' FROM DUAL UNION ALL -- Valid
SELECT 12,  -1, DATE '2016-01-03' FROM DUAL UNION ALL -- -ve
SELECT 13,   2, DATE '2016-01-03' FROM DUAL;          -- Valid

<强>查询

SELECT id,amount,dt
FROM   (
  SELECT t.*,
         CASE
           WHEN amount = 0 THEN LEAD( CASE WHEN amount > 0 THEN id END ) IGNORE NULLS OVER ( PARTITION BY dt ORDER BY id )
           WHEN amount > 0 THEN LAG( CASE WHEN amount = 0 THEN id END ) IGNORE NULLS OVER ( PARTITION BY dt ORDER BY id )
           END AS is_valid,
         COUNT( CASE amount WHEN 0 THEN 1 END ) OVER ( PARTITION BY dt ) AS num_zeros,
         COUNT( CASE WHEN amount > 0 THEN 1 END ) OVER ( PARTITION BY dt ) AS num_positive
  FROM   test t
)
WHERE is_valid IS NOT NULL
AND   num_zeros    = 1
AND   num_positive = 1;

<强>输出

        ID     AMOUNT DT                
---------- ---------- -------------------
        11          0 2016-01-03 00:00:00 
        13          2 2016-01-03 00:00:00 
         1          0 2016-02-01 00:00:00 
         2        100 2016-02-01 00:00:00 

答案 2 :(得分:0)

我会将此作为一个简单的UNION ALL查询:获取金额= 0的记录,其中存在较高的ID,在同一日期具有正数量加上获得的数量&gt; 0记录,其中存在较低的ID且数量为零在同一天。

select * 
from test
where amount = 0
and exists
(
  select *
  from test other
  where other.created_dt = test.created_dt
  and other.id > test.id
  and amount > 0
)
union all
select * 
from test
where amount > 0
and exists
(
  select *
  from test other
  where other.created_dt = test.created_dt
  and other.id < test.id
  and amount = 0
);