2016-11-03 2 views
0

나는 사람과 프로젝트의 데이터베이스를 가지고 있습니다. 특정인과 공동 작업 한 사람의 이름과 몇 개의 프로젝트를 찾을 수 있습니까?MySQL에서 협업 찾기

예를 들어, 나는 데이터베이스에서 지미의 협력자를 찾으려면 :에 의해

Jimmy's collaborations: 
+--------+----------------+ 
| person | collaborations | 
+--------+----------------+ 
| Ashley | 3    | 
| Martin | 2    | 
+--------+----------------+ 

답변

2

자체로 테이블에 참여, 그룹 :

+----------+--------+ 
| project | person | 
+----------+--------+ 
| datamax | Jimmy | 
| datamax | Ashley | 
| datamax | Martin | 
| cocoplus | Jimmy | 
| cocoplus | Ashley | 
| glassbox | Jimmy | 
| glassbox | Martin | 
| powerbin | Jimmy | 
| powerbin | Ashley | 
+----------+--------+ 

이 결과는 다음과 같이 보일 것입니다 person 필드 :

SELECT u2.person, COUNT(u1.project) AS collaborations 
FROM users u1 
JOIN users u2 ON u2.project = u1.project 
WHERE u1.person != u2.person AND u1.person = 'Jimmy' 
GROUP BY u2.person; 

쿼리는 Ji mmy는 u1에서 참가했습니다. u2의 행은 u1의 행으로 필터링됩니다. 두 표의 사용자가 일치하는 중복 항목은 WHERE 절로 필터링됩니다. 마지막으로 결과 집합은 person으로 그룹화되고 COUNT 함수는 그룹 당 행 수를 계산합니다.

성능

주, personproject 열 (또는 두 개의 인덱스)에 대한 지수는 크게 위의 쿼리의 성능이 향상됩니다. 특정 인덱스 구성은 테이블 구조에 따라 다릅니다. 차라리에서 사람과 프로젝트를 저장하는 것,

그러나

ALTER TABLE users ADD INDEX `project` (`project`(10)); 
ALTER TABLE users ADD INDEX `person` (`person`(10)); 

정규화 :하지만, 나는 다음과 같은 예를 들어, personprojectvarchar 필드가있는 테이블에 대한 매우 충분하다 생각 숫자 ID가있는 별도의 표. 세 번째 테이블은 커넥터 역할을 할 수 있습니다 : person_id - project_id. 즉, 나는 normalization을 추천합니다. 정규화 된 테이블을 사용하면 텍스트 필드에 비 대한 인덱스를 작성할 필요가 없습니다. 로 보일 수 있습니다

정규화 된 테이블은 다음과 같습니다

CREATE TABLE users (
    id int unsigned NOT NULL AUTO_INCREMENT, 
    name varchar(200) NOT NULL DEFAULT '', 
    PRIMARY KEY(`id`), 
    -- This index is needed, if you want to fetch users by names 
    INDEX name (name(8)) 
); 
CREATE TABLE projects (
    id int unsigned NOT NULL AUTO_INCREMENT, 
    name varchar(100) NOT NULL DEFAULT '', 
    PRIMARY KEY(`id`) 
); 
CREATE TABLE collaborations (
    project_id int unsigned NOT NULL DEFAULT 0, 
    user_id int unsigned NOT NULL DEFAULT 0, 
    PRIMARY KEY(`project_id`, `user_id`) 
); 

모양 정규화 된 구조에 대한 쿼리 더 복잡한 조금 :

-- In practice, the user ID is retrieved from the calling process 
-- (such as POST/GET HTTP requests, for instance). 
SET @user_id := (SELECT id FROM users WHERE name LIKE 'Jimmy'); 

SELECT u.name person, COUNT(p.id) collaborations 
FROM collaborations c 
JOIN collaborations c2 USING(project_id) 
JOIN users u ON u.id = c2.user_id 
JOIN projects p ON p.id = c2.project_id 
WHERE c.user_id = @user_id AND c.user_id != c2.user_id 
GROUP BY c2.user_id; 

그러나 빨리 될 것이며, 필요한 공간 특히 대용량 데이터 세트의 경우 인덱스가 상당히 작아집니다.

원래 대답

은 각 사람을위한 프로젝트의 총 수를 가져 GROUP BYCOUNT 기능을 사용하려면 :이 사람들과 협업 수의 테이블을 리턴

SELECT person, COUNT(*) AS collaborations 
FROM users 
GROUP BY person; 
+0

,하지만은 않습니다 사람을 지정하지 않고 계산합니까? 나는 모든 공동 작업자와 한 사람의 수를 찾고 있습니다. – Rachie

+0

@Rachie, [this] (http://sqlfiddle.com/#!9/c92a8/1)을 확인하십시오. 답변을 업데이트했습니다. –