SQL Server:对两个不显示层次关系的条件逻辑的递归高级查询
最近,我在SQL Server 2012中遇到了一个需要解决的难题。这就是问题的背景 我们在产品实体中维护一个自引用实体(层次结构)。每种产品都有亲子关系 产品具有称为主产品的特殊分组,主产品基于以下逻辑派生SQL Server:对两个不显示层次关系的条件逻辑的递归高级查询,sql,sql-server,tsql,sql-server-2012,common-table-expression,Sql,Sql Server,Tsql,Sql Server 2012,Common Table Expression,最近,我在SQL Server 2012中遇到了一个需要解决的难题。这就是问题的背景 我们在产品实体中维护一个自引用实体(层次结构)。每种产品都有亲子关系 产品具有称为主产品的特殊分组,主产品基于以下逻辑派生 如果在层次结构上只有一个产品,不管 ISMASTEMPRODCUT/标志,它都要考虑主帐户。 P. >其他产品,其直接母产品标注为主产品或最优先考虑的主要产品。 图形表示如下: 这是DDL -- Create Table CREATE TABLE Product ( Prod
如果在层次结构上只有一个产品,不管<代码> ISMASTEMPRODCUT/<代码>标志,它都要考虑主帐户。
<> P. >其他产品,其直接母产品标注为主产品或最优先考虑的主要产品。 图形表示如下: 这是DDL-- Create Table
CREATE TABLE Product
(
ProductID int PRIMARY KEY,
Name VARCHAR(30) NOT NULL,
ParentId int,
IsMasterProdcut bit NOT NULL
)
-- Insert the data to the table
-- Senario where top most product is the master product
INSERT INTO Product (ProductID,Name,ParentId,IsMasterProdcut) VALUES (1,'Prodcut 1',NULL,0); -- <-- this is the master prodcut as non of the child as flaged
INSERT INTO Product (ProductID,Name,ParentId,IsMasterProdcut) VALUES (2,'Prodcut 2',1,0);
INSERT INTO Product (ProductID,Name,ParentId,IsMasterProdcut) VALUES (3,'Prodcut 3',2,0);
-- Senario two where in middnle account has flag as master product
INSERT INTO Product (ProductID,name,ParentId,IsMasterProdcut) VALUES (4,'Prodcut 4',NULL,0); -- <-- this is the master prodcut as this is top most in hirerachy . So 4 will be master prodcut of 4 and 5 , 6 and 7 will not master product
INSERT INTO Product (ProductID,Name,ParentId,IsMasterProdcut) VALUES (5,'Prodcut 5',4,0);
INSERT INTO Product (ProductID,Name,ParentId,IsMasterProdcut) VALUES (6,'Prodcut 6',5,1); -- < -- this a a master prodcut as it is flagged as master product , So account 7 and 6 master product with be 6
INSERT INTO Product (ProductID,Name,ParentId,IsMasterProdcut) VALUES (7,'Prodcut 7',6,0);
-- Senario three where it has one product
INSERT INTO Product (ProductID,Name,ParentId,IsMasterProdcut) VALUES (8,'Prodcut 8',0,0);
INSERT INTO Product (ProductID,Name,ParentId,IsMasterProdcut) VALUES (9,'Prodcut 9',0,1);
-- Senario 4 Complex product
INSERT INTO Product (ProductID,Name,ParentId,IsMasterProdcut) VALUES (10,'Prodcut 10',0,0);
INSERT INTO Product (ProductID,Name,ParentId,IsMasterProdcut) VALUES (11,'Prodcut 11',10,0);
INSERT INTO Product (ProductID,Name,ParentId,IsMasterProdcut) VALUES (12,'Prodcut 12',11,1);
INSERT INTO Product (ProductID,Name,ParentId,IsMasterProdcut) VALUES (13,'Prodcut 13',12,0);
INSERT INTO Product (ProductID,Name,ParentId,IsMasterProdcut) VALUES (14,'Prodcut 14',10,0);
INSERT INTO Product (ProductID,Name,ParentId,IsMasterProdcut) VALUES (15,'Prodcut 15',14,0);
INSERT INTO Product (ProductID,Name,ParentId,IsMasterProdcut) VALUES (16,'Prodcut 16',15,0);
INSERT INTO Product (ProductID,Name,ParentId,IsMasterProdcut) VALUES (17,'Prodcut 17',10,0);
工作解决方案:这是我目前得到的解决方案:
BEGIN
CREATE TABLE #TmpMasterProduct
(
ProductId nvarchar(50)
)
INSERT INTO #TmpMasterProduct
SELECT ProductId
FROM (
-- Get master accounts which are flagged as master product
SELECT MA.ProductId
FROm [dbo].[Product] AS MA WITH (NOLOCK)
WHERE MA.[IsMasterProdcut] = 1
UNION
-- Get top most prodcut which will be automatically consider as master product.
SELECT MAT.ProductId
FROM DBO.[Product] As MAT WITH (NOLOCK)
WHERE MAT.[ParentId] IS NULL
) AS MasterProdcuts;
WITH Mapping as
(
SELECT A.ProductId , A.ParentId
FROM DBO.[Product] A
WHERE A.ProductId IN
(
SELECT ProductId
FROM #TmpMasterProduct
)
UNION ALL
SELECT A.ProductId , A.ParentId
FROM DBO.[Product] A
INNER JOIN Mapping M
ON M.ProductId = A.ParentID
)
SELECT M.ParentId As MasterProductId , MP.Name As MasterProductName , M.ProductId As ProdcutId , CP.Name As ProductName
From Mapping As M
LEFT OUTER JOIN DBO.Product As MP ON MP.ProductId = M.ParentId
LEFT OUTER JOIN DBO.Product As CP On CP.ProductId = M.ProductId
DROP TABLE #TmpMasterProduct
END
但我偏离了我想要的结果。这是我得到的电流输出
MasterProductId MasterProductName ProdcutId ProductName
NULL NULL 1 Prodcut 1
NULL NULL 4 Prodcut 4
5 Prodcut 5 6 Prodcut 6
0 NULL 9 Prodcut 9
11 Prodcut 11 12 Prodcut 12
12 Prodcut 12 13 Prodcut 13
6 Prodcut 6 7 Prodcut 7
4 Prodcut 4 5 Prodcut 5
5 Prodcut 5 6 Prodcut 6
6 Prodcut 6 7 Prodcut 7
1 Prodcut 1 2 Prodcut 2
2 Prodcut 2 3 Prodcut 3
基本上,我写的这个查询并没有深入到更深的层次。它从父级终止。我的第二个观察结果是,这确实拾取了不是主产品的父节点
我的方法错了吗?除了光标,我能做的最好的方法是什么 您走在正确的轨道上:)一些修复: 您在产品8和10中插入零,而不是null,如
ParentId
-这就是为什么在初始#TmpMasterProduct
查询中从未提取它们-您需要将它们更改回null,例如
INSERT INTO Product (ProductID,Name,ParentId,IsMasterProdcut)
VALUES (8,'Prodcut 8',NULL,0);
(另外,如果您在自联接上使用来自ParentId->ProductId
的外键强制引用完整性,则可以防止此类问题)
您不需要主产品预滤器上的接头
-您只需使用或
,即:
INSERT INTO #TmpMasterProduct
SELECT MA.ProductId
FROM
[dbo].[Product] AS MA
WHERE MA.[IsMasterProdcut] = 1 OR MA.[ParentId] IS NULL;
在递归CTE中,您需要记住每个主产品树的实际主产品ID
,而不一定是父产品ID
,以允许层次结构大于1深,即
WITH Mapping as
(
SELECT A.ProductId as MasterProductId, A.ProductId , A.ParentId ...
UNION ALL
SELECT M.MasterProductId, A.ProductId , A.ParentId ...
您需要在导航树时引入一个终止条件,当有一个节点本身是主产品时,该树终止(这将单独列出)
您需要按MasterProductId
订购项目,以便将它们打印出来
您试图通过查询解决的实际问题是什么?我无法从您的描述中非常清楚地理解。@shree.pat18我正在尝试完成主产品到产品的映射,但我遇到的问题是,由于主产品派生逻辑有点复杂,我无法从sql中处理它。我目前正在使用C夏普来做这件事。实际上,看起来您想要的订单可能只是
ProductId
。您还可以使用附加的CTE完全避免使用#Temp表。谢谢,这就是我要找的。现在,我将尝试我的实际数据。
WITH Mapping as
(
SELECT A.ProductId as MasterProductId, A.ProductId , A.ParentId ...
UNION ALL
SELECT M.MasterProductId, A.ProductId , A.ParentId ...
AND A.IsMasterProdcut = 0