2016-11-03 2 views
0

私は人とプロジェクトのデータベースを持っています。特定の人と協力した人の名前やプロジェクトの数はどのようにして知ることができますか?MySQLでコラボレーションを見つける

例えば、私は、データベースからジミーの協力者を見つけたい:

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

結果はこのようなものになります。

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

答えて

2

自体でテーブルに参加し、でグループを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ファンクションはグループごとの行数を計算します。

パフォーマンス

注、person及びproject列(または2つの別個のインデックス)のインデックスが大幅に上記のクエリのパフォーマンスを向上させるであろう。特定のインデックス構成は、テーブル構造によって異なります。私はむしろに人物やプロジェクトを格納します、

しかし

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

ノーマライゼーション:が、私は次は、例えば、personprojectための2つのvarcharフィールドを持つテーブルのかなり十分だと思います数字のIDを持つ別個の表。 3番目のテーブルはコネクタの役割を果たすことができます: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 BY句でCOUNT機能を使用し、一人一人のためのプロジェクトの合計数を取得するためにオリジナルの答え

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

これは人とコラボレーション数のテーブルを返しますが、何をしますか人を特定せずに数えて平均するか?私はすべての協力者とその人の数を探しています。 – Rachie

+0

@Rachie、[this](http://sqlfiddle.com/#!9/c92a8/1)をチェックしてください。私は答えを更新しました。 –

関連する問題