我在SQL Server 2008中有2个表,customertest
包含客户ID(cid
)列和它的老板ID(upid
),conftest
表{{1} },cid
,confname
自定义架构和数据:
conftest架构和数据:
我想知道如何设计一个CTE,如果confvalue
中的cid
没有conftest
的{{1}},它会继续搜索{{1}直到找到包含confname
和confvalue
的上面一行。
例如,如果我搜索cid = 4,我想得到100的值(这是正常情况)。如果我搜索cid = 7或8,我想得到200的值。
如果cid7和cid8有子节点,如果我使用这个CTE搜索它将全部返回200(cid5)。
我不知道如何做到这一点,我想也许可以使用CTE和一些左外连接,请给我一些例子?非常感谢。
答案 0 :(得分:0)
如果不知道层次结构中有多少级别?
然后这种挑战通常通过递归CTE完成。
示例代码段
--
-- Using table variables for testing reasons
--
declare @customertest table (cid int primary key, upid int);
declare @conftest table (cid int, confname varchar(6) default 'budget', confvalue int);
--
-- Sample data
--
insert into @customertest (cid, upid) values
(1,0), (2,1), (3,1), (4,2), (5,2), (6,3),
(7,5), (8,5), (9,8), (10,9);
insert into @conftest (cid, confvalue) values
(1,1000), (2,700), (3,300), (4,100), (5,200), (6,300);
-- The customer that has his own budget, or not.
declare @customerID int = 10;
;with RCTE AS
(
--
-- the recursive CTE starts from here. The seed records, as one could call it.
--
select cup.cid as orig_cid, 0 as lvl, cup.cid, cup.upid, budget.confvalue
from @customertest as cup
left join @conftest budget on (budget.cid = cup.cid and budget.confname = 'budget')
where cup.cid = @customerID -- This is where we limit on the customer
union all
--
-- This is where the Recursive CTE loops till it finds nothing new
--
select RCTE.orig_cid, RCTE.lvl+1, cup.cid, cup.upid, budget.confvalue
from RCTE
join @customertest as cup on (cup.cid = RCTE.upid)
outer apply (select b.confvalue from @conftest b where b.cid = cup.cid and b.confname = 'budget') as budget
where RCTE.confvalue is null -- Loop till a budget is found
)
select
orig_cid as cid,
confvalue
from RCTE
where confvalue is not null;
结果:
cid confvalue
--- ---------
10 200
顺便说一句,递归CTE使用OUTER APPLY,因为MS SQL Server不允许在那里使用LEFT OUTER JOIN。
如果确定预算的upid最多有1级深度? 然后只需简单的左连接和合并即可。
例如:
select cup.cid, coalesce(cBudget.confvalue, upBudget.confvalue) as confvalue
from @customertest as cup
left join @conftest cBudget on (cBudget.cid = cup.cid and cBudget.confname = 'budget')
left join @conftest upBudget on (upBudget.cid = cup.upid and upBudget.confname = 'budget')
where cup.cid = 8;
答案 1 :(得分:0)
根据我的理解,我不认为你正在寻找CTE
来做这件事:
CREATE TABLE CustomerTest(
CID INT,
UPID INT
);
CREATE TABLE ConfTest(
CID INT,
ConfName VARCHAR(45),
ConfValue INT
);
INSERT INTO CustomerTest VALUES
(1, 0),
(2, 1),
(3, 1),
(4, 2),
(5, 2),
(6, 3),
(7, 5),
(8, 5);
INSERT INTO ConfTest VALUES
(1, 'Budget', 1000),
(2, 'Budget', 700),
(3, 'Budget', 300),
(4, 'Budget', 100),
(5, 'Budget', 200),
(6, 'Budget', 300);
SELECT MAX(CNT.CID) AS CID,
CNT.ConfName,
MIN(CNT.ConfValue) AS ConfValue
FROM ConfTest CNT INNER JOIN CustomerTest CMT ON CMT.CID = CNT.CID
OR CMT.UPID = CNT.CID
WHERE CMT.CID = 7 -- You can test for values (8, 4) or any value you want :)
GROUP BY
CNT.ConfName;