2016-07-07 68 views
2

我有以下几列 - 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 

我需要解决以下情况:

如果天列所有值都是正的,我需要的天最低的为person_id。如果日子列有正面和负面,我需要最低限度的积极。如果所有的否定,我需要最大的负面。

输出,如:

Person_id Days 
1000  100 
1001  10 
1002  -10 

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

+1

请出示你试过的代码。你使用postgresql还是oracle? – Siyual

+0

0可以是天列中的值吗?在这种情况下,如果有0和正值,应该返回什么?可能是0 ...如果有正值,负值和零值会怎么样?返回0? – mathguy

+0

0是可能的列。结果是可以的。@siyual - 我使用postgres – Deepak

回答

0

甲骨文设置

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 
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; 
0
select Person_id, min(abs(days)) * days/abs(days) from table_name 
group by Person_id 

- +处理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; 

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; 
+0

在Oracle:'ORA-00979:不是GROUP BY表达式'和PostgreSQL中:'ERROR:column“table_name.days”必须出现在GROUP BY子句中或用于聚合函数中Position: 36' – MT0

+0

它在MySQL中使用各种数据完美工作。 对不起,写一些错误。 你当然可以改变这一点。 –

+0

无法在任何SQL中使用。在公式中使用“days/abs(days)”?如果你的意思是乘法全部是WITHIN min(),那么它是有意义的,但那只是min(天),这是错误的答案。可以做出正确的答案 – mathguy

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()将返回空值,并且NVL()将返回max()超过全部days(所有这些在这种情况下都是负值或0)。

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

相关问题