2012-10-18 15 views
6

Haben Sie eine schwere Abfrage (dauert 15 Minuten zum Ausführen), aber es gibt mehr Ergebnisse als ich brauche. Es ist eine CONNECT BY-Abfrage, und ich bekomme Knoten, die in den Ergebnissen des Stammknotens untergeordnet sind. D.h .:Ausschließen von Ergebnissen, die in einer anderen Spalte einer CONNECT BY-Abfrage angezeigt werden

Ted 
    Bob 
    John 
Bob 
    John 
John 

Normalerweise wird die Art und Weise, dies zu lösen ist mit einem START MIT Bedingung, in der Regel die Eltern eines Knotens erfordert null zu sein. Aber aufgrund der Art der Abfrage habe ich nicht die START WITH-Werte, mit denen ich vergleichen muss, bis ich die vollständige Ergebnismenge habe. Ich versuche im Grunde, meine Ergebnisse doppelt abzufragen, um QUERY STUFF START WITH RECORDS zu sagen, die NICHT IN DIESEM MATERIAL SIND.


Hier ist die Abfrage (mit Hilfe von Nicholas Krasnov gebaut, hier: Oracle Self-Join on multiple possible column matches - CONNECT BY?):

select cudroot.root_user, cudroot.node_level, cudroot.user_id, cudroot.new_user_id, 
     cudbase.* -- Not really, just simplyfing 
from css.user_desc cudbase 
    join (select connect_by_root(user_id) root_user, 
       user_id     user_id,   
       new_user_id    new_user_id, 
       level     node_level 
     from (select cudordered.user_id,  
         coalesce(cudordered.new_user_id, cudordered.nextUser) new_user_id 
       from (select cud.user_id, 
           cud.new_user_id, 
           decode(cud.global_hr_id, null, null, lead(cud.user_id ignore nulls) over (partition by cud.global_hr_id order by cud.user_id)) nextUser 
         from css.user_desc cud 
          left join gsu.stg_userdata gstgu 
          on (gstgu.user_id = cud.user_id 
           or (gstgu.sap_asoc_global_id = cud.global_hr_id)) 
         where upper(cud.user_type_code) in ('EMPLOYEE','CONTRACTOR','DIV_EMPLOYEE','DIV_CONTRACTOR','DIV_MYTEAPPROVED')) cudordered) 
     connect by nocycle user_id = prior new_user_id) cudroot 
    on cudbase.user_id = cudroot.user_id 
order by 
     cudroot.root_user, cudroot.node_level, cudroot.user_id; 


Das bin ich zu verwandten Benutzer gibt Ergebnisse (basierend weg von User_id umbenennt oder SAP-IDs zugeordnet) das sieht so aus:

ROOT_ID  LEVEL USER_ID   NEW_USER_ID 
------------------------------------------------ 
A5093522 1  A5093522  FG096489 
A5093522 2  FG096489  A5093665 
A5093522 3  A5093665   
FG096489 1  FG096489  A5093665 
FG096489 2  A5093665 
A5093665 1  A5093665 

Was ich brauche ist ein Weg zu Filtern Sie die erste join (select connect_by_root(user_id)..., um FG096489 und A5093665 von der Root-Liste auszuschließen.


Die beste START WITH ich denken kann wie folgt aussehen würde (noch nicht getestet):

start with user_id not in (select new_user_id 
          from (select coalesce(cudordered.new_user_id, cudordered.nextUser) new_user_id 
            from (select cud.new_user_id, 
                decode(cud.global_hr_id, null, null, lead(cud.user_id ignore nulls) over (partition by cud.global_hr_id order by cud.user_id)) nextUser 
              from css.user_desc cud 
              where upper(cud.user_type_code) in ('EMPLOYEE','CONTRACTOR','DIV_EMPLOYEE','DIV_CONTRACTOR','DIV_MYTEAPPROVED')) cudordered) 
          connect by nocycle user_id = prior new_user_id) 

... aber ich meine 15 Minuten Abfrage zweimal effektiv ausgeführt wird.

Ich habe mit Partitionen in der Abfrage untersucht, aber es gibt nicht wirklich eine Partition ... Ich möchte auf die volle Ergebnismenge von new_user_ids schauen. Habe auch analytische Funktionen wie rank() erforscht ... meine Trickkiste ist leer.

Irgendwelche Ideen?


Klärung

Der Grund, warum ich nicht die zusätzlichen Datensätze in der Wurzelliste will, weil ich für jeden Benutzer nur eine Gruppe von Ergebnissen will. Wenn Bob Smith während seiner Karriere vier Konten hatte (Leute kommen und gehen häufig, als Angestellte und/oder Auftragnehmer), möchte ich mit einer Reihe von Konten arbeiten, die Bob Smith gehören.

Wenn Bob als Auftragnehmer kam, in einen Mitarbeiter umgewandelt, ging, kam als Auftragnehmer in einem anderen Land zurück und ging zu einer rechtlichen Organisation zurück, die jetzt in unserem SAP-System seinen Account umbenennen/ketten könnte wie folgt aussehen:

Bob Smith CONTRACTOR ---- US0T0001 -> US001101 (given a new ID as an employee) 
Bob Smith EMPLOYEE  ---- US001101 -> EB0T0001 (contractor ID for the UK) 
Bob Smith CONTRACTOR SAP001 EB0T000T    (no rename performed) 
Bob Smith EMPLOYEE SAP001 TE110001    (currently-active ID) 

im obigen Beispiel werden die vier Konten entweder durch ein new_user_id Feld verknüpft, die festgelegt wurde, wenn der Benutzer umbenannt wurde oder durch die gleiche SAP-ID mit.

Da HR den Geschäftsprozess häufig nicht befolgt, kann die Rückgabe von Benutzern zu einer Wiederherstellung dieser vier IDs führen. Ich muss alle IDs für Bob Smith analysieren und sagen "Bob Smith kann TE110001 nur wiederherstellen", und einen Fehler zurückwerfen, wenn sie versuchen, etwas anderes wiederherzustellen. Ich muss es für mehr als 90.000 Datensätze tun.

Die erste Spalte "Bob Smith" ist nur eine Kennung für die Gruppe der zugeordneten Konten. In meinem ursprünglichen Beispiel verwende ich die root-Benutzer-ID als Kennung (z. B. US0T0001). Wenn ich mit Vor-/Nachnamen Benutzer identifiziere, stoße ich auf Kollisionen.

So Bob Smith würde wie folgt aussehen:

US0T0001 1 CONTRACTOR ---- US0T0001 -> US001101 (given a new ID as an employee) 
US0T0001 2 EMPLOYEE  ---- US001101 -> EB0T0001 (contractor ID for the UK) 
US0T0001 3 CONTRACTOR SAP001 EB0T0001    (no rename performed) 
US0T0001 4 EMPLOYEE SAP001 TE110001    (currently-active ID) 

... wo 1, 2, 3, 4 die Pegel in der Hierarchie sind.

Da US0T0001, US001101, EB0T0001 und TE110001 alle berücksichtigt werden, möchte ich keine andere Gruppe für sie. Aber die Ergebnisse habe ich habe jetzt diese Konten in mehreren Gruppen aufgeführt:

US001101 1 EMPLOYEE  ---- US001101 -> EB0T0001 (
US001101 2 CONTRACTOR SAP001 EB0T0001     
US001101 3 EMPLOYEE SAP001 TE110001    

EB0T0001 1 CONTRACTOR SAP001 EB0T0001    
EB0T0001 2 EMPLOYEE SAP001 TE110001     

US001101 1 EMPLOYEE SAP001 TE110001     

Dies verursacht zwei Probleme:

  1. Wenn ich die Ergebnisse für eine Benutzer-ID abfragen, erhalte ich Treffer von mehreren Gruppen
  2. Jede Gruppe meldet eine andere erwartete Benutzer-ID für Bob Smith.


Sie bat um einen erweiterten Satz von Aufzeichnungen ... hier sind einige aktuelle Daten:

-- NumRootUsers tells me how many accounts are associated with a user. 
-- The new user ID field is explicitly set in the database, but may be null. 
-- The calculated new user ID analyzes records to determine what the next related record is 

      NumRoot     New User Calculated 
RootUser Users Level UserId ID Field New User ID SapId  LastName  FirstName 
----------------------------------------------------------------------------------------------- 
BG100502 3  1  BG100502 BG1T0873 BG1T0873     GRIENS VAN  KION 
BG100502 3  2  BG1T0873 BG103443 BG103443     GRIENS VAN  KION 
BG100502 3  3  BG103443       41008318 VAN GRIENS  KION 

-- This group causes bad matches for Kion van Griens... the IDs are already accounted for, 
-- and this group doesn't even grab all of the accounts for Kion. It's also using a new 
-- ID to identify the group 
BG1T0873 2  1  BG1T0873 BG103443 BG103443     GRIENS VAN  KION 
BG1T0873 2  2  BG103443       41008318 VAN GRIENS  KION 

-- Same here... 
BG103443 1  1  BG103443       41008318 VAN GRIENS  KION 

-- Good group of records 
BG100506 3  1  BG100506    BG100778  41008640 MALEN VAN  LARS 
BG100506 3  2  BG100778    BG1T0877  41008640 MALEN VAN  LARS 
BG100506 3  3  BG1T0877       41008640 VAN MALEN  LARS 

-- Bad, unwanted group of records 
BG100778 2  1  BG100778    BG1T0877  41008640 MALEN VAN  LARS 
BG100778 2  2  BG1T0877       41008640 VAN MALEN  LARS 

-- Third group for Lars 
BG1T0877 1  1  BG1T0877       41008640 VAN MALEN  LARS 


-- Jan... fields are set differently than the above examples, but the chain is calculated correctly 
BG100525 3  1  BG100525    BG1T0894  41008651 ZANWIJK VAN  JAN 
BG100525 3  2  BG1T0894 TE035165 TE035165  41008651 VAN ZANWIJK  JAN 
BG100525 3  3  TE035165       41008651 VAN ZANWIJK  JAN 

-- Bad 
BG1T0894 2  1  BG1T0894 TE035165 TE035165  41008651 VAN ZANWIJK  JAN 
BG1T0894 2  2  TE035165       41008651 VAN ZANWIJK  JAN 

-- Bad bad 
TE035165 1  1  TE035165       41008651 VAN ZANWIJK  JAN 


-- Somebody goofed and gave Ziano a second SAP ID... but we still matched correctly 
BG100527 3  1  BG100527    BG1T0896  41008652 STEFANI DE  ZIANO 
BG100527 3  2  BG1T0896 TE033030 TE033030  41008652 STEFANI DE  ZIANO 
BG100527 3  3  TE033030       42006172 DE STEFANI  ZIANO 

-- And we still got extra, unwanted groups 
BG1T0896 3  2  BG1T0896 TE033030 TE033030  41008652 STEFANI DE  ZIANO 
BG1T0896 3  3  TE033030       42006172 DE STEFANI  ZIANO 

TE033030 3  3  TE033030       42006172 DE STEFANI  ZIANO 


-- Mark's a perfect example of the missing/frustrating data I'm dealing with... but we still matched correctly 
BG102188 3  1  BG102188    BG1T0543  41008250 BULINS   MARK 
BG102188 3  2  BG1T0543    TE908583  41008250 BULINS   R.J.M.A. 
BG102188 3  3  TE908583       41008250 BULINS   RICHARD JOHANNES MARTINUS ALPHISIUS 

-- Not wanted 
BG1T0543 3  2  BG1T0543    TE908583  41008250 BULINS   R.J.M.A. 
BG1T0543 3  3  TE908583       41008250 BULINS   RICHARD JOHANNES MARTINUS ALPHISIUS 

TE908583 3  3  TE908583       41008250 BULINS   RICHARD JOHANNES MARTINUS ALPHISIUS 


-- One more for good measure 
BG1T0146 3  1  BG1T0146 BG105905 BG105905     LUIJENT   VALERIE 
BG1T0146 3  2  BG105905    TE034165  42006121 LUIJENT   VALERIE 
BG1T0146 3  3  TE034165       42006121 LUIJENT   VALERIE 

BG105905 3  2  BG105905    TE034165  42006121 LUIJENT   VALERIE 
BG105905 3  3  TE034165       42006121 LUIJENT   VALERIE 

TE034165 3  3  TE034165       42006121 LUIJENT   VALERIE 

Nicht sicher, ob alles, was info macht deutlicher, oder wird Ihre Augen machen rollen wieder in Ihre Kopf:)

Danke für das Betrachten!

+0

ist mir nicht sehr klar, warum FG096489 und A5093665 aus der Root-Liste ausgeschlossen werden sollten - ist es, weil sie root_users mit new_user_id ist null, oder was könnten Sie ein vollständigeres Beispiel für die Ausgabe von der Abfrage geben, so dass wir sehen können ein paar mehr Kombinationen - mit nur 2 Benutzer-IDs erscheinen alle in allen Spalten, es ist schwer, das Muster zu sehen. –

+0

Der einzige Grund, sie von der Liste auszuschließen, ist, dass ich sie ausgeschlossen habe:) Ich bin offen für andere Designs, aber was ich mit den Ergebnissen versuche, erfordert, dass es nur eine Gruppe pro assoziierten Benutzergruppe gibt. Will versuchen, mehr in der Frage zu erklären, danke! –

+0

Können Sie die Abfrage nach Datum steuern? Mit anderen Worten: 'STARTING WITH FirstEmployment' –

Antwort

1

Ich denke, ich habe es. Wir haben uns erlaubt, uns auf die chronologische Reihenfolge zu fixieren, obwohl es eigentlich keine Rolle spielt. Ihre START WITH-Klausel sollte "NEW_USER_ID IS NULL" lauten.

Um chronologische Reihenfolge zu erhalten, könnten Sie 'ORDER BY cliorot.node_level * -1'.

Ich würde auch empfehlen, dass Sie eine WITH-Klausel verwenden, um Ihre Stammdaten zu bilden und die hierarchische Abfrage dazu durchzuführen.

+0

Versucht, dass ... 'new_user_id' ist NULL wird nicht immer einen Wurzelknoten anzeigen: (In Die Beispiele, die ich hinzugefügt habe, Lars van Malen hat eine Null 'new_user_id' für alle drei Benutzer-IDs ... sie sind stattdessen durch SAP ID verbunden Ich kann nicht sagen, wo SAP ID null ist oder beide null oder eins sind ist null und der andere gefüllt, weil es in jedem Fall Ausnahmen gibt.Ich muss einen Weg finden zu sagen "kein anderer Knoten ist ein Elternteil dieses Knotens." –

+0

Ich konnte nicht ORDER BY SIBLINGS für einige arbeiten Grund ... Mir wurde immer gesagt, dass ich es nicht benutzen kann, obwohl die Abfrage ein CONNECT BY ist, aber ich schaue dort nach Möglichkeiten JOC, wenn du "ORDER BY cliroot.node_level * -1" schreibst. .. Ich habe noch nie eine Bestellung in diesem Format oder mit einem Sternchen gesehen. Was macht das mit der Sortierreihenfolge? –

+0

'Knotenniveau mal minus eins'. Können Sie eine Ansicht der Daten erzeugen, die die Datensätze in einer Form liefern, mit der wir arbeiten können - mit anderen Worten, mit einem Feld namens Parent_ID? Wenn ja, können Sie Ihre hierarchische Abfrage dazu durchführen. –

1

Vielleicht brauchen Sie hier mehrere Abfragen. Jede Abfrage findet eine Teilmenge der Datensätze, die Sie suchen. Jede Abfrage wird hoffentlich einfacher und schneller als eine einzelne, ginormous Abfrage sein. Etwas wie:

  1. wo NEW_USER_ID ist null und SAP ID ist null
  2. wo NEW_USER_ID ist nicht null und SAP ID ist null
  3. wo NEW_USER_ID ist null und SAP-ID ist nicht null
  4. wo NEW_USER_ID ist ID nicht null und SAP ist nicht null

(diese sind der Manschette Beispiele)

ich denke, ein Teil des p Problem bei der Lösung dieses Rätsels ist, dass der Problemraum zu groß ist. Indem dieses Problem in kleinere Teile unterteilt wird, wird jedes Teil funktionsfähig sein.

Verwandte Themen