2017-12-22 11 views
-4

Ich habe eine Neugier. Bitte schlage mir hier die Best Practices vor.Self-Join-Tabellen vs cte Rekursion

Ich habe eine Tabelle Test, der empname und mgr_name Spalten enthält, wie der Name vorschlagen empname enthält empname und mgr_name enthält Manager-Name für den bestimmten Mitarbeiter. Meine Anforderung besteht darin, diejenigen Mitarbeiter zu finden, die mindestens einem Manager und Mitarbeitern, die Manager sind, Bericht erstatten.

Ich schreibe eine Abfrage und die richtigen Datensätze zurückgibt.

create table test(empname varchar(10),mgr_name varchar(10)) 

insert into test 
values('a','b'),('b',null),('c',null),('d','f'),('f',null),('g',null),('h',null) 

query:

select a.empname 
from test a , test b 
where a.mgr_name =b.empname 
union 
select b.empname 
from test a , test b 
where a.mgr_name =b.empname 

Ich habe versucht, diese Abfrage zu optimieren und CTE zu verwenden, anstatt Tabellen in Self-Join der Verwendung mehrerer Zeiten wie

;with cte as (
select * 
from test 

) 
select a.empname 
from cte a , cte b 
where a.mgr_name =b.empname 
union 
select b.empname 
from cte a , cte b 
where a.mgr_name =b.empname 

Aber ich fand, dass es keine Besserung zeigt im Ausführungsplan.

Ich brauche Ihre Hilfe, um zu entscheiden, die Abfrage in diesem Fall zu optimieren, bitte schlagen Sie vor, wenn ein anderer Ansatz in diesem Fall optimiert wäre.

+4

** wollen [Schlechte Gewohnheiten treten: im alten Stil mit JOIN] (http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/08/bad-habits -zu-kick-using-old-style-joins.aspx) ** – Sami

+0

Ohne die Pläne, STATS IO und DDL dieser Ansätze zu teilen, wie können wir helfen? –

+1

* Warum * dachtest du, dass die Einführung eines CTE hier helfen würde? –

Antwort

-1

Es gibt keine Notwendigkeit, den Tisch 4 mal abfragen ... Nur sehen überprüfen, ob mgr_name einen Wert von NULL hat:

SELECT empname 
FROM test 
WHERE mgr_name IS NOT NULL 
UNION 
SELECT mgr_name 
FROM test 
WHERE mgr_name IS NOT NULL; 

werden Sie noch 2 Scans tun müssen, aber das bekommen los von der impliziten JOIN sowie 2 Scans (wie in Ihrer Abfrage die Tabelle wurde zweimal auf jeder Seite der UNION gescannt).

+0

Nicht das gleiche wie dies FK fehlt nicht vorhanden – Paparazzi

+0

@Paparazzi "nicht das Gleiche" als was? Welcher Fremdschlüssel? Das OP spezifiziert keine Schlüssel in der DDL. Die obige Abfrage liefert das gleiche Ergebnis wie die OPs. Bitte erläutern Sie, wenn Sie kommentieren: "funktioniert nicht" ist nie hilfreich. – Larnu

+0

Genau, OP gibt keinen Schlüssel an. Dies wird gelöscht, auch wenn mgr_name nicht gültig ist. – Paparazzi

0

Optimierung auf die angegebenen Kennzahlen (keine) Ergebnisse in der folgenden Liste aller Menschen zu schaffen, und ob sie (1) verwaltet von einer Person oder (b) die Verwaltung von jemand:

declare @Employees as Table (EmployeeName VarChar(10), ManagerName VarChar(10)); 

insert into @Employees (EmployeeName, ManagerName) values 
    ('a', 'b'), ('b', null), ('c', null), ('d', 'f'), ('f', null), ('g', null), ('h', null); 

select distinct(Name), 
    case when exists 
    (select 42 from @Employees where EmployeeName = Name and ManagerName is not NULL) then 1 else 0 end as IsManaged, 
    case when exists 
    (select 42 from @Employees where ManagerName = Name) then 1 else 0 end as IsManager 
    from (
    select EmployeeName as Name 
     from @Employees 
    union all 
    select ManagerName 
     from @Employees 
     where ManagerName is not NULL) as PH; 

-- Alternatively: 
select Name, Max(IsManaged) as IsManaged, Max(IsManager) as IsManager 
    from (
    select EmployeeName as Name, case when ManagerName is NULL then 0 else 1 end as IsManaged, 0 as IsManager 
     from @Employees 
    union all 
    select ManagerName, 0, 1 
     from @Employees 
     where ManagerName is not NULL) as PH 
    group by Name; 

Selbstmanagement wird unterstützt.

0

Eigentlich tut Ihr CTE nichts. Sie kopieren nur eine Tabelle genau, es gibt also keinen Unterschied zur Verwendung von CTE oder Test. Sie wollten wahrscheinlich so etwas wie:

; with cte as (
    select * -- This won't work because duplicate naming, but you can change that 
    from test a, test b -- my soul weeps at this terrible syntax 
) 

In jedem Fall müssen Sie dies nicht tun. Hier ist die Abfrage, die Sie

select empname 
from test 
where mgr_name is not null 
    or empname in (
     select mgr_name 
      from test 
    )