2012-01-16 5 views
1

У меня есть таблица «Категории». Каждая строка имеет «CategoryId» (обязательно) и «ParentCategoryId» (не требуется). Это позволяет устанавливать отношения между родителями и родителями -> детьми.Условный запрос выбора SQL

Что я пытаюсь сделать, это выбрать все категории, но если существует родительское -> дочернее отношение, выберите только родителя.

Вот что я сейчас пытаюсь, но он берет навсегда, и он просто плоский. Отказ от ответственности, SQL не мой сильный костюм!

declare @ProjectId int 
set @ProjectId = 1 

declare @catid int 
declare @catname nvarchar(100) 
declare @catprojid int 
declare @catparentid int 
declare @sortorder int 

declare db_cursor cursor for 
select categoryid,categoryname,projectid,parentcategoryid,sortorder from dbo.ProjectCategories 
where ProjectId = @ProjectId 

open db_cursor 
fetch NEXT from db_cursor into @catid,@catname,@catprojid,@catparentid,@sortorder 

while @@FETCH_STATUS = 0 
begin 
    if @catparentid != null select * from dbo.ProjectCategories where CategoryId = @catparentid 
    else select @catid,@catname,@catprojid,@catparentid,@sortorder 
end 

close db_cursor 
deallocate db_cursor 
go 
+2

Я чувствую запах рекурсивного КТР. Я сделаю это, когда вернусь домой, если кто-то еще этого не сделает. – SQLMason

+1

yikes курсор бежит! – JonH

+0

Если у вас есть несколько уровней в иерархии parent => child, вы хотите получить только самый низкий уровень родительского для каждого ребенка? – JNK

ответ

2

следующие выберите извлекает все категории, которые являются родители, по крайней мере, одной другой категории:

declare @ProjectId int 
set @ProjectId = 1 

select distinct 
    parent.categoryid, 
    parent.categoryname, 
    parent.projectid, 
    parent.parentcategoryid, 
    parent.sortorder 
from dbo.ProjectCategories parent 
join dbo.ProjectCategories child on child.ParentCategoryId = parent.CategoryId 
where parent.ProjectId = @ProjectId 
+0

Что делать, если существует несколько отношений родителя/ребенка? – SQLMason

+0

@DanAndrews Спасибо, что заметили это. Я просто добавил ключевое слово 'distinct', чтобы избежать дублирования записей в этом случае. – GolfWolf

0

Должно быть довольно просто:

select categoryid,categoryname,projectid,parentcategoryid,sortorder 
    from dbo.ProjectCategories 
where parentcategoryid is null 
+0

На следующий обзор, я думаю, что это ответ. Дети без родителей будут иметь родительскую категориюID = null. У родителей верхнего уровня будет parentCategoryID = null. Все остальные не будут. – Anderson

+0

Да, после того, как я перечитаю ваш вопрос, это действительно так просто, но вы хотите убедиться, что есть ребенок ... так что будет внутреннее соединение. Я добавлю свой ответ, но, возможно, это уже было сделано в другом ответе. – SQLMason

0
SELECT 
    COALESCE(parent.categoryid, child.categoryid), 
    COALESCE(parent.categoryname, child.categoryname), 
    COALESCE(parent.projectid, child.projectid), 
    COALESCE(parent.parentcategoryid, child.parentcategoryid), 
    COALESCE(parent.sortorder, child.sortorder) 
FROM 
    dbo.ProjectCategories child 
    LEFT JOIN dbo.ProjectCategories parent 
     ON child.parentcategoryid = parent.categoryid 
WHERE 
    child.ProjectId = @ProjectId 

COALESCE возвращает первый параметр не-NULL.

Несколько безопаснее вариант, в случае, если некоторые из столбцов родительской категории являются NULL

SELECT 
    CASE WHEN parent.categoryid IS NULL THEN child.categoryid ELSE parent.categoryid END, 
    CASE WHEN parent.categoryid IS NULL THEN child.categoryname ELSE parent.categoryname END, 
    CASE WHEN parent.categoryid IS NULL THEN child.projectid ELSE parent.projectid END, 
    CASE WHEN parent.categoryid IS NULL THEN child.parentcategoryid ELSE parent.parentcategoryid END, 
    CASE WHEN parent.categoryid IS NULL THEN child.sortorder ELSE parent.sortorder END 
FROM 
    dbo.ProjectCategories child 
    LEFT JOIN dbo.ProjectCategories parent 
     ON child.parentcategoryid = parent.categoryid 
WHERE 
    child.ProjectId = @ProjectId 
0

Это будет список всех родителей, имеющих детей. Родители без детей не будут отображаться.

DECLARE @ProjectCategories TABLE 
(
    categoryid   INT, 
    categoryname  VARCHAR(10), 
    projectid   INT, 
    parentcategoryid INT, 
    sortorder   INT 
) 

INSERT INTO @ProjectCategories 
SELECT 1, 'Main1', 1, null, 1 UNION ALL 
SELECT 2, 'Child1', 1, 1,  1 UNION ALL 
SELECT 3, 'Child2', 1, 2,  1 UNION ALL 
SELECT 4, 'Child3', 1, 3,  1 UNION ALL 
SELECT 5, 'Child4', 1, 4,  1 UNION ALL 
SELECT 6, 'MainA', 2, null, 1 UNION ALL 
SELECT 7, 'ChildA', 2, 6,  1 UNION ALL 
SELECT 8, 'ChildB', 2, 7,  1 UNION ALL 
SELECT 9, 'Main!', 3, null, 1 

SELECT * 
FROM @ProjectCategories Child 
    INNER JOIN @ProjectCategories Parent 
     ON Child.parentcategoryid = Parent.categoryid 
      AND Parent.parentcategoryid IS NULL 

Здесь все родители, независимо, если есть дети:

DECLARE @ProjectCategories TABLE 
(
    categoryid   INT, 
    categoryname  VARCHAR(10), 
    projectid   INT, 
    parentcategoryid INT, 
    sortorder   INT 
) 

INSERT INTO @ProjectCategories 
SELECT 1, 'Main1', 1, null, 1 UNION ALL 
SELECT 2, 'Child1', 1, 1,  1 UNION ALL 
SELECT 3, 'Child2', 1, 2,  1 UNION ALL 
SELECT 4, 'Child3', 1, 3,  1 UNION ALL 
SELECT 5, 'Child4', 1, 4,  1 UNION ALL 
SELECT 6, 'MainA', 2, null, 1 UNION ALL 
SELECT 7, 'ChildA', 2, 6,  1 UNION ALL 
SELECT 8, 'ChildB', 2, 7,  1 UNION ALL 
SELECT 9, 'Main!', 3, null, 1 

SELECT * 
FROM @ProjectCategories Parent 
WHERE Parent.parentcategoryid IS NULL 

Вот рекурсивное CTE, который будет получать все дети для родителей, независимо от того, сколько детей есть.

DECLARE @ProjectCategories TABLE 
(
    categoryid   INT, 
    categoryname  VARCHAR(10), 
    projectid   INT, 
    parentcategoryid INT, 
    sortorder   INT 
) 

INSERT INTO @ProjectCategories 
SELECT 1, 'Main1', 1, null, 1 UNION ALL 
SELECT 2, 'Child1', 1, 1,  1 UNION ALL 
SELECT 3, 'Child2', 1, 2,  1 UNION ALL 
SELECT 4, 'Child3', 1, 3,  1 UNION ALL 
SELECT 5, 'Child4', 1, 4,  1 UNION ALL 
SELECT 6, 'MainA', 2, null, 1 UNION ALL 
SELECT 7, 'ChildA', 2, 6,  1 UNION ALL 
SELECT 8, 'ChildB', 2, 7,  1 UNION ALL 
SELECT 9, 'Main!', 3, null, 1 


;WITH Projects 
(
    categoryid, 
    categoryname, 
    parentcategoryid 
) 
AS 
(
    -- Base Case 
    SELECT categoryid, 
      categoryname, 
      parentcategoryid 
    FROM @ProjectCategories 
    WHERE projectid = 1 -- Change this to 1, 2, or 3 
     AND parentcategoryid IS NULL 
    UNION ALL 
    -- Recursive 
    SELECT pc.categoryid, 
      pc.categoryname, 
      pc.parentcategoryid 
    from Projects 
     INNER JOIN @ProjectCategories pc 
      ON pc.parentcategoryid = Projects.categoryid 
) 
SELECT * from Projects 
+0

Увы, все, чего он действительно хочет, это родители. – SQLMason