2016-11-11 3 views
1

Betrachten Sie diese Daten:Berechnete Spalte für mehrere Zeilen basierend auf einreihige

user code score 
1  1  50 
1  2  100 
2  1  100  
3  2  100 
4  2  50 

Grundsätzlich ich alle Noten für jeden Benutzer erhalten möchten, aber ich möchte eine berechnete Spalte basierend auf nur Zeilen mit einem bestimmten Code.

So: CASE WHEN code = 2 AND score > 50 THEN 'Yes' ELSE 'No'.

Aber ich möchte, dass die berechnete Spalte den Code 1 ignoriert.

sollte also sein, die Ergebnisse der oben genannten Daten:

user code score pass 
1  1  50  Yes 
1  2  100  Yes 
2  1  100  No 
3  2  100  Yes 
4  2  50  No 

Ich bin sicher, dass es einige Oracle-SQL-Funktion ist, die Daten zu partitionieren, aber ich weiß nicht, wie.

  • Zeile 1: Ja, weil der gleiche Benutzer hat 100 in Reihe 2.
  • Row 2: Ja, weil Code 2> 50
  • Row 3: Nein, weil es ein Code 1 und sie ist don‘ t haben keine Code-2-Punkte.
  • Row 4: Ja, weil es ein Code 2> 50
  • Reihe 5:

    : Nein, weil es einen Code 2 niedriger als 51.

Basierend auf @ Antwort des mathguy ist, ich das gemacht

CASE 
    WHEN COUNT(CASE 
     WHEN (sortest_tesc_code = 'A02' AND sortest_test_score >= 23) OR 
      (sortest_tesc_code = 'S02' AND sortest_test_score >= 540) OR 
      (sortest_tesc_code = 'MPT' AND sortest_test_score >= 60) OR 
      (sortest_tesc_code = '66' AND sortest_test_score >= 3) THEN 1 END) OVER (PARTITION BY sortest_pidm) = 0 THEN 'No' 
    ELSE 'Yes' 
END pass, 

Überprüfen Sie die Daten jetzt, aber ich denke, das funktioniert.

+0

Ich bin verwirrt. Was sollte "Pass" sein, wenn der Code 1 ist? Null? – xQbert

+0

Also möchten Sie, dass das Ergebnis so viele Zeilen wie die Eingabe hat - und nicht nur eine Zeile pro Benutzer? Es scheint, dass die berechnete Spalte für einen bestimmten Benutzer in allen Zeilen den gleichen "Durchlauf" hat. Daher ist nicht klar, warum Sie mehr als eine Zeile pro Benutzer in der Ausgabe benötigen. – mathguy

+0

'CASE WHEN code = 1 oder (code = 2 UND score> 50) DANN 'Yes' ELSE 'No' END' –

Antwort

3

Dies ist ein Job für analytische Funktionen ist. Natürlich ist user ein reserviertes Wort, daher sollte es kein Spaltenname sein. Andere als das:

with 
    test_data (usr, code, score) as (
     select 1, 1, 50 from dual union all 
     select 1, 2, 100 from dual union all 
     select 2, 1, 100 from dual union all 
     select 3, 2, 100 from dual union all 
     select 4, 2, 50 from dual 
    ) 
-- end of test data. Solution (SQL query) begins below this line 
select usr, code, score, 
     case when count(case when code != 1 and score > 50 then 1 end) 
       over (partition by usr) = 0 then 'No' else 'Yes' end as passed 
from test_data 
; 

     USR  CODE  SCORE PASSED 
---------- ---------- ---------- ------ 
     1   1   50 Yes 
     1   2  100 Yes 
     2   1  100 No 
     3   2  100 Yes 
     4   2   50 No 
+0

Richtig Ich habe nur einfache Namen für das Beispiel verwendet, weil meine realen Tabellen/name sind viel länger. Es sind die analytischen Funktionen, mit denen ich am wenigsten vertraut bin. Ich versuche, sie zu lesen, aber ich benutze sie so selten, dass ich bei SO auf Hilfe stoße. Es ist als ob ich weiß, dass es "gemacht" werden kann, aber ich weiß nicht genau wie. Wie gesagt, ich mache viel mehr Front/Back-End als auf der DB-Ebene. – Leeish

+0

@Leeish - Analytische Funktionen sind nicht so kompliziert - und count(), insbesondere die analytische Version, ist noch einfacher zu verstehen. "partition by usr" bewirkt, dass die Tabelle so behandelt wird, als ob es viele kleine, unabhängige Tabellen wären, eine für jeden usr. Dann wird die analytische Funktion einen Wert (in diesem Fall die Anzahl) an jede Zeile in der Eingabe anhängen, anstatt einen Wert pro Gruppe oder "Partition". Das ist alles, was zu diesem speziellen Problem gehört! Analytische Funktionen allgemein (gerade count(), wenn ich ihm zusätzlich zu PARTITION BY eine ORDER BY-Klausel gegeben hätte), aber hier nicht der Fall. – mathguy

+0

Gerade jetzt versuche ich, Ihre Antwort in meine tatsächlichen Tabellen zu übersetzen, die tatsächlich ein paar verschiedene 'Code'-Werte haben, die ich verwenden und nicht verwenden muss. Ich denke, ich habe es jetzt getestet, aber wenn nicht, brauche ich vielleicht Hilfe. Danke für deine Antwort. – Leeish

0
with userscore (select user, sum(case WHEN code = 2 AND score > 50 then 1 else 0) s end 
       from my_table group by user) 
select m.*, CASE WHEN (code = 2 AND score > 50) or (code = 1 and s > 0) THEN 'Yes' ELSE 'No' end 
    from my_table m, userscore; 
+0

Ergebnisse in 20 Zeilen, sobald ich die Syntax richtig habe. Fall w/o Ende auf 1. Zeile und Gebrauch des reservierten Wortes des Benutzers ging nicht gut w/compiler. versuche 'userscore as (wähle user, sum (case WENN code = 2 AND score> 50 dann 1 else 0 end) s' – xQbert

1

noch viele Annahmen machen ... aber dies führt zu dem Ausgang gegeben ..

with cte as (
Select 1 usr,  1 code,  50 score from dual union all 
Select 1,  2,  100 from dual union all 
Select 2,  1,  100 from dual union all  
Select 3 ,  2,  100 from dual union all 
Select 4 ,  2,  50 from dual) 
Select A.*, case when B.usr is null then 'No' else 'Yes' end as pass 
from cte A 
LEFT JOIN (Select * from cte where code = 2 and score > 50) B 
on A.Usr = B.usr 
order by A.usr, A.code 

enter image description here

+0

Ich mag diese Lösung, muss aber zweimal an der Tabelle teilnehmen Es tut mir leid mit SQL-Funktionen (hauptsächlich Ein Front-/Back-End-Dev nicht SQL-Dev. Sie sehen keine eingebauten Funktionen, die helfen könnten Partition/Gruppierung der Noten von Benutzer oder etwas. Ich denke, das wird funktionieren, es tatsächlich zu betrachten. – Leeish

+0

Sie können eine Gruppierung tun , aber Ihr Endergebnis zeigt alle Zeilen an, so dass immer noch ein 'JOIN' benötigt wird –

+0

@JuanCarlosOropeza - no; Wenn Sie eine Gruppierung durchführen müssen, aber das Endergebnis alle Zeilen anzeigt, verwenden Sie analytische Funktionen (viel effizienter als Joins) – mathguy

Verwandte Themen