Есть ли способ присоединить каждую строку TableA к строке меньшего TableB, повторяя TableB, сколько бы раз это ни понадобилось?

8

Извините за запутанный заголовок, я не был уверен, что там написать.

У меня есть таблица из нескольких сотен записей. Мне нужно назначить каждую запись этой таблицы гораздо меньшей динамической таблице пользователей, и пользователи должны чередовать, какие записи им назначаются.

Например, если TableA

Идентификатор Row_Number ()
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 10

и таблица B

Идентификатор Row_Number ()
1 1
2 2
3 3

Мне нужен набор конечных результатов, который

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

Мне удалось сделать что-то немного беспорядочно, используя оператор mod, но мне было любопытно, можно ли выполнить этот же запрос без временной таблицы и переменной.

Временная таблица используется потому, что TableA на самом деле является определяемой пользователем функцией, которая преобразует строку с разделителями-запятыми в таблицу, и мне нужно количество объектов из UDF.

-- 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

Важно, чтобы идентификаторы пользователей тоже чередовались. Я не могу назначить верхнюю 1/3 записей для User1, вторую 1/3 записей для User2 и третью 1/3 записей для User3.

Кроме того, UserIds должны поддерживать порядок, в котором они были первоначально введены, поэтому у меня есть Row_Number() OVER (ORDER BY (SELECT 1))в таблице пользователя

Есть ли способ объединения этих таблиц в одном запросе, поэтому мне не нужно использовать временную таблицу и переменную?

Я использую SQL Server 2005

Рейчел
источник

Ответы:

12

Другой способ избежать временных таблиц был бы следующим:

;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;
Lamak
источник
Ааа , я не понимаю , что я мог бы использовать Count(*)с , OVER()чтобы получить количество записей без фактических группировок записей. Это позволяет мне избавиться как от временной таблицы, так и от переменной, спасибо :)
Rachel
6

Да, вы можете сделать это без каких-либо временных таблиц:

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;

Смотрите здесь для демонстрации SQLFiddle

Джек говорит, попробуйте topanswers.xyz
источник
Хотя это избавляет от временной таблицы и переменных, мне не нравится тот факт, что вам нужно запускать подзапрос для каждой записи :)
Rachel
4
@ Рейчел только потому, что так заявлено, не значит, что так оно и выполняется.
Аарон Бертран
@AaronBertrand Это правда, но мне не нравится доверять компилятору SQL определять хороший план выполнения для меня больше, чем нужно. В прошлом это вызывало у меня проблемы :)
Рэйчел