Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

Lựa chọn có trọng số ngẫu nhiên trong T-SQL

Câu trả lời của Dane bao gồm một tự tham gia theo cách đưa ra luật bình phương. (n*n/2) các hàng sau phép nối trong đó có n hàng trong bảng.

Điều lý tưởng hơn là có thể chỉ phân tích cú pháp bảng một lần.

DECLARE @id int, @weight_sum int, @weight_point int
DECLARE @table TABLE (id int, weight int)

INSERT INTO @table(id, weight) VALUES(1, 50)
INSERT INTO @table(id, weight) VALUES(2, 25)
INSERT INTO @table(id, weight) VALUES(3, 25)

SELECT @weight_sum = SUM(weight)
FROM @table

SELECT @weight_point = FLOOR(((@weight_sum - 1) * RAND() + 1))

SELECT
    @id = CASE WHEN @weight_point < 0 THEN @id ELSE [table].id END,
    @weight_point = @weight_point - [table].weight
FROM
    @table [table]
ORDER BY
    [table].Weight DESC

Điều này sẽ đi qua bảng, thiết lập @id đến id của mỗi bản ghi giá trị đồng thời giảm @weight điểm. Cuối cùng, @weight_point sẽ chuyển sang tiêu cực. Điều này có nghĩa là SUM của tất cả các trọng số trước đó đều lớn hơn giá trị mục tiêu được chọn ngẫu nhiên. Đây là bản ghi chúng tôi muốn, vì vậy từ thời điểm đó trở đi, chúng tôi đặt @id cho chính nó (bỏ qua bất kỳ ID nào trong bảng).

Thao tác này chỉ chạy qua bảng một lần, nhưng phải chạy qua toàn bộ bảng ngay cả khi giá trị được chọn là bản ghi đầu tiên. Bởi vì vị trí trung bình là một nửa của bảng (và ít hơn nếu được sắp xếp theo trọng số tăng dần) nên việc viết một vòng lặp có thể nhanh hơn ... (Đặc biệt nếu các trọng số nằm trong các nhóm chung):

DECLARE @id int, @weight_sum int, @weight_point int, @next_weight int, @row_count int
DECLARE @table TABLE (id int, weight int)

INSERT INTO @table(id, weight) VALUES(1, 50)
INSERT INTO @table(id, weight) VALUES(2, 25)
INSERT INTO @table(id, weight) VALUES(3, 25)

SELECT @weight_sum = SUM(weight)
FROM @table

SELECT @weight_point = ROUND(((@weight_sum - 1) * RAND() + 1), 0)

SELECT @next_weight = MAX(weight) FROM @table
SELECT @row_count   = COUNT(*)    FROM @table WHERE weight = @next_weight
SET @weight_point = @weight_point - (@next_weight * @row_count)

WHILE (@weight_point > 0)
BEGIN
    SELECT @next_weight = MAX(weight) FROM @table WHERE weight < @next_weight
    SELECT @row_count   = COUNT(*)    FROM @table WHERE weight = @next_weight
    SET @weight_point = @weight_point - (@next_weight * @row_count)
END

-- # Once the @weight_point is less than 0, we know that the randomly chosen record
-- # is in the group of records WHERE [table].weight = @next_weight

SELECT @row_count = FLOOR(((@row_count - 1) * RAND() + 1))

SELECT
    @id = CASE WHEN @row_count < 0 THEN @id ELSE [table].id END,
    @row_count = @row_count - 1
FROM
    @table [table]
WHERE
    [table].weight = @next_weight
ORDER BY
    [table].Weight DESC


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Quyền truy vấn dbo.sysobjects

  2. CHÈN SỐ LƯỢNG LỚN SQL Server từ Linux

  3. Sử dụng trình kích hoạt để mô phỏng cột nhận dạng thứ hai trong SQL Server 2005

  4. Tạo tên bảng là các từ / từ khóa dành riêng trong MS SQL Server

  5. Cách tắt tất cả các trình kích hoạt trong cơ sở dữ liệu SQL Server