如何识别密钥列中的正最小值或负最大值?

时间:2016-07-07 21:23:45

标签: sql oracle postgresql

我有以下列 - Person_ID Days。对于一个人身份证,可以多天。像这样:

Person_Id Days
1000      100
1000      200
1000      -50
1000      -10
1001      100
1001      200
1001       50
1001       10
1002      -50
1002      -10

我需要解决以下问题:

如果天列的所有值都是正值,则我需要最少的person_id天数。如果日期列有正面和负面,我需要最小的正面。如果所有的负面因素,我需要最多的负数。

输出如:

Person_id Days
1000      100
1001       10
1002      -10

我尝试使用case语句,但我无法在条件和分组中使用相同的列。

5 个答案:

答案 0 :(得分:3)

试试这个(Postgres 9.4 +):

select person_id, coalesce(min(days) filter (where days > 0), max(days))
from a_table
group by 1
order by 1;

答案 1 :(得分:0)

Oracle安装程序

CREATE TABLE table_name ( Person_Id, Days ) AS 
SELECT 1000, 100 FROM DUAL UNION ALL
SELECT 1000, 200 FROM DUAL UNION ALL
SELECT 1000, -50 FROM DUAL UNION ALL
SELECT 1000, -10 FROM DUAL UNION ALL
SELECT 1001, 100 FROM DUAL UNION ALL
SELECT 1001, 200 FROM DUAL UNION ALL
SELECT 1001,  50 FROM DUAL UNION ALL
SELECT 1001,  10 FROM DUAL UNION ALL
SELECT 1002, -50 FROM DUAL UNION ALL
SELECT 1002, -10 FROM DUAL;

<强>查询

SELECT person_id, days
FROM   (
  SELECT t.*,
         ROW_NUMBER() OVER ( PARTITION BY person_id
                             ORDER BY SIGN( ABS( days ) ),
                                      SIGN( DAYS ) DESC,
                                      ABS( DAYS )
                           ) AS rn
  FROM   table_name t
)
WHERE  rn = 1;

<强>输出

 PERSON_ID       DAYS
---------- ----------
      1000        100 
      1001         10 
      1002        -10 

答案 2 :(得分:0)

select Person_id, min(abs(days)) * days/abs(days) from table_name 
group by Person_id

- + handle zero_divide .. SORRY ..以上只适用于MySQL。

这样的东西可以在任何相当于上述查询的地方工作:

select t.Person_id , min(t.days) from table_name t, 
    (select Person_id, min(abs(days)) as days from table_name group by Person_id) v 
  where t.Person_id = v.Person_id 
  and abs(t days)   = v.days 
  group by Person_id;

OR

select id, min(Days) from ( 
    select Person_id, min(abs(Days)) as Days from temp group by Person_id 
    union 
    select Person_id, max(Days) as Days from temp group by Person_id
) temp 
group by Person_id;

答案 3 :(得分:0)

Oracle解决方案:

with
     input_data ( person_id, days) as (
     select 1000, 100 from dual union all
     select 1000, 200 from dual union all
     select 1000, -50 from dual union all
     select 1000, -10 from dual union all
     select 1001, 100 from dual union all
     select 1001, 200 from dual union all
     select 1001,  50 from dual union all
     select 1001,  10 from dual union all
     select 1002, -50 from dual union all
     select 1002, -10 from dual
     )
select person_id,
       NVL(min(case when days > 0 then days end), max(days)) as days
from   input_data
group by person_id;



 PERSON_ID       DAYS
---------- ----------
      1000        100
      1001         10
      1002        -10

对于每个person_id,如果至少有一个days值严格为正值,那么min将仅接管肯定days并将被退回按NVL()。否则,min()将返回null,NVL()将返回max()所有days(所有这些都是负数或0)。

答案 4 :(得分:0)

您可以通过在sql server中使用GroupBy子句来完成此操作。请看下面的查询: -

CREATE TABLE #test(Person_Id INT, [Days] INT)
DECLARE @LargestNumberFromTable INT;

INSERT INTO #test
SELECT 1000    , 100  UNION
SELECT 1000    ,  200 UNION
SELECT 1000    ,  -50 UNION
SELECT 1000    ,  -10 UNION
SELECT 1001    ,  100 UNION
SELECT 1001    ,  200 UNION
SELECT 1001    ,   50 UNION
SELECT 1001    ,   10 UNION
SELECT 1002    ,  -50 UNION
SELECT 1002    ,  -10 

SELECT @LargestNumberFromTable = ISNULL(MAX([Days]), 0)
FROM #test

SELECT Person_Id
    ,CASE WHEN  SUM(IIF([Days] > 0,[Days] , 0)) = 0 THEN MAX([Days]) -- All Negative
        WHEN SUM([Days]) = SUM(IIF([Days] > 0, [Days], 0)) THEN MIN ([Days]) -- ALL Positive
        WHEN SUM([Days]) <> SUM(IIF([Days] > 0, [Days], 0)) THEN MIN(IIF([Days] > 0, [Days], @LargestNumberFromTable)) --Mix (Negative And positive)
    END AS [Days]       
FROM #test
GROUP BY Person_Id

DROP TABLE #test

Result