如何在T-SQL中以分层格式高效地分组数据?
我有这样的数据:如何在T-SQL中以分层格式高效地分组数据?,sql,sql-server,sql-server-2005,tsql,Sql,Sql Server,Sql Server 2005,Tsql,我有这样的数据: Task | Hours 1.1 | 40 2 | 40 2.1 | 60 2.1.1 | 15 15.9 | 24 16 | 5 19.1 | 40 19.1.1 | 8 19.1.2 | 12 19.2 | 6 19.2.1 | 21 19.2.2 | 15 19.2.3 | 2 19.3 | 64 我想根据任务的前两个级别进行分
Task | Hours
1.1 | 40
2 | 40
2.1 | 60
2.1.1 | 15
15.9 | 24
16 | 5
19.1 | 40
19.1.1 | 8
19.1.2 | 12
19.2 | 6
19.2.1 | 21
19.2.2 | 15
19.2.3 | 2
19.3 | 64
我想根据任务的前两个级别进行分组,得出以下结果:
Task | Hours
1.1 | 40
2 | 40
2.1 | 75
15.9 | 24
16 | 5
19.1 | 60
19.2 | 44
19.3 | 64
我不想让16个关卡卷起它下面的东西,但我需要所有其他关卡卷起。这是SQLServer2005。我通常会在小数点上进行拆分,并以这种方式进行拆分,但我想知道是否有更好的方法在SQL中进行拆分。假设字段任务的结构是一致的,您可以使用以下方法
select left(task,4) as Task,sum(hours) as Hours
from table
group by left(task,4)
这是一个稍微修改过的版本
select LEFT(task,charindex('.',task+'.')+1),SUM(hours)
from test1
group by LEFT(task,charindex('.',task+'.')+1)
假设现场任务的结构是一致的,您可以使用以下方法
select left(task,4) as Task,sum(hours) as Hours
from table
group by left(task,4)
这是一个稍微修改过的版本
select LEFT(task,charindex('.',task+'.')+1),SUM(hours)
from test1
group by LEFT(task,charindex('.',task+'.')+1)
改变模型是一种选择吗?如果您的任务列实际上是要表示层次结构,那么您应该在关系模型中正确地表示层次结构 如果深度级别的数量固定为三,另一个选项可能是添加三列,分别表示任务列的每个“部分” 如果这不是一个选项,我认为您可以通过一系列CASE语句来解析字符串(加上SUM和groupby)来实现这一点 更新: 好吧,这似乎是一个有趣的挑战,所以我想出了这个:
SELECT
main_task,
SUM(hours)
FROM
(
SELECT
task,
CASE
WHEN
LEN(task) + 1 - CHARINDEX('.', REVERSE(task)) = CHARINDEX ('.', task) THEN task
ELSE LEFT(task, LEN(task) + 1 - CHARINDEX('.', REVERSE(task)) - 1)
END main_task,
hours
FROM
#temp
) sub
GROUP BY
main_task
改变模型是一种选择吗?如果您的任务列实际上是要表示层次结构,那么您应该在关系模型中正确地表示层次结构 如果深度级别的数量固定为三,另一个选项可能是添加三列,分别表示任务列的每个“部分” 如果这不是一个选项,我认为您可以通过一系列CASE语句来解析字符串(加上SUM和groupby)来实现这一点 更新: 好吧,这似乎是一个有趣的挑战,所以我想出了这个:
SELECT
main_task,
SUM(hours)
FROM
(
SELECT
task,
CASE
WHEN
LEN(task) + 1 - CHARINDEX('.', REVERSE(task)) = CHARINDEX ('.', task) THEN task
ELSE LEFT(task, LEN(task) + 1 - CHARINDEX('.', REVERSE(task)) - 1)
END main_task,
hours
FROM
#temp
) sub
GROUP BY
main_task
另一种方法是添加一些计算列,将各个任务级别分开,然后根据需要分组和求和。另一种方法是添加一些计算列,将各个任务级别分开,然后根据需要分组和求和。我在回家的路上考虑过这个问题,我想提出以下解决方案: 创建一个存储层次结构的表,然后执行一个获取任务父级的联接 TaskStructureTable:
task | task_group
1 | 1
1.1 | 1.1
1.1.1 | 1.1
1.1.2 | 1.1
1.1.3 | 1.1
1.2 | 1.2
1.2.1 | 1.2
然后我可以这样做:
SELECT SUM(d.Hours) AS "Hours", t.task_group
FROM Data d
JOIN TaskStructureTable t ON d.Task = t.task
你认为这比做CHARINDEX要快吗?(是的,我可以测量并确定)我在开车回家的路上考虑过这个问题,我想提出这个解决方案: 创建一个存储层次结构的表,然后执行一个获取任务父级的联接 TaskStructureTable:
task | task_group
1 | 1
1.1 | 1.1
1.1.1 | 1.1
1.1.2 | 1.1
1.1.3 | 1.1
1.2 | 1.2
1.2.1 | 1.2
然后我可以这样做:
SELECT SUM(d.Hours) AS "Hours", t.task_group
FROM Data d
JOIN TaskStructureTable t ON d.Task = t.task
你认为这比做CHARINDEX要快吗?(是的,我可以测量并肯定知道)如果中间部分超过一个数字,我认为您的更新答案仍然会失败?如果你能确定中间部分的长度并用该值替换“+1”,我想你已经知道了。如果中间部分超过一个数字,你的更新答案仍然会失败?如果你能确定中间部分的长度,并用该值替换“+1”,我认为你已经做到了。我认为如果你的建议符合你的要求,你几乎可以将任务组视为一个“类别”,而不是层次结构的一部分。您甚至不需要单独的表,尽管我建议使用一个表来实现引用完整性(有点像类别查找)。是的,以这种方式构造它并在类别(_id)上放置索引肯定比解析字符串性能更好。如果要更改模型,并且使用sql 2008,则可以研究使用hierarchyid数据类型。这将使在任何级别分解报告变得非常简单。SQL Server 2005不幸的是,我认为如果您的建议符合您的要求,您几乎可以将任务组视为一个“类别”,而不是层次结构的一部分。您甚至不需要单独的表,尽管我建议使用一个表来实现引用完整性(有点像类别查找)。是的,以这种方式构造它并在类别(_id)上放置索引肯定比解析字符串性能更好。如果要更改模型,并且使用sql 2008,则可以研究使用hierarchyid数据类型。这将使在任意级别分解报表变得非常简单。SQL Server 2005不幸的是,我认为在模型中存储层次结构是正确的。我发布了一种可能的方法——这与您的想法一致吗?我认为您在模型中存储层次结构的想法是正确的。我发布了一个可能的方法——这是否符合你的想法?