2016-07-07 6 views
2

Ich habe die folgenden Spalten - Person_ID Days. Für eine Person ID sind mehrere Tage möglich. Etwas wie folgt aus:Wie kann man ein positives minimales oder negatives Maximum in einer Spalte für einen Schlüssel identifizieren?

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

ich die folgenden Szenarien ansprechen müssen:

Wenn alle Werte für Tage Spalte positiv sind, muss ich mindestens die Tage für einen person_id. Wenn die Spalte "Tage" sowohl positiv als auch negativ ist, benötige ich ein Minimum an positiven Ergebnissen. Wenn alle negativ sind, brauche ich maximal negativ.

Die Ausgabe wie:

Person_id Days 
1000  100 
1001  10 
1002  -10 

Ich versuchte Case-Anweisung, aber ich bin nicht in der Lage eine gleiche Spalte in dem Zustand, wie Gruppierung als auch zu verwenden.

+1

Bitte zeigen Sie den Code, den Sie versucht haben. Verwenden Sie postgresql oder oracle? – Siyual

+0

Kann 0 ein Wert in der Spalte "Tage" sein? In diesem Fall, wenn es eine 0 und auch positive Werte gibt, was sollte zurückgegeben werden? Wahrscheinlich 0 ... Was ist, wenn es positive, negative und Nullwerte gibt? Rückgabe 0? – mathguy

+0

0 ist in der Spalte möglich. Es ist okay, es als Ergebnis zu [email protected] - ich benutze Postgres – Deepak

Antwort

0

Oracle-Setup:

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; 

Abfrage:

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; 

Ausgang:

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

starten (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 

- + Griff zero_divide .. sorry .. Die oben genannten Arbeiten nur in MySQL.

So etwas wie dies überall funktionieren, die äquivalent der obigen Abfrage ist:

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; 

ODER

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

In Oracle: 'ORA-00979: kein GROUP BY Ausdruck' und in PostgreSQL:' ERROR: Spalte "Tabellenname.days" muss in der GROUP BY-Klausel erscheinen oder in einer Aggregatfunktion verwendet werden Position: 36' – MT0

+0

Es funktioniert perfekt in MySQL mit verschiedenen Daten. Entschuldigung für das Schreiben eines Fehlers. Das können Sie natürlich ändern. –

+0

Kann nicht in ANY SQL arbeiten. Welche "Tage/abs (Tage) wird in der Formel verwendet? Wenn du meinst, dass die Multiplikation alles WITHIN min() ist, dann wäre es sinnvoll, aber das wäre nur min (Tage), was die falsche Antwort ist. Sehr unwahrscheinlich, dass dies kann in eine richtige Antwort gemacht werden – mathguy

0

Oracle Lösung:

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 

Für jede person_id, wenn es an ist mindestens ein days Wert, der streng positiv ist, dann die min wird nur positiv days übernommen und wird von NVL() zurückgegeben. Andernfalls gibt min() Null zurück, und NVL() gibt max() über alle days zurück (alle sind in diesem Fall negativ oder 0).

0

Sie können dies tun, indem Sie GroupBy-Klausel in SQL Server verwenden. Werfen Sie einen Blick in folgenden Abfrage: -

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

Verwandte Themen