2015-06-16 3 views
0

У меня есть таблица с двумя интересующими колонками, item_id и bucket_id. Есть фиксированное количество значений для bucket_id, и я в порядке с перечислением их, если мне нужно.Расчет перекрытия между группами

Каждый item_id может отображаться несколько раз, но каждое событие будет иметь отдельное значение bucket_id. Например, item_id из 123 может отображаться дважды в таблице, один раз под bucket_id от A, один раз под B.

Моя цель - определить, сколько перекрытий существует между каждой парой значений bucket_id и отображать ее как матрицу N-на-N.

Для примера рассмотрим следующий небольшой пример таблицы:

item_id  bucket_id 
========= =========== 
111   A 
111   B 
111   C 

222   B 
222   D 

333   A 
333   C 

444   C 

Так что для этого набора данных, ведра A и B один item_id в общих, ведра C и D нет товаров общего и т.д.

Я бы хотел, чтобы приведенная выше таблица была отформатирована примерно так:

 A  B  C  D 
=================================== 
A  2  1  2  0 
B  1  2  1  1 
C  2  1  3  0 
D  0  1  0  1 

В приведенной выше таблице пересечение строки и столбца сообщает вам, сколько записей существует в значениях bucket_id. Например, когда строка A пересекает столбец C, у нас есть 2, так как есть 2 записи, которые существуют как в bucket_id A, так и C. Поскольку пересечение X и Y совпадает с пересечением Y и X, приведенное выше таблица отражается по диагонали.

Я предполагаю, что запрос включает PIVOT, но я не могу на всю жизнь понять, как заставить его работать.

+0

Что представляет собой последняя таблица (например, что означает значение 2 для столбца A строки C)? – John

+1

@John - Я добавил немного больше объяснений чуть ниже таблицы. –

+0

Это своего рода показатель. но подключаемый – Ravi

ответ

1

Вы можете использовать простой PIVOT:

SELECT t1.bucket_id, 
     SUM(CASE WHEN t2.bucket_id = 'A' THEN 1 ELSE 0 END) AS A, 
     SUM(CASE WHEN t2.bucket_id = 'B' THEN 1 ELSE 0 END) AS B, 
     SUM(CASE WHEN t2.bucket_id = 'C' THEN 1 ELSE 0 END) AS C, 
     SUM(CASE WHEN t2.bucket_id = 'D' THEN 1 ELSE 0 END) AS D 
FROM table1 t1 
JOIN table1 t2 ON t1.item_id = t2.item_id 
GROUP BY t1.bucket_id 
ORDER BY 1 
; 

или вы можете использовать Oracle пункт PIVOT (работает на 11.2 и выше):

SELECT * FROM (
    SELECT t1.bucket_id AS Y_bid, 
      t2.bucket_id AS x_bid 
    FROM table1 t1 
    JOIN table1 t2 ON t1.item_id = t2.item_id 
) 
PIVOT (
    count(*) FOR x_bid in ('A','B','C','D') 
) 
ORDER BY 1 
; 

Примеры: http://sqlfiddle.com/#!4/39d30/7

0

Я считаю, что это даст вам данные, которые вам нужны. Поворот таблицы может быть выполнен программно (или в Excel и т. Д.).

-- This gets the distinct pairs of buckets 
select distinct 
    a.name, 
    b.name 
from 
    bucket a 
    join bucket b 
where 
    a.name < b.name 
order by 
    a.name, 
    b.name 

+ --------- + --------- + 
| name  | name  | 
+ --------- + --------- + 
| A   | B   | 
| A   | C   | 
| A   | D   | 
| B   | C   | 
| B   | D   | 
| C   | D   | 
+ --------- + --------- + 
6 rows 

-- This gets the distinct pairs of buckets with the counts you are looking for 
select distinct 
    a.name, 
    b.name, 
    count(distinct bi.item_id) 
from 
    bucket a 
    join bucket b 
    left outer join bucket_item ai on ai.bucket_name = a.name 
    left outer join bucket_item bi on bi.bucket_name = b.name and ai.item_id = bi.item_id 
where 
    a.name < b.name 
group by 
    a.name, 
    b.name 
order by 
    a.name, 
    b.name 

+ --------- + --------- + ------------------------------- + 
| name  | name  | count(distinct bi.item_id)  | 
+ --------- + --------- + ------------------------------- + 
| A   | B   | 2        | 
| A   | C   | 1        | 
| A   | D   | 0        | 
| B   | C   | 2        | 
| B   | D   | 0        | 
| C   | D   | 0        | 
+ --------- + --------- + ------------------------------- + 
6 rows 

Вот весь пример с DDL и вставляет его настроить (это в MySQL, но одни и те же идеи применимы и в других местах):

use example; 

drop table if exists bucket; 

drop table if exists item; 

drop table bucket_item; 

create table bucket (
    name varchar(1) 
); 

create table item(
    id int 
); 

create table bucket_item(
    bucket_name varchar(1) references bucket(name), 
    item_id int references item(id) 
); 

insert into bucket values ('A'); 
insert into bucket values ('B'); 
insert into bucket values ('C'); 
insert into bucket values ('D'); 

insert into item values (111); 
insert into item values (222); 
insert into item values (333); 
insert into item values (444); 
insert into item values (555); 

insert into bucket_item values ('A',111); 
insert into bucket_item values ('A',222); 
insert into bucket_item values ('A',333); 
insert into bucket_item values ('B',222); 
insert into bucket_item values ('B',333); 
insert into bucket_item values ('B',444); 
insert into bucket_item values ('C',333); 
insert into bucket_item values ('C',444); 
insert into bucket_item values ('D',555); 


-- query to get distinct pairs of buckets 
select distinct 
    a.name, 
    b.name 
from 
    bucket a 
    join bucket b 
where 
    a.name < b.name 
order by 
    a.name, 
    b.name 
; 

select distinct 
    a.name, 
    b.name, 
    count(distinct bi.item_id) 
from 
    bucket a 
    join bucket b 
    left outer join bucket_item ai on ai.bucket_name = a.name 
    left outer join bucket_item bi on bi.bucket_name = b.name and ai.item_id = bi.item_id 
where 
    a.name < b.name 
group by 
    a.name, 
    b.name 
order by 
    a.name, 
    b.name 
; 
Смежные вопросы