我需要帮助解决有关保存在父子模型表中的数据以及我需要在其上构建的报告的问题。我已经尝试过搜索有关亲子问题的主题,但我在我的方案中找不到任何有用的东西。
我有什么
Microsoft SQL Server 2000数据库服务器。
一个categories
表,其中有四列:category_id
,category_name
,father_id
和visible
;这些类别有 x 根类别(其中 x 是可变的),并且可能 y 级别深(其中 y 是变量),如果一个类别是根级别,它有father_id
null,否则它填充了父类别的id。
一个sales
表,其中包含 z 列,其中一列为category_id
,是categories.category_id
的外键;销售必须始终具有类别,并且可以链接到上述 y 级别的任何位置。
我需要什么
我被问到一份报告,只显示根(第一级)类别,以及每个类别或其子项的销售物品数量,无论多深。即如果其中一个根类别为food
,其中有一个名为fruit
的子类别,其子类别名为apple
,则我需要计算属于food
的每个项目或fruit
或apple
。
您是否无法使用嵌套集数据模型?
我知道嵌套集模型,但我已经有了这样的表,并将它迁移到嵌套集模型会很痛苦(更不用说我甚至没有完全掌握嵌套集如何工作),不算数使用数据库的应用程序中所需的更改。 (如果有人认为这仍然是最不痛苦的方式,请解释为什么以及如何迁移当前数据。)
你不能使用CTE(通用表格式)吗?
不,它是Microsoft SQL Server 2000 ,并且 2005 版本中引入了公用表表达式。
先谢谢,安德烈。
答案 0 :(得分:1)
DECLARE @Stack TABLE (
StackID INTEGER IDENTITY
, Category VARCHAR(20)
, RootID INTEGER
, ChildID INTEGER
, Visited BIT)
INSERT INTO @Stack
SELECT [Category] = c.category_name
, [RootID] = c.category_id
, [ChildID] = c.category_id
, 0
FROM Categories c
WHILE EXISTS (SELECT * FROM @Stack WHERE Visited = 0)
BEGIN
DECLARE @StackID INTEGER
SELECT @StackID = MAX(StackID) FROM @Stack
INSERT INTO @Stack
SELECT st.Category
, st.RootID
, c.category_id
, 0
FROM @Stack st
INNER JOIN Categories c ON c.father_id = st.ChildID
WHERE Visited = 0
UPDATE @Stack
SET Visited = 1
WHERE StackID <= @StackID
END
SELECT st.RootID
, st.Category
, COUNT(s.sales_id)
FROM @Stack st
INNER JOIN Sales s ON s.category_id = st.ChildID
GROUP BY st.RootID, st.Category
ORDER BY st.RootID
CTE可以为您提供所需的内容
INNER JOIN
您的销售表的结果。由于每个 root 都在CTE的结果中,因此简单的GROUP BY
足以获得每个项目的计数。SQL声明
;WITH QtyCTE AS (
SELECT [Category] = c.category_name
, [RootID] = c.category_id
, [ChildID] = c.category_id
FROM Categories c
UNION ALL
SELECT cte.Category
, cte.RootID
, c.category_id
FROM QtyCTE cte
INNER JOIN Categories c ON c.father_id = cte.ChildID
)
SELECT cte.RootID
, cte.Category
, COUNT(s.sales_id)
FROM QtyCTE cte
INNER JOIN Sales s ON s.category_id = cte.ChildID
GROUP BY cte.RootID, cte.Category
ORDER BY cte.RootID
答案 1 :(得分:0)
这样的东西?
CREATE TABLE #SingleLevelCategoryCounts
{
category_id,
count,
root_id
}
CREATE TABLE #ProcessedCategories
{
category_id,
root_id
}
CREATE TABLE #TotalTopLevelCategoryCounts
{
category_id,
count
}
INSERT INTO #SingleLevelCategoryCounts
SELECT
category_id, SUM(*), category_id
FROM
Categories
INNER JOIN Sales ON Categories.category_id = sales.category_id
WHERE
Categories.father_id IS NULL
GROUP BY
Categories.category_id
WHILE EXISTS (SELECT * FROM #SingleLevelCategoryCounts)
BEGIN
IF NOT EXISTS(SELECT * FROM #TopLevelCategoryCounts)
BEGIN
INSERT INTO #TopLevelCategoryCounts
SELECT
root_id, count
FROM
#SingleLevelCategoryCounts
END
ELSE
BEGIN
UPDATE top
SET
top.count = top.count + level.count
FROM
#TopLevelCategoryCounts top
INNER JOIN #SingleLevelCategoryCounts level ON top.category_id = level.count
END
INSERT INTO #ProcessedCategories
SELECT category_id, root_id FROM #SingleLevelCategoryCounts
DELETE #SingleLevelCategoryCounts
INSERT INTO #SingleLevelCategoryCounts
SELECT
category_id, SUM(*), pc.root_id
FROM
Categories
INNER JOIN Sales ON Categories.category_id = sales.category_id
INNER JOIN #ProcessedCategories pc ON Categories.father_id = pc.category_id
WHERE
Categories.category_id NOT IN
(
SELECT category_id in #ProcessedCategories
)
GROUP BY
Categories.category_id
END