我认为这是一种需要的正常查询,但有时您必须知道问题的通用名称才能找到有关解决问题的更多信息。我称之为“指挥链”。问题
我有以下表结构:
using System;
using AppoMobi;
using AppoMobi.Droid.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using ListView = Xamarin.Forms.ListView;
[assembly: ExportRenderer(typeof(NiftyListView), typeof(NiftyListViewRenderer))]
namespace AppoMobi.Droid.Renderers
{
//-------------------------------------------------------------------
class NiftyListViewRenderer : ListViewRenderer
//-------------------------------------------------------------------
{
protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
{
base.OnElementChanged(e);
var view = (NiftyListView)Element;
if (view == null) return;
view.EventScrollToTop += OnScrollToTop;
}
//-------------------------------------------------------------------------------------------
public async void OnScrollToTop(object sender, EventArgs eventArgs)
//-------------------------------------------------------------------------------------------
{
Control.SmoothScrollToPositionFromTop(0, 0);
}
}
}
以下示例数据:
create table employee_boss_history (
name nvarchar(50),
boss nvarchar(50),
start_date date,
end_date date
);
此(假)数据表示某人的经理发生变化。
我想要做的是有一个查询,它将占用整个表并构建所有的命令链。每个员工和命令链应该有一行,它应该具有命令链生效的最早日期和最新日期。如果他们的命令链中的任何人改变了,那么他们应该添加另一个命令记录链。
例如,Rich有四个不同的经理,但随着时间的推移,他的命令结构至少会有六个不同的变化。也许更多,我试图手工解决。
insert into employee_boss_history (name, boss, start_date, end_date)
VALUES
('Bill', null, '2002-01-01', '2016-03-01'),
('Will', 'Bill', '2015-03-02', '2016-03-01'),
('Will', null, '2016-03-02', null),
('Mark', 'Bill', '2003-01-01', '2006-12-31'),
('Mark', 'Bill', '2012-01-01', '2016-03-01'),
('Mark', 'Will', '2016-03-02', '2016-04-30'),
('Ross', 'Will', '2016-05-01', null),
('Roger', 'Bill', '2006-01-01', '2012-03-01'),
('Roger', 'Mark', '2012-03-02', '2012-09-30'),
('Kris', 'Mark', '2012-10-01', '2016-04-30'),
('Kris', 'Ross', '2016-05-01', '2017-01-31'),
('Moe', 'Ross', '2017-03-01', null),
('Rich', 'Roger', '2006-03-01', '2012-09-30'),
('Rich', 'Kris', '2012-10-01', '2017-01-31'),
('Rich', 'Ross', '2017-02-01', '2017-02-28'),
('Rich', 'Moe', '2017-03-01', null)
我已经开发了一个CTE,我可以传入一个人和一个日期,然后它会走到邻接列表并显示该日期的层次结构。它有效,但我试图建立一个像上面这样的摘要。
对于解决方案的指针表示感谢,或者如果我有更多的阅读材料(这被认为是差距和岛屿吗?),请告诉我。
谢谢。
答案 0 :(得分:2)
这是使用递归CTE攻击它的第一步。
WITH recCTE AS
(
SELECT
name as starting_name,
name,
boss,
start_Date,
end_date,
CAST(name as VARCHAR(200)) as coc,
1 as depth
FROM employee_boss_history
WHERE name = 'Rich'
UNION ALL
SELECT
recCTE.starting_name,
ebh.name,
ebh.boss,
CASE WHEN recCTE.start_date < ebh.start_date THEN ebh.start_date ELSE recCTE.start_Date END,
CASE WHEN recCTE.end_date > ebh.end_date THEN ebh.end_date ELSE recCTE.end_Date END,
cast(recCTE.coc + ' | ' + ebh.name as varchar(200)),
recCTE.depth + 1
FROM recCTE
INNER JOIN employee_boss_history ebh ON
recCTE.boss = ebh.name AND
recCTE.start_date <= ebh.end_date AND
recCTE.end_Date >= ebh.start_date
)
SELECT starting_name, coc as chain_of_command, start_date, end_date, depth FROM recCTE;
递归CTE分为两部分。
最后但只是从CTE中选择。你会看到你在递归的每一步都得到了记录,但是......我认为这会让你接近你需要的位置。
+---------------+----------------------------+------------+-----------+-------+
| starting_name | chain_of_command | start_date | end_date | depth |
+---------------+----------------------------+------------+-----------+-------+
| Rich | Rich | 3/1/2006 | 9/30/2012 | 1 |
| Rich | Rich | 10/1/2012 | 1/31/2017 | 1 |
| Rich | Rich | 2/1/2017 | 2/28/2017 | 1 |
| Rich | Rich | 3/1/2017 | (null) | 1 |
| Rich | Rich | Kris | 10/1/2012 | 4/30/2016 | 2 |
| Rich | Rich | Kris | 5/1/2016 | 1/31/2017 | 2 |
| Rich | Rich | Kris | Mark | 10/1/2012 | 3/1/2016 | 3 |
| Rich | Rich | Kris | Mark | 3/2/2016 | 4/30/2016 | 3 |
| Rich | Rich | Kris | Mark | Bill | 10/1/2012 | 3/1/2016 | 4 |
| Rich | Rich | Roger | 3/1/2006 | 3/1/2012 | 2 |
| Rich | Rich | Roger | 3/2/2012 | 9/30/2012 | 2 |
| Rich | Rich | Roger | Mark | 3/2/2012 | 9/30/2012 | 3 |
| Rich | Rich | Roger | Mark | Bill | 3/2/2012 | 9/30/2012 | 4 |
| Rich | Rich | Roger | Bill | 3/1/2006 | 3/1/2012 | 3 |
+---------------+----------------------------+------------+-----------+-------+
答案 1 :(得分:0)
我认为以下代码可以解决问题。我首先将NULL更改为将来日期以简化事物,然后开始递归到层次结构中。当我们有一个&#34; NULL boss&#34;。
时,递归就结束了外部查询然后只选择那些&#34; NULL bosses&#34;,否则它将返回中间步骤。
WITH d AS(
SELECT name, boss, start_date, ISNULL(end_date, '99991231') end_date
FROM employee_boss_history
),
r AS (
SELECT start_date, end_date, name, boss,
CAST(name AS VARCHAR(1000)) AS chain_of_command
FROM d
WHERE name = 'Rich'
UNION ALL
SELECT
CASE WHEN d.start_date > r.start_date THEN d.start_date ELSE r.start_date END,
CASE WHEN d.end_date < r.end_date THEN d.end_date ELSE r.end_date END,
d.name,
d.boss,
CAST(CONCAT_WS(' | ', chain_of_command, d.name) AS VARCHAR(1000))
FROM d
INNER JOIN r
ON d.name = r.boss
AND r.start_date <= d.end_date
AND r.end_date >= d.start_date
)
SELECT start_date, end_date, chain_of_command
FROM r
WHERE boss IS NULL
ORDER BY start_date;