2016-06-15 22 views
-1

Ein ziemlich kniffliges Szenario. Ich habe einen Tisch wie unten. Grundsätzlich möchte ich alle Kombinationen von Bereichen von jedem RangeSet in SQL Server 2012 abrufen.SQL Jede Kombination von IDs

Am besten zeige ich ein Beispiel für Struktur und gewünschte Ausgabe. Das Problem ist, die Anzahl der RangeSetID des dynamisch sein kann und die Anzahl der RangeID des in jedem Bereich eingestellt

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 

ich die Ausgabe muß dynamisch sein, um rekursiv die folgenden Datensatz von Raten zu erstellen:

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 

Und so weiter, bis ich die letzte RangeID von jedem RangeSetID und führen in

4 10 16 20 (last from range4, last from range2, last from range1, last from range3) 

erreichen, die letztlich in der Folge wird unter dem RateID 1 ist das erste Ergebnis vertica zeigt ly, um die dynamische Anzahl der RangeSetIDs

RateID RangeID 
------------------ 
    1   1 
    1   5 
    1   11 
    1   17 
    2   1 
    2   5 
    2   11 
    2   18 

zu berücksichtigen. Dies sollte zu 11.000 Zeilen (ca.) führen. Ich habe versucht, CROSS JOIN usw., aber ich kann das überhaupt nicht funktionieren.

Irgendwelche Genies da draußen bitte?

Dank

+2

Es würde helfen, wenn Sie erklären, wie Sie bekam '1 5 11 17' –

+0

die Zahl ** n ** - Anzahl der Spalten in Ergebnismenge ist gleich Anzahl der unterschiedlichen 'RangeSetID', so dass die allgemeine Idee sein sollte: get ** n ** Alias-Tabellen als' select rangeID aus der Tabelle - group by RangeSetID where row_number = 1 ... n; ', dann cross join ** n ** tables, Holen Sie Spalten in jeder Tabelle zur Ergebnismenge. Problem ist, wie man ** n ** bekommt und dynamisch benutzt. –

+0

Aktualisiert als Bearbeitung. Mein Problem ist die RangeSet sind dynamisch und die Anzahl der RangeIDs in der RangeSet ist auch dynamisch – CR41G14

Antwort

0

Diese Art von Arbeiten, aber es ist viel zu kompliziert und mit einigen Optimierungen tun könnte. Beachten Sie, dass ich Ihre Beispieldaten geändert habe, um Lücken zu schließen, damit dies richtig funktioniert.

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); 
+0

Mächtig langsam mit 99 RangeIDs und 4 RangeSets. Gute Leistung und danke für den Versuch! – CR41G14

+0

Auch die RangeIDs sind möglicherweise nicht genau inkrementell und es kann Lücken geben ... – CR41G14

+0

Ja, ich dachte ursprünglich PIVOT für Geschwindigkeit, aber wie Sie sagten, das war dynamisch, macht es viel schwieriger, etwas zu schreiben, das funktioniert. Ich bekam fast sofort Ergebnisse mit den Beispieldaten, aber ich kann mir vorstellen, dass das alles nicht gut skaliert werden könnte ... Ich könnte ein bisschen mehr damit spielen, um zu sehen, ob ich mit Lücken umgehen kann usw. –

0

Raten Sie, das sollte helfen. Glückliche Kodierung!

;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 
+0

Die Anzahl der Range Set sind dynamisch, also ich don Ich weiß nicht, wie viele Verbindungen es gibt, das ist die Schwierigkeit – CR41G14

+0

Dies ist die Logik Versuchen Sie, dies zu dynamischen Abfrage zu ändern .. – Varun

0

Gleiche Logik in dynamische Abfrage implementiert. Dies sollte für Sie arbeiten, ich denke,

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 '[email protected] + ', '; 

     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); 
Verwandte Themen