我需要在用户树所获得的每个级别上加分。级别1是用户1级以下用户的用户点数之和。 2级是用户等级2级以下用户的等级1点......
计算在非生产服务器上每月发生一次,不用担心性能。
SQL会是什么样子?
如果你感到困惑,别担心,我也好!
用户表:
ID ParentID Points
1 0 230
2 1 150
3 0 80
4 1 110
5 4 54
6 4 342
Tree:
0
|---\
1 3
| \
2 4---
\ \
5 6
输出应为:
ID Points Level1 Level2
1 230 150+110 150+110+54+342
2 150
3 80
4 110 54+342
5 54
6 342
SQL Server语法和函数最好......
答案 0 :(得分:2)
如果您使用的Oracle DBMS非常简单,因为Oracle支持使用 CONNECT BY / STARTS WITH 语法进行树查询。对于SQL Server,我认为您可能会发现Common Table Expressions有用
答案 1 :(得分:2)
树与SQL不兼容。如果你有非常(非常非常)的写访问,你可以改变树实现以使用嵌套集,这将使这个查询非常容易。
示例(如果我没记错的话):
SELECT SUM(points)
FROM users
where left > x and right < y
但是,树上的任何更改都需要触摸大量行。在您的客户端进行递归可能更好。
答案 2 :(得分:1)
我会说:创建一个存储过程,可能具有最佳性能。 或者,如果您有最大级别数,则可以创建子查询,但它们的性能非常高。
(或者你可以获得MS SQL Server 2008并获得新的层次结构函数......;))
答案 3 :(得分:1)
如果您正在使用存储在关系数据库中的树,我建议您查看“嵌套集”或“修改前序树遍历”。 SQL就像那样简单:
SELECT id,
SUM(value) AS value
FROM table
WHERE left>left\_value\_of\_your\_node
AND right<$right\_value\_of\_your\_node;
...并为您感兴趣的每个节点执行此操作。
也许这会对你有所帮助: http://www.dbazine.com/oracle/or-articles/tropashko4或使用谷歌。
答案 4 :(得分:1)
每次在“表格”中添加记录时,您:
INSERT INTO relations (id, parent_id) VALUES ([current_id], [current_id]);
INSERT INTO relations (id, parent_id) VALUES ([current_id], [current_parent_id]);
INSERT INTO relations (id, parent_id)
SELECT [current_id], parent_id
FROM relations
WHERE id = [current_parent_id];
有逻辑来避免循环
确保使用存储过程处理“关系”的更新,删除
鉴于该表,您需要:
SELECT rel.parent_id, SUM(tbl.points)
FROM table tbl INNER JOIN relations rel ON tbl.id=rel.id
WHERE rel.parent_id <> 0
GROUP BY rel.parent_id;
答案 5 :(得分:1)
好的,这可以为您提供所需的结果,但无法保证我没有错过任何内容。认为这是一个起点。我使用SQL 2005来做到这一点,SQL 2000不支持CTE的
WITH Parent (id, GrandParentId, parentId, Points, Level1Points, Level2Points)
AS
(
-- Find root
SELECT id,
0 AS GrandParentId,
ParentId,
Points,
0 AS Level1Points,
0 AS Level2Points
FROM tblPoints ptr
WHERE ptr.ParentId = 0
UNION ALL (
-- Level2 Points
SELECT pa.GrandParentId AS Id,
NULL AS GrandParentId,
NULL AS ParentId,
0 AS Points,
0 AS Level1Points,
pa.Points AS Level2Points
FROM tblPoints pt
JOIN Parent pa ON pa.GrandParentId = pt.Id
UNION ALL
-- Level1 Points
SELECT pt.ParentId AS Id,
NULL AS GrandParentId,
NULL AS ParentId,
0 AS Points,
pt.Points AS Level1Points,
0 AS Level2Points
FROM tblPoints pt
JOIN Parent pa ON pa.Id = pt.ParentId AND pa.ParentId IS NOT NULL
UNION ALL
-- Points
SELECT pt.id,
pa.ParentId AS GrandParentId,
pt.ParentId,
pt.Points,
0 AS Level1Points,
0 AS Level2Points
FROM tblPoints pt
JOIN Parent pa ON pa.Id = pt.ParentId AND pa.ParentId IS NOT NULL )
)
SELECT id,
SUM(Points) AS Points,
SUM(Level1Points) AS Level1Points,
CASE WHEN SUM(Level2Points) > 0 THEN SUM(Level1Points) + SUM(Level2Points) ELSE 0 END AS Level2Points
FROM Parent
GROUP BY id
ORDER by id
答案 6 :(得分:0)
您有几个选择:
答案 7 :(得分:0)
您可以编写一个简单的递归函数来完成这项工作。我的MSSQL有点生疏,但它看起来像这样:
CREATE FUNCTION CALC
(
@node integer,
)
returns
(
@total integer
)
as
begin
select @total = (select node_value from yourtable where node_id = @node);
declare @children table (value integer);
insert into @children
select calc(node_id) from yourtable where parent_id = @node;
@current = @current + select sum(value) from @children;
return
end
答案 8 :(得分:0)
下表:
Id ParentId
1 NULL
11 1
12 1
110 11
111 11
112 11
120 12
121 12
122 12
123 12
124 12
以下Amount表:
Id Val
110 500
111 50
112 5
120 3000
121 30000
122 300000
只有叶子(最后一级)Id具有定义的值。 获取数据的SQL查询如下所示:
;WITH Data (Id, Val) AS
(
select t.Id, SUM(v.val) as Val from dbo.TestTable t
join dbo.Amount v on t.Id = v.Id
group by t.Id
)
select cd.Id, ISNULL(SUM(cd.Val), 0) as Amount FROM
(
-- level 3
select t.Id, d.val from TestTable t
left join Data d on d.id = t.Id
UNION
-- level 2
select t.parentId as Id, sum(y.Val) from TestTable t
left join Data y on y.id = t.Id
where t.parentId is not null
group by t.parentId
UNION
-- level 1
select t.parentId as Id, sum(y.Val) from TestTable t
join TestTable c on c.parentId = t.Id
left join Data y on y.id = c.Id
where t.parentId is not null
group by t.parentId
) AS cd
group by id
这导致输出:
Id Amount
1 333555
11 555
12 333000
110 500
111 50
112 5
120 3000
121 30000
122 300000
123 0
124 0
我希望这会有所帮助。