2012-03-23 33 views
1

我很久以來一直在使用Mysql,並且對三個表上簡單的LEFT JOIN的結果感到困惑。三個表的Mysql LEFT JOIN返回到許多行

我有以下三個表(I創建了一個例子,將它縮小)

一個)人

+----------+-------------+------+-----+---------+----------------+ 
| Field | Type  | Null | Key | Default | Extra   | 
+----------+-------------+------+-----+---------+----------------+ 
| PersonID | int(11)  | NO | PRI | NULL | auto_increment | 
| Name  | varchar(50) | YES |  | NULL |    | 
| Age  | int(11)  | YES |  | NULL |    | 
+----------+-------------+------+-----+---------+----------------+ 

b)中person_fav_artists

+----------------+--------------+------+-----+---------+----------------+ 
| Field   | Type   | Null | Key | Default | Extra   | 
+----------------+--------------+------+-----+---------+----------------+ 
| FavInterpretID | int(10)  | NO | PRI | NULL | auto_increment | 
| PersonID  | int(10)  | NO |  | 0  |    | 
| Interpret  | varchar(100) | YES |  | NULL |    | 
+----------------+--------------+------+-----+---------+----------------+ 

c)中person_fav_movies

+------------+--------------+------+-----+---------+----------------+ 
| Field  | Type   | Null | Key | Default | Extra   | 
+------------+--------------+------+-----+---------+----------------+ 
| FavMovieID | int(10)  | NO | PRI | NULL | auto_increment | 
| PersonID | int(10)  | NO |  | 0  |    | 
| Movie  | varchar(100) | YES |  | NULL |    | 
+------------+--------------+------+-----+---------+----------------+ 

我的示例表格用於將任意數量的藝術家和電影存儲到一個人中。 天氣這使得它的存在與否並不重要,因爲它只是一個簡單的例子。

現在我有以下數據表中:

mysql> SELECT * FROM persons; 
+----------+------+------+ 
| PersonID | Name | Age | 
+----------+------+------+ 
|  1 | Jeff | 22 | 
|  2 | Lisa | 15 | 
|  3 | Jon | 30 | 
+----------+------+------+ 

mysql> SELECT * FROM person_fav_artists; 
+----------------+----------+----------------+ 
| FavInterpretID | PersonID | Interpret  | 
+----------------+----------+----------------+ 
|    1 |  1 | Linkin Park | 
|    2 |  1 | Muse   | 
|    3 |  2 | Madonna  | 
|    4 |  2 | Katy Perry  | 
|    5 |  2 | Britney Spears | 
|    6 |  1 | Fort Minor  | 
|    7 |  1 | Jay Z   | 
+----------------+----------+----------------+ 

mysql> SELECT * FROM person_fav_movies; 
+------------+----------+-------------------+ 
| FavMovieID | PersonID | Movie    | 
+------------+----------+-------------------+ 
|   1 |  1 | American Pie 1 | 
|   2 |  1 | American Pie 2 | 
|   3 |  1 | American Pie 3 | 
|   4 |  3 | A Game of Thrones | 
|   5 |  3 | Eragon   | 
+------------+----------+-------------------+ 

現在i'm簡單地用下面的查詢連接表:

Select * FROM persons 
LEFT JOIN person_fav_artists USING (PersonID) 
LEFT JOIN person_fav_movies USING (PersonID); 

返回以下結果:

+----------+------+------+----------------+----------------+------------+-------------------+ 
| PersonID | Name | Age | FavInterpretID | Interpret  | FavMovieID | Movie    | 
+----------+------+------+----------------+----------------+------------+-------------------+ 
|  1 | Jeff | 22 |    1 | Linkin Park |   1 | American Pie 1 | 
|  1 | Jeff | 22 |    1 | Linkin Park |   2 | American Pie 2 | 
|  1 | Jeff | 22 |    1 | Linkin Park |   3 | American Pie 3 | 
|  1 | Jeff | 22 |    2 | Muse   |   1 | American Pie 1 | 
|  1 | Jeff | 22 |    2 | Muse   |   2 | American Pie 2 | 
|  1 | Jeff | 22 |    2 | Muse   |   3 | American Pie 3 | 
|  1 | Jeff | 22 |    6 | Fort Minor  |   1 | American Pie 1 | 
|  1 | Jeff | 22 |    6 | Fort Minor  |   2 | American Pie 2 | 
|  1 | Jeff | 22 |    6 | Fort Minor  |   3 | American Pie 3 | 
|  1 | Jeff | 22 |    7 | Jay Z   |   1 | American Pie 1 | 
|  1 | Jeff | 22 |    7 | Jay Z   |   2 | American Pie 2 | 
|  1 | Jeff | 22 |    7 | Jay Z   |   3 | American Pie 3 | 
|  2 | Lisa | 15 |    3 | Madonna  |  NULL | NULL    | 
|  2 | Lisa | 15 |    4 | Katy Perry  |  NULL | NULL    | 
|  2 | Lisa | 15 |    5 | Britney Spears |  NULL | NULL    | 
|  3 | Jon | 30 |   NULL | NULL   |   4 | A Game of Thrones | 
|  3 | Jon | 30 |   NULL | NULL   |   5 | Eragon   | 
+----------+------+------+----------------+----------------+------------+-------------------+ 
17 rows in set (0.00 sec) 

到目前爲止這麼好。 現在我的問題是,如果'人'傑夫'返回'12'行'是正常的',儘管他只有四個'藝術家'和三部'電影'分配給他。 我想我可能會理解爲什麼結果是如此,但我認爲爲實際數據太少而返回太多行是相當愚蠢的。

那麼,我的查詢有什麼問題,或者這是故意的行爲?

結果我倒是想有,會象(僅適用於傑夫)以下:

+----------+------+------+----------------+----------------+------------+-------------------+ 
| PersonID | Name | Age | FavInterpretID | Interpret  | FavMovieID | Movie    | 
+----------+------+------+----------------+----------------+------------+-------------------+ 
|  1 | Jeff | 22 |    1 | Linkin Park |   1 | American Pie 1 | 
|  1 | Jeff | 22 |    2 | Muse   |   2 | American Pie 2 | 
|  1 | Jeff | 22 |    3 | Fort Minor  |   3 | American Pie 3 | 
|  1 | Jeff | 22 |    4 | Jay Z   |   1 | NULL    | <- 'American Pie 1/2/3' would be OK as well. 
+----------+------+------+----------------+----------------+------------+-------------------+ 

感謝您的幫助!

回答

0

你得到正確的結果與12條記錄因爲這是正確的元組與您要求的數據的方式。我不確定爲什麼你將這3個表連接在一起,因爲這2個表是不同的數據類型。我建議你選擇的人&電影,然後你可以聯合人&藝術家,因爲你的工會希望列是相同的,我會建議添加一個類型來區分藝術家和電影,然後好名字應該只是作爲一個string_value

+0

謝謝您的回答! 我已經認爲這是「正確」的結果,因爲它返回所有可能的組合。 關於你的問題: 我加入表格在C#中創建一個對象「人物」,然後列出哪些包含「電影」和「藝術家」。 我正在使用此查詢來創建整個對象,因此我將所有內容連接在一起。 也許這將是更聰明的做它分開,但後來我有更多的查詢... – user1288392 2012-03-23 14:57:07

+0

如果您使用的C#對象,有能力「過濾」的記錄,你當然可以使用過濾器數據並將其應用於您的對象/視圖,然後重新過濾並將其應用於其他對象/視圖。這會讓你的SQL拉一拉,但我不建議。從第三個表加入數據所需的時間與第二個語句相同,因爲你的第一個表被緩存了。 – 2012-03-23 15:32:01

+0

是的,你說得對,我的C#對象是從Mysql-Query中「過濾」結果的。這意味着重複的行將被忽略。 我不舒服我理解你的答案的第二部分。你的意思是我應該使用更多的查詢,而不是像我在我的例子中完成的一樣大嗎?這意味着我必須爲電影和藝術家創建一個單獨的查詢。 – user1288392 2012-03-23 16:42:57

0

此行爲是故意的。

  1. 您的第一張表格有1列給Jeff。
  2. 第二張表有4列Jeff,所以加入的表格給出 1x4。
  3. 第三張表有3列Jeff,所以連接表給出 1x4x3。

你現在已經有了所有可能的組合。

0

我認爲這是正常的,因爲它採取了喜劇電影和收藏藝術家的所有組合。我認爲這是如何加入作品。

1

查詢或結果沒有錯,它只是返回所有可能的組合。如果數據量將很大,一種選擇是分成兩個單獨的查詢。

+0

感謝您的回答。 我只是希望能夠有一種不分裂查詢的方式,但是接下來我要分一杯羹。 – user1288392 2012-03-23 15:01:04

0

嘗試通過更換LEFT JOIN與INNER JOIN爲:

 SELECT * 
    FROM persons 
    INNER JOIN person_fav_artists USING (PersonID) 
    INNER JOIN person_fav_movies USING (PersonID); 
+1

使用「INNER JOIN」無法工作,也不會減少人員「Jeff」產生的行數。這隻會導致沒有「麗莎」和「喬恩」的結果。 – user1288392 2012-03-23 14:54:49