Gibt es eine Möglichkeit, jede Zeile von Tabelle A mit einer Zeile der kleineren Tabelle B zu verbinden, indem Sie Tabelle B wiederholen, wie oft dies erforderlich ist?


8

Entschuldigung für den verwirrenden Titel, ich war mir nicht sicher, was ich dort schreiben sollte.

Ich habe eine Tabelle mit ein paar hundert Aufzeichnungen. Ich muss jeden Datensatz dieser Tabelle einer viel kleineren dynamischen Benutzertabelle zuweisen, und die Benutzer sollten abwechseln, welche Datensätze ihnen zugewiesen werden.

Zum Beispiel, wenn TableA ist

Row_Number () Id
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 10

und Tabelle B ist

Row_Number () Id
1 1
2 2
3 3

Ich brauche eine Endergebnismenge

UserId RecordId
1 1
2 2
3 3
1 4
2 5
3 6
1 7
2 8
3 9
1 10

Ich habe es geschafft, mit dem Mod-Operator etwas chaotisch zu machen, aber ich war neugierig, ob dieselbe Abfrage ohne die temporäre Tabelle und die Variable ausgeführt werden kann.

Die temporäre Tabelle wird verwendet, da TableA tatsächlich eine benutzerdefinierte Funktion ist, die eine durch Kommas getrennte Zeichenfolge in eine Tabelle konvertiert, und ich die Anzahl der Objekte aus der UDF benötige.

-- Converts a comma-delimited string into a table
SELECT Num as [UserId], Row_Number() OVER (ORDER BY (SELECT 1)) as [RowNo]
INTO #tmpTest
FROM dbo.StringToNumSet('2,3,1', ',') 

DECLARE @test int
SELECT @test = Count(*) FROM #tmpTest

SELECT *
FROM #tmpTest as T1
INNER JOIN (
    SELECT Top 10 Id, Row_Number() OVER (ORDER BY SomeDateTime) as [RowNo]
    FROM TableA WITH (NOLOCK)
) as T2 ON T1.RowNo = (T2.RowNo % @test) + 1

Es ist wichtig, dass sich auch die UserIds abwechseln. Ich kann Benutzer1 nicht das oberste Drittel der Datensätze, Benutzer2 das zweite Drittel der Datensätze und Benutzer3 das dritte Drittel der Datensätze zuweisen.

Außerdem müssen die Benutzer-IDs die Reihenfolge beibehalten, in der sie ursprünglich eingegeben wurden, weshalb ich eine Row_Number() OVER (ORDER BY (SELECT 1))in der Benutzertabelle habe

Gibt es eine Möglichkeit, diese Tabellen in einer einzigen Abfrage zu verknüpfen, sodass ich keine temporäre Tabelle und Variable verwenden muss?

Ich verwende SQL Server 2005

Antworten:


12

Eine andere Möglichkeit, temporäre Tabellen zu vermeiden, wäre folgende:

;WITH tmpTest AS
(
    SELECT  Num as [UserId]
            , Row_Number() OVER (ORDER BY (SELECT 1)) as [RowNo]
            , COUNT(*) OVER() AS Quant
    FROM dbo.StringToNumSet('2,3,1', ',') 
)
SELECT *
FROM tmpTest as T1
INNER JOIN 
    (
        SELECT Top 10 Id
            , Row_Number() OVER (ORDER BY SomeDateTime) as [RowNo]
        FROM TableA WITH (NOLOCK)
    ) as T2 ON T1.RowNo = (T2.RowNo % Quant) + 1;

Ahhh Ich wusste nicht , ich konnte Count(*)mit OVER()einer Rekordzahl zu erhalten , ohne tatsächlich die Datensätze gruppieren. Dies ermöglicht mir, sowohl die temporäre Tabelle als auch die Variable loszuwerden, danke :)
Rachel

6

Ja, Sie können dies ohne temporäre Tabellen tun:

with w as (select usr_id, row_number() over (order by usr_id) as usr_ordinal from usr)
select record_id, ( select usr_id
                    from w
                    where usr_ordinal=1+(record_ordinal%(select count(*) from w))
                  ) as usr_id
from ( select record_id, row_number() over (order by record_id) as record_ordinal 
       from record ) as z;

Sehen Sie hier für eine Demo SQLFiddle


Während dies die temporäre Tabelle und Variable loswird, mag ich nicht die Tatsache, dass Sie eine Unterabfrage für jeden Datensatz ausführen müssen :)
Rachel

4
@Rachel Nur weil es so deklariert ist, heißt das nicht, dass es so ausgeführt wird.
Aaron Bertrand

@AaronBertrand Das stimmt, aber ich mag es nicht, dem SQL-Compiler zu vertrauen, um einen guten Ausführungsplan für mich zu ermitteln, mehr als ich muss. Es hat mir in der Vergangenheit Probleme bereitet :)
Rachel
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.