#title 작업 할당 최적화 문제 [[TableOfContents] 커뮤니티에 아래와 같은 [http://www.sqler.com/bSQLQA/842640 질문]이 올라왔다. 재미있을 것 같아 해봤다. ==== 문제 ==== {{{ 오더번호 규격 오더길이 만들개수 작업자 E 1 50 7 D 3 80 6 B 1 30 1 F 3 100 15 A 2 100 10 C 1 40 4 위의 자료를 가지고 작업자(홍길동,강감찬....)를 배정 할려고 합니다. 배정하는 원칙은 첫번째, 작업자별로 오더의 길이의 합이 비슷하도록 하여 나누어야 하며, 두번째, 작업난이도를 분류하여 작업자별로 비슷하게 배분되어야 합니다. 해당 오더의 작업난이도는 1. 규격(1~3 / 클수록 작업이 어려움) 2. 오더길이/만들개수 = 제품의길이 (제품의 길이가 짧을수록 작업이 어려움) 위 두가지를 고려합니다. 규격에 따른 작업 난이도는 1~3까지 정해져 있고, 제품의 길이는 오더길이와 만들개수로 정해집니다. 설명이 제대로 전달되었는지 모르겠네요.. 물론 최종적 디테일한 부분은 응용프로그램으로 구현이 되겠지만 최적화된 기본 쿼리가 언뜻 생각이 나지 않네요 고수분들의 조언을 구해 봅니다. }}} ==== 솔루션 ==== 최적화 문제다. 유사도 개념을 이용하여 시뮬레이션 하면 쉽게 최적화 할 수 있다. {{{ --데이터 만들기 ;with temp(오더번호, 규격, 오더길이, 만들개수) as ( select 'A', 2, 100, 10 union all select 'B', 1, 30 , 1 union all select 'C', 1, 40 , 4 union all select 'D', 3, 80 , 6 union all select 'E', 1, 50 , 7 union all select 'F', 3, 100, 15 ) select * into #temp from temp select N'홍길동' name into #worker union all select N'강감찬' union all select N'이순신' --simulation --similarity, euclidean distance set nocount on if object_id('tempdb.dbo.#result') is not null drop table #result create table #result( 오더번호 nvarchar(200) , 규격 int , 오더길이 int , 만들개수 int , 작업자 nvarchar(200) ) declare @i int , @dist float , @min_dist float set @i = 1 while(@i <= 100) begin if object_id('tempdb.dbo.#rand') is not null drop table #rand select a.오더번호 , a.규격 , a.오더길이 , a.만들개수 , b.작업자 , b.num into #rand from (select *, row_number() over(order by newid()) - 1 num from #temp) a inner join ( select name 작업자 , row_number() over(order by newid()) - 1 num , count(*) over() cnt from #worker ) b on a.num % b.cnt = b.num declare @v1 float , @v2 float , @v3 float select @v1 = sum(규격) , @v2 = sum(오더길이) , @v3 = sum(만들개수) from #rand where num = 0 select @dist = sqrt(sum(n)) from ( select power(@v1 - sum(규격), 2) + power(@v2 - sum(오더길이), 2) + power(@v3 - sum(만들개수), 2) n from #rand where num <> 0 group by num ) t if @i = 1 begin insert #result select 오더번호 , 규격 , 오더길이 , 만들개수 , 작업자 from #rand set @min_dist = @dist end else begin if @min_dist > @dist begin truncate table #result insert #result select 오더번호 , 규격 , 오더길이 , 만들개수 , 작업자 from #rand set @min_dist = @dist end end --print @i set @i = @i + 1 end print @min_dist select 오더번호 , 규격 , 오더길이 * 1.0 / 만들개수 [오더길이/만들개수] , 작업자 from #result order by 작업자 }}} 결과 {{{ 오더번호 규격 오더길이/만들개수 작업자 E 1 7.142857142857 강감찬 D 3 13.333333333333 강감찬 A 2 10.000000000000 이순신 C 1 10.000000000000 이순신 B 1 30.000000000000 홍길동 F 3 6.666666666666 홍길동 }}}