2016-10-30 22 views
7

Hãy nói rằng tôi có một bảng đơn giản của văn bản với một cột loại:Zip/lặp lại tham gia?

Documents 
Id Type 
1 A 
2 A 
3 B 
4 C 
5 C 
6 A 
7 A 
8 A 
9 B 
10 C 

Người dùng có quyền truy cập vào các loại tài liệu khác nhau:

Permissions 
Type User 
A  John 
A  Jane 
B  Sarah 
C  Peter 
C  John 
C  Mark 

Và tôi cần phải phân phối các tài liệu giữa các người dùng làm công việc:

Tasks 
Id T DocId UserId 
1 A 1 John 
2 A 2 Jane 
3 B 3 Sarah 
4 C 4 Peter 
5 C 5 John 
6 A 6 John 
7 A 7 Jane 
8 A 8 John 
9 B 9 Sarah 
10 C 10 Mark 

Làm cách nào để làm điều đó? Làm thế nào để tôi có được các nhiệm vụ?

+0

Đó là một câu hỏi hay –

+1

Sau khi đọc câu hỏi của bạn, và @Prdp bình luận, Khi bạn nói - phân phối tài liệu - Bạn có nghĩa là phân phối đồng đều không? i, e, phân phối tải công việc? –

Trả lời

2

Bạn có thể liệt kê các hàng và sau đó sử dụng số học modulo cho phù hợp:

with d as (
     select d.*, 
      row_number() over (partition by type order by newid()) as seqnum, 
      count(*) over (partition by type) as cnt 
     from documents d 
    ), 
     u as (
     select u.*, 
       row_number() over (partition by type order by newid()) as seqnum, 
       count(*) over (partition by type) as cnt 
     from users u 
    ) 
select d.* 
from d join 
    u 
    on d.type = u.type and 
     u.seqnum = (d.seqnum % u.cnt) + 1 
0

Great câu hỏi.

  • Giải pháp này trả về tất cả các bản phân phối có thể, sắp xếp theo ưu tiên được xác định bởi các thông tin như số người sử dụng tham gia, tài liệu tối thiểu cho mỗi người dùng, độ lệch chuẩn của nhiệm vụ cho mỗi người dùng, vv
  • Tôi không tính vào document.id là một chuỗi các số bắt đầu bằng 1, do đó việc sử dụng dense_rank.
  • Cốt lõi của các giải pháp là CTE lặp lại tạo ra các bộ bản ghi của tất cả các bản phân phối có thể có. Hiện
  • Thực hiện trên máy tính xách tay của tôi là khoảng 20 giây, (phần lặp đi lặp lại mất 5 giây)

with  doc_user as 
      (
       select   d."id"           as docid 
           ,p."user"          as userid 
           ,dense_rank () over (order by  d."id")  as doc_seq 

       from    documents  d 

         left join permissions  p 

         on   p.type = d.type 
      ) 

      ,it_cte as 
      (
       select  docid 
          ,userid 
          ,doc_seq 
          ,cast (coalesce(userid,'') as varchar(max)) as path 
          ,'A'           as cte_part 

       from  doc_user  

       where  doc_seq = 1 


       union all 

       select  r.docid 
          ,r.userid 
          ,du.doc_seq 
          ,r.path + ',' + coalesce (du.userid,'') 
          ,'B' 


       from     it_cte  as r 

          cross join doc_user as du 

       where  du.doc_seq = r.doc_seq + 1 


       union all 

       select  du.docid 
          ,du.userid 
          ,du.doc_seq 
          ,r.path + ',' + coalesce (du.userid,'') 
          ,'C' 


       from     it_cte  as r 

          cross join doc_user as du 

       where  du.doc_seq = r.doc_seq + 1 
         and r.cte_part in ('A','C') 
      ) 

      ,result_sets as 
      (
       select  dense_rank () over (order by path) as set_id 
          ,docid 
          ,userid 

       from  it_cte 

       where  doc_seq = (select count(*) from documents) 
      ) 

      ,result_sets_stat as 
      (
       select  set_id 
          ,count (distinct userid) as users_involved 

       from  result_sets 

       group by set_id 
      ) 

      ,result_sets_users_stat as 
      (
       select  set_id 
          ,min  (doc) min_doc_per_user 
          ,stdevp (doc) stdevp_doc_per_user 

       from  (select  set_id 
             ,userid 
             ,count (*) as doc 

          from  result_sets 

          group by set_id 
             ,userid 
          ) t 

       group by set_id 
      ) 

select  s.set_priority 
      ,r.docid 
      ,r.userid 
      ,s.users_involved   
      ,s.min_doc_per_user    
      ,s.stdevp_doc_per_user  

from     (select  s.set_id 
            ,s.users_involved   
            ,u.min_doc_per_user    
            ,u.stdevp_doc_per_user 

            ,row_number() over  
            (
             order by s.users_involved  desc 
                ,u.min_doc_per_user  desc 
                ,u.stdevp_doc_per_user 
                ,s.set_id 

            ) as set_priority 

         from     result_sets_stat  as s 

            join  result_sets_users_stat as u 

            on   u.set_id = 
               s.set_id 
         ) s 

      join  result_sets as r 

      on   r.set_id = 
         s.set_id  

order by s.set_priority 
      ,r.docid 

option  (merge join) 
;