T-SQL | "Round Robin" | Пример реализации

Если интересно также: Пример приложения MS Access, решающего аналогичную задачу

 

 


Пример выполен на базе данных AdventureWorks (см. Примеры БД MS SQL Server)

 

Пример равномерного (карусельного) распределения клиентов по менеджерам (/задач по исполнителям)

 

Тест реализации на семи клиентах:

(каждый запуск даёт стабильный равномерный результат)

 

Реализация равномерности с помощью запроса выдать менеджера по самой ранней дате ModifiedDate, где ModifiedDate -- дата и время назначения менеджеру очередного клиента (точность хранения времени одна сотая секунды)

 

 SELECT TOP 1 @Result = SalesPersonId FROM Sales.SalesPerson

 WHERE TerritoryID = @TerritoryID

 ORDER BY ModifiedDate

 

[ModifiedDate] по каждому назначенному менеджеру помечается новым системным CURRENT_TIMESTAMP, при этом вызов WAITFOR DELAY обеспечивает её уникальность

 


Описание задачи:

 

USE AdventureWorks

GO

--есть список клиентов и территорий

SELECT CustomerID, TerritoryID FROM [Sales].[Customer]

--для наглядности берём одну территоррию и несколько каких-то клиентов:

WHERE TerritoryID = 4 AND CustomerID IN (3, 4, 5, 6, 21, 23, 24, 25)

 

 

--есть список менеджеров и территорий

SELECT TerritoryID, SalesPersonID FROM [Sales].[SalesPerson]

WHERE TerritoryID = 4

 

 

--Задача по каждой территории распределить клиентов между менеджерами

--на каждого CustomerID выбрать одного SalesPersonID, который работает на той же территории

--распределение должно быть равномерным

 

--РЕШЕНИЕ:

 


USE [AdventureWorks]

GO

CREATE PROCEDURE [dbo].[TestTerritorySalesPersonRoundRobin] --курсором бежит по клиентам и этому клиенту назначает менеджера

AS

BEGIN

 -- SET NOCOUNT ON added to prevent extra result sets from

 -- interfering with SELECT statements.

 SET NOCOUNT ON;

 

print 'CustomerID|TerritoryID|SalesPersonID'

 

declare @CustomerID int

declare @TerritoryID int

 

DECLARE ids_cursor CURSOR FOR

SELECT CustomerID, TerritoryID FROM Sales.Customer

 

OPEN ids_cursor

-- выполнить первое считывание и сохранить указанные значения (выполненного Select запроса)

-- FETCH - достать

FETCH NEXT FROM ids_cursor

-- переменные должны идти в том же порядке, в котором идут клонки Select запроса

INTO @CustomerID, @TerritoryID

-- проверить, считалась ли запись: если результат считывания успешный, обработать полученные данные

WHILE @@FETCH_STATUS = 0

BEGIN

DECLARE @SalesPersonID int

select @SalesPersonID = dbo.GetSalesPersonID(@TerritoryID) --GetSalesPersonID находит человека по территории

print cast(@CustomerID as varchar) + '|' + cast(@TerritoryID as varchar) + '|' + cast(@SalesPersonID as varchar)

execute dbo.TouchSalesPerson @SalesPersonID --TouchSalesPerson помечает менеджера как недавно назначенного

-- продолжить пока есть записи в рекордсете

FETCH NEXT FROM ids_cursor

INTO @CustomerID, @TerritoryID

END

 

-- закрыть рекордсет, освободить ресурсы на сервере

CLOSE ids_cursor

DEALLOCATE ids_cursor

 

END

 


 

USE [AdventureWorks]

GO

CREATE FUNCTION [dbo].[GetSalesPersonID](@TerritoryID as Int)

RETURNS int

AS

BEGIN

 -- Declare the return variable here

 DECLARE @Result int

 

 -- Add the T-SQL statements to compute the return value here

 SELECT top 1 @Result = SalesPersonId from Sales.SalesPerson

 where TerritoryID = @TerritoryID

 order by ModifiedDate

 

 -- Return the result of the function

 RETURN @Result

 

END

 


USE [AdventureWorks]

GO

CREATE PROCEDURE [dbo].[TouchSalesPerson](@SalesPersonID as Int)

AS

BEGIN

 -- SET NOCOUNT ON added to prevent extra result sets from

 -- interfering with SELECT statements.

 SET NOCOUNT ON;

 

 WAITFOR DELAY '00:00:00:002' -- обеспечивает уникальность ModifiedDate (на большой скорости получались одни и те же значения, а это не то, что нужно)

 

 update Sales.SalesPerson set ModifiedDate = CURRENT_TIMESTAMP

 where SalesPersonID = @SalesPersonID

END

 


 

Запуск по всем клиентам:

 

USE [AdventureWorks]

GO

execute TestTerritorySalesPersonRoundRobin

 

Результат: 1 минута 47 секунд для 19 185 записей

 

Распределено супер-равномерно:

(сводка результата в Excel)

 



© 2018 | Анна Петросян | pashelp@yandex.ru