相当棘手的情况。我有一张桌子如下。基本上我想从SQL Server 2012中的每个RangeSet中获取范围的所有组合。
最好我展示一个结构和所需输出的例子。问题是RangeSetID的数量可以是动态的,并且RangeID的数量在每个范围集中都是动态的
RangeID RangeSetID
------------------
1 4
2 4
3 4
4 4
5 2
6 2
7 2
8 2
9 2
10 2
11 1
12 1
13 1
14 1
15 1
16 1
17 3
18 3
19 3
20 3
我需要输出以递归方式创建以下数据集:
1 5 11 17 (first from range4, first from range2, first from range1, first from range3)
1 5 11 18 (first from range4, first from range2, first from range1, second from range3)
1 5 11 19 (first from range4, first from range2, first from range1, third from range3)
1 5 11 20 (first from range4, first from range2, first from range1, fourth from range3)
1 5 12 17 (first from range4, first from range2, second from range1, first from range3)
1 5 12 18 (first from range4, first from range2, second from range1, second from range3)
1 5 12 19
1 5 12 20
依此类推,直到我从每个RangeSetID到达最后一个RangeID并导致
4 10 16 20 (last from range4, last from range2, last from range1, last from range3)
哪个最终会产生以下结果,其中RateID 1垂直显示第一个结果,以允许RangeSetID的动态数量
RateID RangeID
------------------
1 1
1 5
1 11
1 17
2 1
2 5
2 11
2 18
这应该导致11,000行(大约)。我曾尝试过CROSS JOIN等,但我根本无法解决这个问题。
那里有天才吗?
由于
答案 0 :(得分:0)
这种作品,但它过于复杂,可以做一些调整。请注意,我更改了您的示例数据,以包含间隙以测试其是否正常工作。
DECLARE @table TABLE (
range_id INT,
range_set_id INT);
INSERT INTO @table SELECT 1, 4;
INSERT INTO @table SELECT 2, 4;
INSERT INTO @table SELECT 3, 4;
INSERT INTO @table SELECT 5, 4;
INSERT INTO @table SELECT 8, 2;
INSERT INTO @table SELECT 10, 2;
INSERT INTO @table SELECT 17, 2;
INSERT INTO @table SELECT 18, 2;
INSERT INTO @table SELECT 19, 2;
INSERT INTO @table SELECT 20, 2;
INSERT INTO @table SELECT 21, 1;
INSERT INTO @table SELECT 23, 1;
INSERT INTO @table SELECT 28, 1;
INSERT INTO @table SELECT 29, 1;
INSERT INTO @table SELECT 30, 1;
INSERT INTO @table SELECT 33, 1;
INSERT INTO @table SELECT 35, 3;
INSERT INTO @table SELECT 38, 3;
INSERT INTO @table SELECT 39, 3;
INSERT INTO @table SELECT 40, 3;
--Work out the order of the range_set_ids
WITH ordered AS (
SELECT
range_set_id,
range_id,
ROW_NUMBER() OVER (PARTITION BY range_set_id ORDER BY range_id) AS sequential_id
FROM
@table),
ranges AS (
SELECT
range_set_id,
MIN(range_id) AS range_id
FROM
@table
GROUP BY
range_set_id),
range_order AS (
SELECT
range_set_id,
ROW_NUMBER() OVER (ORDER BY range_id) AS order_id
FROM
ranges),
set_count AS (
SELECT
MAX(order_id) AS max_order_id
FROM
range_order),
start_and_end AS (
SELECT
o.range_set_id,
o.order_id,
MIN(range_id) AS min_range_id,
MAX(range_id) AS max_range_id,
COUNT(range_id) AS iterations
FROM
range_order o
INNER JOIN @table t ON t.range_set_id = o.range_set_id
GROUP BY
o.range_set_id,
o.order_id),
toggles AS (
SELECT
s.range_set_id,
s.order_id,
s.iterations AS toggle
FROM
start_and_end s
CROSS JOIN set_count c
WHERE
s.order_id = c.max_order_id
UNION ALL
SELECT
s.range_set_id,
s.order_id,
t.toggle * (s.iterations) AS toggle
FROM
toggles t
INNER JOIN start_and_end s ON s.order_id = t.order_id - 1
WHERE
s.order_id > 0),
toggle_count AS (
SELECT
MAX(toggle * s.iterations) AS max_toggle
FROM
toggles t
CROSS JOIN set_count c
INNER JOIN start_and_end s ON s.order_id = c.max_order_id),
all_combos AS (
SELECT
1 AS rate_set_id,
o.range_set_id,
1 AS sequential_id,
o.order_id,
lt.toggle AS reset_toggle,
ISNULL(t.toggle, 1) AS increment_toggle,
1 AS current_toggle
FROM
range_order o
CROSS JOIN set_count c
INNER JOIN toggles lt ON lt.order_id = o.order_id
LEFT JOIN toggles t ON t.order_id = o.order_id + 1
UNION ALL
SELECT
a.rate_set_id + 1,
a.range_set_id,
CASE
WHEN a.current_toggle = a.reset_toggle THEN 1 --flip back at the end
WHEN a.current_toggle % a.increment_toggle != 0 THEN a.sequential_id --something lower is still toggling
ELSE a.sequential_id + 1 --toggle
END,
a.order_id,
a.reset_toggle,
a.increment_toggle,
CASE
WHEN a.current_toggle < a.reset_toggle THEN a.current_toggle + 1
ELSE 1
END
FROM
all_combos a
CROSS JOIN set_count sc
CROSS JOIN toggle_count tc
WHERE
a.rate_set_id < tc.max_toggle)
SELECT
a.rate_set_id,
a.range_set_id,
o.range_id
FROM
all_combos a
INNER JOIN ordered o ON o.range_set_id = a.range_set_id AND o.sequential_id = a.sequential_id
ORDER BY
a.rate_set_id,
a.order_id
OPTION (MAXRECURSION 0);
答案 1 :(得分:0)
猜猜这应该有所帮助。快乐的编码!
;WITH CTE
AS
(
SELECT * FROM (
SELECT ROW_NUMBER() over (order by [RangeID1] , [RangeID2], [RangeID3], [RangeID4]) as 'RateID', [RangeID1] , [RangeID2], [RangeID3], [RangeID4] FROM
(
select A.RangeID as [RangeID1], B.RangeID as [RangeID2], C.RangeID as [RangeID3], D.RangeID as [RangeID4]
from [Range] as A
inner join [Range] as B on (A.RangeID <= B.RangeID)
inner join [Range] as C on (B.RangeID <= C.RangeID)
inner join [Range] as D on (C.RangeID <= D.RangeID)
where A.RangeSetID <> B.RangeSetID
and B.RangeSetID <> C.RangeSetID
and C.RangeSetID <> D.RangeSetID
) as A) T
UNPIVOT ( RangeID FOR N IN ([RangeID1] , [RangeID2], [RangeID3], [RangeID4] ))P
)
SELECT RateID, RangeID
FROM CTE
答案 2 :(得分:0)
在动态查询中实现了相同的逻辑。这应该适合你,我想
declare @i int = 1;
declare @count int = 0;
declare @cols varchar(max) = '';
declare @select varchar(max) = 'select ';
declare @join varchar(max);
declare @where varchar(max);
declare @query varchar(max);
declare @range varchar(100);
declare @prevrange varchar(100);
declare @rangeid varchar(100);
select @count =count(distinct RangeSetID) from [Range];
while @count > 0
begin
set @range = 'Range' + cast(@i as varchar(max));
set @rangeid = 'RangeID' + cast(@i as varchar(max));
set @cols = @cols + @rangeid + ', ';
set @select = @select + @range + '.RangeID as '+@rangeid + ', ';
if @i = 1
begin
set @join = ' from [Range] as ' + @range;
set @where = 'where ' + @range + '.RangeSetID <> ';
end
else
begin
set @prevrange = 'Range' + cast((@i - 1) as varchar(max));
set @join = @join + ' inner join [Range] as ' + @range + ' on (' + @prevrange + '.RangeID <= ' + @range + '.RangeID)';
if(@count = 1)
set @where = @where + @range+ '.RangeSetID';
else
set @where = @where + @range+ '.RangeSetID and '+ @range+ '.RangeSetID <> ';
end
set @i = @i + 1;
set @count = @count - 1;
end
set @query = '
;WITH CTE
AS
(
SELECT * FROM (
SELECT ROW_NUMBER() over (order by '+ SUBSTRING(@cols, 0, LEN(@cols)) + ') as ''RateID'', '+ SUBSTRING(@cols, 0, LEN(@cols)) +' FROM
(
' + SUBSTRING(@select, 0, LEN(@select)) + char(13) + @join + char(13) + @where + '
) as A) T
UNPIVOT ( RangeID FOR N IN ('+(SUBSTRING(@cols, 0, LEN(@cols))) +' ))P
)
SELECT RateID, RangeID
FROM CTE
';
exec (@query);