oracle 如何在列中为键确定正最小值或负最大值?

kgqe7b3p  于 2023-05-16  发布在  Oracle
关注(0)|答案(5)|浏览(197)

我有以下列- Person_ID Days。对于一个人ID,可能有多天。就像这样:

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

我需要解决以下情况:
如果days列的所有值都是正数,则person_id需要的天数最少。如果天列既有正数又有负数,我需要最小的正数。如果都是负数,我需要最大的负数。
输出如下:

Person_id Days
1000      100
1001       10
1002      -10

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

sauutmhj

sauutmhj1#

试试这个(Postgres 9.4+):

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

vjrehmav2#

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
06odsfpq

06odsfpq3#

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()将在所有days上返回max()(在本例中,所有days都是负数或0)。

lsmd5eda

lsmd5eda4#

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

-- + handle zero_divide ..对不起,以上内容只适用于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;

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;
wz1wpwve

wz1wpwve5#

可以通过在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

相关问题