views:

306

answers:

3

Can someone please let me know how to get the different segments of the three rows that are intersecting in different ways using SQL? The three rows in #t2 represent sets A,B, C - I am looking for A I B, A I C, B I C, A I B I C, A' , B', C' etc., (7 possible segments with 3 rows as in a Venn diagram) where I is the Intersection.

I am looking for a generic solution which can handle n number of rows in #t2.

-- SQL Code Begin
create table #t1 (key1 int, key2 int) -- for each Key1 there can be 1 or more Key2
go
create table #t2 (row_id int identity(101, 1), key1 int) --row_id is the primary key
go 

insert into #t1
select 1, 11 union select 1, 12 union select 1, 13 union select 1, 14 union 
select 2, 13 union select 2, 15 union select 2, 16 union select 2, 17 union 
select 3, 13 union select 3, 12 union select 3, 16 union select 3, 17

-- 1 --> 11, 12, 13, 14
-- 2 --> 13, 15, 16, 17
-- 3 --> 13, 12, 16, 17

insert into #t2 (key1)
select 1 union select 2 union select 3

-- SQL Code End

The output I am looking for is,

1001  11 (A')
1001  14 (A')
1002  12 (A I C - A I B I C)
1003  13 (A I B I C)
1004  15 (B')
1005  16 (B I C - A I B I C)
1005  17 (B I C - A I B I C)

The output has 5 segments, instead of the possible 7 as two of them are NULL.

A: 

How about this?

SELECT key2,
  CASE
  WHEN InA = 1 and InB = 1 and InC = 1 THEN 'ABC'
  WHEN InA = 0 and InB = 1 and InC = 1 THEN 'BC'
  WHEN InA = 1 and InB = 0 and InC = 1 THEN 'AC'
  WHEN InA = 1 and InB = 1 and InC = 0 THEN 'AB'
  WHEN InA = 1 and InB = 0 and InC = 0 THEN 'A'
  WHEN InA = 0 and InB = 1 and InC = 0 THEN 'B'
  WHEN InA = 0 and InB = 0 and InC = 1 THEN 'C'
  ELSE 'I''m broke'
  END as [SubSet]
FROM

(
SELECT key2,
  MAX(CASE WHEN key1 = 1 THEN 1 ELSE 0 END) as InA,
  MAX(CASE WHEN key1 = 2 THEN 1 ELSE 0 END) as InB,
  MAX(CASE WHEN key1 = 3 THEN 1 ELSE 0 END) as InC
FROM #t1
WHERE key1 in (1, 2, 3)
GROUP BY key2
) sub

ORDER BY key2
David B
Thanks. It works for 3 values. But, I am actually looking for a solution that can handle any larger value for n (say, 100, 1000 etc.,). Of course, all combinations won't exist and the result will be like a sparse matrix, but the query needs to handle where the combination is not NULL.
A: 

If you can popluate the table 2 as 1, Key1-Value 1 2, Key1-Value 2 4, Key1-Value 3 like wise if you have more key1's then the identity column as you have, should be populated as a binary tree. so that the values in t2 would be 1 , 1 2, 2 4, 3 Then you need to do a select select sum(identity), key2 from t1, t2 where t1.key1 = t2.key1 groupby key2

the output you will get will be 1 11 5 12 7 13 1 14 2 15 6 16 6 17

you can see that 1,2,4 will be A',B',C' 2 will be A|B , 7 will be A|B|C and likewise

Dheer
I understand you suggest making #t2 as insert into #t2 values (1, 1), (2, 2), (4,3) where 1,2 and 4 are the generated values (2^n).However, I am not sure about the part "if you have more key1's then the identity column ...binary tree ... 1, 1 2, 2 4, 3.". Please explain with an example.
Also, if #t2 has 1000 rows, we we are taking about 2 ^ 1000. Do you have any better suggestion? Thanks.
Dheer
There is no significance to the numbers 1001, 1002, etc. They are just identity values starting from 1001. I just gave them to distingush them from the Keys values 1,2,3, 101, 102 etc., in the example. It could be any number. But, having 2 ^ n won't work for 1000s of rows. Thanks.
Just to clarify, the identity values 1001 should be same for all A' ?
Dheer
Yes. It is done to identify all the elements of A' easily.
+2  A: 

If I have understood the problem correctly, I think you may have to resort to using a loop to cope with 'n' number of rows

DECLARE @Key2 INT
DECLARE @Subset VARCHAR(1000)
DECLARE @tblResults TABLE
(
    Key2 INT,
    Subset VARCHAR(1000)
)

SET @Subset = ''
SELECT @Key2 = MIN(Key2) FROM #t1

WHILE @Key2 IS NOT NULL
BEGIN
    SELECT @Subset = @Subset + CAST(Key1 AS VARCHAR(10))
    FROM #t1
    WHERE Key2 = @Key2

    INSERT INTO @tblResults (Key2, Subset)
    VALUES (@Key2, @Subset)

    SET @Subset = ''
    SELECT @Key2 = MIN(Key2) FROM #t1 WHERE Key2 > @Key2
END

SELECT * FROM @tblResults
Tim C
Thanks. It seems to do the trick. I was trying to avoid the loop which I am not sure is possible. Thanks again.