2016-08-02 7 views
1

Ich muss eine Stored Procedure schreiben, um einige Daten zu einer Bestellung von Kindern zu Eltern zurückzugeben. Es ist irgendwie kompliziert zu beschreiben, was ich tun möchte, aber lass es mich versuchen: Stellen wir diese Hierarchie genannt Kategorien haben: Parent> Child1> Child2> Child3, alle gespeicherten mit SQL HierarchyID:SQL HierarchyID verwenden, um von Children zu Eltern auszuwählen

Category Table 
-------------- 
Cat_ID    | Cat_Name 
.............................. 
/1/    | News 
/1/1/    | NewsOfUSA 
/1/1/1/   | NewsOfWestUSA 
/1/1/1/1/   | NewsOfWashington 

Und wir haben Wie unten Nachrichten mit diesen Kategorien gespeichert:

News Table 
------------- 
News_ID  | FK_Cat_ID | News_Content 
......................................... 
0001  | /1/   | one 
0002  | /1/1/  | two 
0003  | /1/1/1/  | three 
0004  | /1/1/1/1/ | four1 
0005  | /1/1/1/1/ | four2 
0006  | /1/1/1/1/ | four3 
0007  | /1/1/1/1/ | four4 

und schließlich Ich möchte zum Beispiel To auswählen p Zehn Nachrichten mit dieser Bedingung:

Wenn NewsOfWashington 10 Nachrichten hat sie dann wählen, sonst wählen Sie aus NewsOfWestUSA, sonst wählen Sie aus NewsOfUSA, sonst wählen Sie aus Nachrichten, Bis Sie erreichen zehn

Und die Reihenfolge ausgewählt werden, ist dies

four4,four3,four2,four1,three,two,one 

Ich habe versucht, rekursive CTE zu verwenden, konnte aber keine geeignete Methode zur Implementierung finden.

+0

Verwenden Sie mehrere Abfragen mit einer 'UNION'? – Malk

+0

@Malk, Nein Nein, nur diese zwei Tabellen Ich möchte zuerst überprüfen, ob Nachrichten mit NewsOfWashington 10 oder nicht erreichen, wenn nicht von seinem Eltern NewsOfWestUSA usw. auswählen ... – Yasin

Antwort

0

die Daten vollständig Skript von Mitch stehlen‘ s Antwort, dann ist dies nicht so schlecht:

CREATE TABLE Categories 
    (
     CatID hierarchyid not null 
         primary key , 
     Name nvarchar(255) not null 
    ); 
CREATE TABLE News 
    (
     NewsID int not null 
       primary key , 
     CatID hierarchyid not null , 
     NewsContent nvarchar(max) not null 
    ); 

INSERT INTO Categories 
VALUES ('/1/', 'News'), 
    ('/1/1/', 'NewsOfUSA'), 
    ('/1/1/1/', 'NewsOfIndiana'), 
    ('/1/2/', 'NewsOfUK'); 

INSERT INTO News 
VALUES (1, '/1/', 'Aliens invaded'), 
    (2, '/1/1/', 'Aliens invaded the US'), 
    (3, '/1/1/1/', 'Aliens invaded the midwest'), 
    (4, '/1/2/', 'Aliens invaded the UK'); 

-- actual answer begins here 
select TOP(10) News.[NewsContent] 
from dbo.Categories as parent 
join dbo.Categories as child 
    on child.CatID.IsDescendantOf(parent.CatID) = 1 
join News 
    on News.CatID = parent.CatID 
WHERE child.Name = 'NewsOfIndiana' 
order by News.CatID.GetLevel() DESC 

Im Wesentlichen Ich verwende die IsDescendentOf() Methode zu erhalten, welche Kategorien der jeweiligen Kategorie gehört und dann auf die Nachrichten Beitritt auf der Grundlage dieser neuen Liste der Kategorien und schließlich Sortierung auf die GetLevel() Methode (die zurückgibt, wie tief in der Hierarchie ein gegebener Wert ist).

+0

Gut gemacht! Wie Sie sagten, sollten wir Mitchs Antwort auch als Antwort markieren, weil er sie auch beantwortet hat, aber Ihre ist irgendwie einfacher und einfacher zu implementieren. Dank bro. – Yasin

+0

Sie * können * den kleinen Pfeil nach oben neben seiner Antwort drücken, um ihm einen schnellen Ruf zu verschaffen. :) Ich tat (danke für die Erinnerung!). –

+1

Ich tat es, aber mein Ruf ist nicht hoch genug, um sofort zu reflektieren – Yasin

0

Versuchen verfolgt wird, wird TOP 10 in der Reihenfolge zurückkehren Sie wollen:

SELECT TOP 10 CASE n.FK_Cat_ID 
WHEN '/1/1/1/1/' THEN 0 
WHEN '/1/1/1/' THEN 1 
WHEN '/1/1/' THEN 2 
WHEN '/1/' THEN 3 
Else 4 END,* 
FROM News as n 
INNER JOIN Category as c 
ON n.FK_Cat_ID = c.Cat_ID 
ORDER BY 1; 
+0

Ich schätze Ihre Hilfe, aber das Problem ist, dass diese Kategorien, 'NewsOfWashington' usw. sind dynamisch und ich habe nur die cat_id/1/1/1/1/ wie kann es auf diese Weise getan werden? – Yasin

+0

Es ist einfach zu reparieren –

1

den Abstand zu identifizieren, sucht alle Nachkommen und dann sortieren durch die Differenz in der Tiefe:

USE tempdb; 

CREATE TABLE Categories (CatID hierarchyid not null primary key, Name nvarchar(255) not null); 
CREATE TABLE News (NewsID int not null primary key, CatID hierarchyid not null, NewsContent nvarchar(max) not null); 

INSERT INTO Categories 
VALUES ('/1/', 'News'), 
    ('/1/1/', 'NewsOfUSA'), 
    ('/1/1/1/', 'NewsOfIndiana'), 
    ('/1/2/', 'NewsOfUK'); 

INSERT INTO News 
VALUES (1, '/1/', 'Aliens invaded'), 
    (2, '/1/1/', 'Aliens invaded the US'), 
    (3, '/1/1/1/', 'Aliens invaded the midwest'), 
    (4, '/1/2/', 'Aliens invaded the UK'); 

DECLARE @VisitorLocation hierarchyid = '/1/1/1/'; 

WITH 
relevantCategories AS (
    SELECT c.*, ABS(@VisitorLocation.GetLevel() - c.CatID.GetLevel()) as RelevanceDistance 
    FROM Categories c 
    WHERE @VisitorLocation.IsDescendantOf(c.CatID) = 1 
) 
SELECT TOP(10) n.*, c.RelevanceDistance 
FROM relevantCategories c 
INNER JOIN News n on n.CatID = c.CatID 
ORDER BY RelevanceDistance ASC, n.NewsID DESC; 

DROP TABLE Categories; 
DROP TABLE News; 

produziert:

NewsID CatID   NewsContent   RelevanceDistance 
-------- -------- ---------------------------- ------------------- 
     3 0x5AD6 Aliens invaded the midwest     0 
     2 0x5AC0 Aliens invaded the US      1 
     1 0x58  Aliens invaded        2 
+0

Ich möchte auch Ihre als Antwort zu markieren, denn das ist auch sehr gut, aber leider ist es nicht möglich, mehr als eine zu markieren! Vielen Dank für Ihre Antwort – Yasin

Verwandte Themen