Có cách nào để nối từng hàng của TableA với một hàng của TableB nhỏ hơn bằng cách lặp lại TableB tuy nhiên cần nhiều lần không?


8

Xin lỗi vì tiêu đề khó hiểu, tôi không chắc nên viết gì ở đó.

Tôi có một bảng vài trăm hồ sơ. Tôi cần gán từng bản ghi của bảng này cho một bảng người dùng động nhỏ hơn nhiều và người dùng nên thay thế cho bản ghi nào họ được chỉ định.

Ví dụ: nếu TableA là

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

và TableB là

Row_Number () Id
1 1
2 2
3 3

Tôi cần một tập kết quả cuối cùng

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

Tôi đã quản lý để làm một cái gì đó hơi lộn xộn bằng cách sử dụng toán tử mod, nhưng tôi tò mò liệu cùng một truy vấn này có thể được chạy mà không có bảng tạm thời và biến.

Bảng tạm thời được sử dụng vì TableA thực sự là Hàm do người dùng xác định để chuyển đổi một chuỗi được phân tách bằng dấu phẩy thành bảng và tôi cần Đếm các đối tượng từ 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

Điều quan trọng là UserIds cũng thay thế. Tôi không thể chỉ định 1/3 bản ghi trên cùng cho Người dùng1, 1/3 bản ghi thứ hai cho Người dùng2 và 1/3 của bản ghi cho Người dùng3.

Ngoài ra, UserIds cần duy trì thứ tự mà chúng được nhập vào ban đầu, đó là lý do tại sao tôi có một bảng Row_Number() OVER (ORDER BY (SELECT 1))trong Người dùng

Có cách nào để nối các bảng này trong một truy vấn không nên tôi sẽ không cần sử dụng bảng tạm thời và biến?

Tôi đang sử dụng SQL Server 2005

Câu trả lời:


12

Một cách khác để tránh các bảng tạm thời sẽ là:

;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 tôi đã không nhận ra tôi có thể sử dụng Count(*)với OVER()để có được một số kỷ lục mà không thực sự nhóm các hồ sơ. Điều này cho phép tôi thoát khỏi cả bảng tạm thời và biến, cảm ơn bạn :)
Rachel

6

Có, bạn có thể làm điều này mà không cần bất kỳ bảng tạm thời nào:

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;

Xem ở đây để xem bản demo SQLFiddle


Mặc dù điều này không thoát khỏi bảng tạm thời và biến, tôi không thích thực tế là bạn cần chạy truy vấn phụ cho mỗi bản ghi :)
Rachel

4
@Rachel chỉ vì đó là cách nó được tuyên bố không có nghĩa đó là cách nó được thực thi.
Aaron Bertrand

@AaronBertrand Điều đó đúng, nhưng không thích tin tưởng trình biên dịch SQL để xác định kế hoạch thực hiện tốt cho tôi nhiều hơn tôi phải làm. Nó đã gây ra vấn đề cho tôi trong quá khứ :)
Rachel
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.