2017-01-16 6 views
1

Ich habe verschiedene Produktseriennummern in einer Tabelle ProdHistory, die, wie der Tabellenname suggeriert, Produktionsverlauf enthält.
Zum Beispiel habe ich Produktserien SER001, die Teile mit einer eigenen Seriennummer verwendet.
Wir produzieren auch diese Teile verwendet also die gleiche Tabelle ProdHistory, um seine Unterteile zu verfolgen.
Das gleiche gilt für die Unterteile und wenn es Unterteile hat.Rekursive Abfrage aus der gleichen Tabelle

Beispieltabelle

IF OBJECT_ID('tempDB.dbo.#SAMPLETable') IS NOT NULL DROP TABLE #SAMPLETable 
CREATE TABLE #SAMPLETable 
(
    ITEMSEQ INT IDENTITY(1,1), 
    SERIAL NVARCHAR(10) COLLATE SQL_Latin1_General_CP850_CI_AS, 
    ITEMID NVARCHAR(10) COLLATE SQL_Latin1_General_CP850_CI_AS, 
    PARTSERIAL NVARCHAR(10) COLLATE SQL_Latin1_General_CP850_CI_AS, 
    PARTID NVARCHAR(10) COLLATE SQL_Latin1_General_CP850_CI_AS, 
    CREATEDDATETIME DATETIME 
) 

INSERT INTO 
     #SAMPLETable (SERIAL,ITEMID,PARTSERIAL,PARTID,CREATEDDATETIME) 
VALUES ('SER0001','ASY-1342','ITM0001','PRT-0808','2017-01-17'), 
     ('SER0001','ASY-1342','ITM0002','PRT-0809','2017-01-17'), 
     ('SER0001','ASY-1342','ITM0003','PRT-0810','2017-01-17'), 
     ('SER0001','ASY-1342','ITM0004','PRT-0811','2017-01-17'), 
     ('ITM0001','PRT-0808','UNT0001','PRT-2020','2017-01-16'), 
     ('ITM0002','PRT-0809','UNT0002','PRT-2021','2017-01-16'), 
     ('ITM0002','PRT-0809','UNT0003','PRT-2022','2017-01-16'), 
     ('ITM0003','PRT-0810','UNT0004','PRT-2023','2017-01-16'), 
     ('UNT0002','PRT-2021','DTA0000','PRT-1919','2017-01-15'), 
     ('UNT0003','PRT-2022','DTA0001','PRT-1818','2017-01-15'), 
     ('DTA0001','PRT-1818','LST0001','PRT-1717','2017-01-14') 

Die Frage ist, wenn ich nur die Haupt-Seriennummer gegeben habe, wie kann ich alle Teile zurückkehren und Subparts Serien damit verbunden?

Probe Ergebnis:

MainSerial SubSerial1 SubSerial2 SubSerial3 SubSerial4 
------------------------------------------------------- 
SER0001 ITM0001 UNT0001 
SER0001 ITM0002 UNT0002 DTA0000 
SER0001 ITM0002 UNT0003 DTA0001 LST0001 
SER0001 ITM0003 UNT0004 
SER0001 ITM0004 

In oben ist es nicht eindeutig, wie viele Teile und Subparts dort für eine Seriennummer.
Ich habe meinen Code nicht gepostet, da ich gerade jetzt einen nach dem anderen abfrage.
Wenn ich die Anzahl der Unterteile kannte, kann ich verschachtelt Joins tun, aber es ist nicht.

Eine andere Frage ist, ob es möglich ist, das gleiche Ergebnis zu erhalten, wenn ich nur einen der obigen Teile erhalten habe?

+0

Könnte ein Teil mehr als 4 Ebenen haben? Wenn ja, würde ich vorschlagen, die Visualisierung auf der Anwendungsebene – JohnHC

+3

zu behandeln. Können Sie bitte die Tabellenstruktur und Beispieldaten posten. Es ermöglicht uns, Ihnen eine sinnvolle Anfrage zu stellen. –

+0

Sie müssen CTE mit Filter in der Ankerabfrage für den Teil/Unterabschnitt verwenden, für den Sie die zugehörigen Unterabschnitte suchen müssen. –

Antwort

1

Ich denke, eine Möglichkeit, dynamische SQL wie folgt verwenden:

-- Variables to generate SQL query string dynamically 
declare @cols nvarchar(max) = '', @joins nvarchar(max) = '', @sql nvarchar(max) = '';  

-- Using CTE to iterate parent-child records 
with cte(i, cols, joins, itemId, serial, partId, partSerial) as (
    select 
     1, -- Level or depth of hierarchically tree 
     N's1.serial MainSerial, s1.partSerial SubSerial'+cast(1 as varchar(max)), 
     N'yourTable s'+cast(1 as varchar(max)), 
     s.itemId, s.serial, s.partId, s.partSerial 
    from yourTable s 
    -- A way to filter root-parents is filtering items those are not in parts 
    where s.itemId not in (select si.partId from yourTable si) 
    union all 
    select 
     i+1, 
     cols + N', s'+cast(i+1 as varchar(max))+N'.partSerial SubSerial'+cast(i+1 as varchar(max)), 
     joins + N' left join yourTable s'+cast(i+1 as varchar(max))+N' on s'+cast(i as varchar(max))+N'.partId = s'+cast(i+1 as varchar(max))+N'.itemId', 
     st.itemId, st.serial, st.partId, st.partSerial 
    from cte 
    join #sampleTable st on cte.partId = st.itemId 
) 
-- Now we need only strings of deepest level 
select top(1) 
    @cols = cols, @joins = joins 
from cte 
order by i desc; 

-- Finalize and executing query string 
set @sql = N'select ' + @cols + N' from ' + @joins + N' where s1.itemId not in (select s.partId from yourTable s)'; 
exec(@sql); 

Zusätzliche Anmerkung: Generierte Abfrage ist:

select s1.serial MainSerial 
    , s1.partSerial SubSerial1 
    , s2.partSerial SubSerial2 
    , s3.partSerial SubSerial3 
    , s4.partSerial SubSerial4 
    --, ... 
from yourTable s1 
    left join yourTable s2 on s1.partId = s2.itemId 
    left join yourTable s3 on s2.partId = s3.itemId 
    left join yourTable s4 on s3.partId = s4.itemId 
--left join ... 
where s1.itemId not in (select s.partId from yourTable s); 
+0

Habe viel daraus gelernt. Sie haben recht, ich habe die dynamische Abfrage von SQL nicht untersucht. Dies funktioniert besonders gut auf dem Probentisch. Ich arbeite daran, dass es für mehrere Hauptseriennummern funktioniert. Prost. Das ist total toller Kumpel. – L42