2010-08-01 8 views
2

두 개의 int 열이있는 테이블이 있으며, 이들의 조합은 고유합니다. 내가 원하는 무엇SQL에서 n- 튜플을 계산하십시오.

ids idk 
--------- 
1 2 
1 3 
1 4 

2 2 
2 3 
2 4 

3 2 
3 5 
3 4 

4 2 
4 3 

적어도 2 IDS에 공통 idks의 가장 큰 세트를 얻는 것입니다. 여기

결과는 다음과 같아야합니다

보시다시피
(2,3,4) - 2x 
(2,4) - 3x 
(2,3) - 3x 
(3,4) - 2x 
(2,5) - 1x 

는, 일반적인 idks의 수는 가장 중요한 일이다. 숫자가 같으면 # (2,4) = # (2,5) 기준은 발생 횟수입니다.

나를 프로그래밍하는 데 필요한 알고리즘처럼 보이지만 잘못되었거나 SQL이 가능합니다.

+0

Vitalii은 - 당신이 IDK 값의 최대 #을 의미합니까? 예를 들어, 그가 2 idks의 일반적인 세트의 수를 찾고 있다면, 이것은 비교적 쉬울 것입니다. 일반적인 idk 2 개 또는 3 개를 찾는다면 여전히 가능합니다 (그러나 더 큰 데이터 세트 및 직선 SQL에서는 메모리 집약적입니다). – Andrew

+0

이것은 프로그래밍 언어를 통한 사소한 문제이지만, 대부분의 데이터베이스에서 스트레이트 SQL에 대한 하드 (비효율적 인) 문제입니다 (제한되지 않은 idk 가정). SQL 만 사용할 수있는 경우 DBMS 내의 내장 프로 시저 논리를 활용하여 일부/모든 논리를 수행하는 것을 고려하십시오. – Andrew

+1

그렇게하지 않겠습니다. 그것은 세트의 이론을 전문으로하는 일부 수학자가 대답 할 수있는 문제의 종류입니다. 나는 조합을 "평평하게"하려고 노력할 것입니다. 그러나 이들이 정수이기 때문에 조합 수는 모든 SQL에 비해 너무 큽니다. idks가 특정 범위 (예 : 1-9)에 있으면 나는 그 일을 할 수있는 SELECT 문을 쓰는 재미만을 위해서입니다. – hol

답변

2

흥미로운 질문입니다! SQL Server에서이 문제를 해결할 방법을 찾은 것 같습니다. 그럼에도 불구하고 오히려 복잡 :

  • 이었다 각 조합에 대해 1 씩 각 ids
  • Increate의 occurance을 조합 목록을 만들 조합에게
  • 전화 저장 프로 시저를 계산하는 저장 프로 시저를 만들기 이전에
  • 발견 결과 테이블에
  • 삽입 새로운 조합

여기에 전체 코드는 다음과 같습니다

귀하의 예제 데이터 세트에 대한
set nocount on 

-- Helper table for sp_Combinations 
if OBJECT_ID('tempdb..#combos') is not null 
    drop table #combos 
create table #combos (
    comboid int default 1, 
    basecomboid int, 
    combosize int default 1, 
    val int, 
    primary key (comboid, val)) 


if OBJECT_ID('dbo.sp_Combinations') is null 
    exec ('create procedure dbo.sp_Combinations as select 1') 
go 
-- Creates a list of all combinations of values in #combos, 
-- based on a starting list with comboid = 1 
alter procedure dbo.sp_Combinations 
as begin 
    delete from #combos where comboid <> 1 

    declare @n int 
    select @n = count(*) from #combos 

    update #combos set combosize = (select count(*) from #combos) 

    if @n = 1 
     return 

    -- Add individual numbers 
    insert #combos 
      (comboid, basecomboid, val) 
    select row_number() over (order by val) + 1 
    ,  1 
    ,  val 
    from #combos 
    where comboid = 1 

    declare @k int 
    set @k = 1 
    while @k + 1 < @n 
     begin 
     declare @max_combo_id int 
     select @max_combo_id = max(comboid) from #combos 

     -- Add one new member to each combination of size @k 
     -- The new member must be larger than all existing members 
     -- F.e. for @n = 4 and @k = 1: 
     --  (1) --> (1,2) (1,3) (1,4) 
     --  (2) --> (2,3) (2,4) 
     --  (3) --> (3,4) 
     --  (4) --> no new combinations 
     ;with b as (
      select val 
      from #combos 
      where comboid = 1 
     ), g as (
      select comboid 
      ,  max(val) as maxval 
      from #combos c 
      where combosize = @k 
      group by 
        comboid 
     ) 
     insert #combos (comboid, basecomboid, combosize, val) 
     select row_number() over (order by g.comboid) + @max_combo_id 
     ,  g.comboid 
     ,  @k + 1 
     ,  b.val 
     from b 
     join g 
     on  b.val > g.maxval 

     -- Add the members of the base combo 
     insert #combos (comboid, basecomboid, combosize, val) 
     select l.comboid 
     ,  l.basecomboid 
     ,  l.combosize 
     ,  b.val 
     from #combos l 
     join #combos b 
     on  b.comboid = l.basecomboid 
     where l.combosize = @k + 1 

     set @k = @k + 1 
     end 
end 
go 
go 

-- Input table 
declare @t table (ids int, idk int) 
insert into @t (ids, idk) values 
    (1, 2), (1, 3), (1, 4), 
    (2, 2), (2, 3), (2, 4), 
    (3, 2), (3, 5), (3, 4), 
    (4, 2), (4, 3); 

-- Valid combinations with number of occurrences 
declare @combinations table (comboid int, val int, cnt int) 

-- Iterate over all ids  
declare cur cursor for select distinct ids from @t 
open cur 
declare @ids int 
while 1=1 
    begin 
    fetch from cur into @ids 
    if @@FETCH_STATUS <> 0 
     break 

    -- Calculate combinations for this ids 
    truncate table #combos 
    insert into #combos (comboid, val) select 1, idk from @t where ids = @ids 
    exec dbo.sp_Combinations 

    -- Increase count of existing combinations 
    update u 
    set  cnt = cnt + 1 
    from @combinations u 
    where exists 
      (
      select * 
      from @combinations a 
      full join 
        #combos b 
      on  a.val = b.val 
      where a.comboid = u.comboid 
      group by 
        a.comboid 
      having max(case when a.val is null then 1 else 0 end) = 0 
        and max(case when b.val is null then 1 else 0 end) = 0 
      ) 

    -- Insert new combinations 
    declare @max_combo_id int 
    select @max_combo_id = isnull(max(comboid),0) from @combinations 

    insert @combinations 
      (comboid, val, cnt) 
    select n.comboid + @max_combo_id 
    ,  n.val 
    ,  1 
    from #combos n 
    where not exists 
      (
      select * 
      from @combinations a 
      full join 
        #combos b 
      on  a.val = b.val 
      where b.comboid = n.comboid 
      group by 
        b.comboid 
      having max(case when a.val is null then 1 else 0 end) = 0 
        and max(case when b.val is null then 1 else 0 end) = 0 
      ) 
    end 

close cur 
deallocate cur 

-- Display result 
select x.r as combination 
,  cnt as occurrences 
from (
     select distinct comboid 
     ,  cnt 
     from @combinations 
     ) a 
cross apply 
     (
     select val as [text()] 
     from @combinations c 
     where c.comboid = a.comboid 
     for xml path('') 
     ) x(r) 
where a.cnt > 1 
order by 
     len(x.r) desc 
,  cnt desc 

이 인쇄 :

combination occurrences 
234   2 
23   3 
24   3 
34   2 
2   4 
3   3 
4   3 
관련 문제