2015-11-17 112 views
1

我有一個表格:網站,廣告系列和out,用於我正在構建的廣告系列跟蹤系統。當點擊鏈接時,表格會在網站ID和廣告系列ID匹配的位置更新其點擊次數。一對多加入三張表

在表格中有一個campaign_id和site_id,它們分別對應於網站和廣告系列表。更爲複雜的是,每個網站可以有4個廣告系列(campaign_a,campaign_b,campaign_id_reviews,campaign_id_reviews_phone)。我想加盟三個表,併爲每個站點我想folllowing是在一行:

site.site_name, site.campaign_id_a, campaigns.campaign_name, out.hits, 
site.campaign_id_b, campaigns.campaign_name, out.hits, 
site.campaign_id_reviews, campaigns.campaign_name, out.hits, 
site.campaign_id_reviews_phone, campaigns.campaign_name, out.hits 

這是我嘗試不把所有的SITE_ID/CAMPAIGN_ID組合回來了,只帶回一個記錄每個SITE_ID,而不是所有的SITE_ID/CAMPAIGN_ID組合

SELECT s.*, c.*, o.* FROM sites s 
INNER JOIN campaigns c ON s.campaign_id_a=c.campaign_id 
INNER JOIN campaigns ON s.campaign_id_b=campaigns.campaign_id 
INNER JOIN `out` o ON s.campaign_id_a=o.campaign_id AND s.site_id=o.site_id 
WHERE s.site_id NOT IN(100,101) 
ORDER BY o.site_id ASC 

我與3記錄轉儲創建表:

CREATE TABLE IF NOT EXISTS `sites` (
    `site_id` mediumint(4) NOT NULL AUTO_INCREMENT, 
    `site_name` varchar(70) NOT NULL, 
    `campaign_id_a` tinyint(4) NOT NULL, 
    `campaign_id_b` tinyint(4) NOT NULL, 
    `a_display_name` varchar(50) NOT NULL, 
    `b_display_name` varchar(50) NOT NULL, 
    `campaign_id_reviews` tinyint(4) NOT NULL, 
    `campaign_id_reviews_phone` tinyint(3) NOT NULL DEFAULT '4', 
    PRIMARY KEY (`site_id`), 
    UNIQUE KEY `site_id` (`site_id`), 
    UNIQUE KEY `site_name` (`site_name`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=102 ; 

INSERT INTO `sites` (`site_id`, `site_name`, `campaign_id_a`, `campaign_id_b`, `a_display_name`, `b_display_name`, `campaign_id_reviews`, `campaign_id_reviews_phone`) VALUES 
(1, 'example.com', 1, 8, 'hard456', 'easy123', 3, 4), 
(2, 'example.org', 1, 8, 'hard456', 'easy123', 3, 4), 
(3, 'example.net', 8, 8, 'easy123', 'easy123', 3, 4); 



CREATE TABLE IF NOT EXISTS `out` (
    `out_id` mediumint(7) NOT NULL AUTO_INCREMENT, 
    `site_id` tinyint(4) NOT NULL, 
    `campaign_id` tinyint(4) NOT NULL DEFAULT '0', 
    `hits` int(11) NOT NULL, 
    `date_last_hit` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
    PRIMARY KEY (`out_id`), 
    UNIQUE KEY `site2campaign` (`site_id`,`campaign_id`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=101 ; 

INSERT INTO `out` (`out_id`, `site_id`, `campaign_id`, `hits`, `date_last_hit`) VALUES 
(19, 60, 3, 418, '2015-11-16 22:52:33'), 
(10, 2, 1, 1135, '2015-11-15 04:51:32'), 
(20, 60, 1, 1710, '2015-11-14 13:52:20'); 




CREATE TABLE IF NOT EXISTS `campaigns` (
    `campaign_id` tinyint(4) NOT NULL AUTO_INCREMENT, 
    `campaign_name` varchar(60) NOT NULL, 
    `network` varchar(60) NOT NULL, 
    `url` varchar(400) NOT NULL, 
    PRIMARY KEY (`campaign_id`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=10 ; 

INSERT INTO `campaigns` (`campaign_id`, `campaign_name`, `network`, `url`) VALUES 
(1, 'Hard456', 'Hard Network', 'exampleURL'), 
(3, 'medium678', 'Medium Network', 'examplewithURL'), 
(8, 'easy123', 'Easy Network', 'exampleURLLoaction'); 
(4, 'none23', 'None Network', 'urlExample'); 
+0

你可以嘗試使用臨時表。會讓你的查詢看起來更簡單。 – Sohaib

+0

我認爲臨時表會讓高流量的數據庫變得複雜,高成本只是爲了讓它看起來很簡單。我看不出我如何使用臨時表來恢復我需要的所有數據 –

+0

對於製作課程不是必需的。我只想更好地理解你的用例。 – Sohaib

回答

0

問題是要覆蓋列名。雖然我沒有測試過,但這應該可行。您可以使用類似的模式爲每個廣告系列ID獲取out.hits。

SELECT 
    r3.*, c4.campaign_name c_name_rev_phone 
FROM 
    (SELECT 
      r2.*, c3.campaign_name c_name_rev 
    FROM 
     (SELECT 
      r1.*, c2.campaign_name c_name_b 
     FROM 
      (SELECT 
       s1.site_id s_id, 
       s1.site_name sname, 
       s1.campaign_id_a c_id_a, 
       s1.campaign_id_b c_id_b, 
       s1.campaign_id_reviews c_id_rev, 
       s1.campaign_id_reviews_phone c_id_rev_phone, 
       c1.campaign_name c_name_a 
      FROM sites s1 JOIN campaigns c1 ON s1.campaign_id_a = c1.campaign_id) r1 
     JOIN campaigns c2 ON c2.campaign_id=r1.c_id_b) r2 
    JOIN campaigns c3 ON c3.campaign_id=r2.c_id_rev) r3 
JOIN campaigns c4 on c4.campaign_id=r3.c_id_rev_phone; 

編輯1-

如佔該問題所提供的樣本數據以下查詢的結果將是

SELECT s.*, c.* FROM sites s 
INNER JOIN campaigns c ON s.campaign_id_a=c.campaign_id 
INNER JOIN campaigns ON s.campaign_id_b=campaigns.campaign_id 
WHERE s.site_id NOT IN(100,101); 

結果:

site_id |site_name  |campaign_id_a |campaign_id_b |a_display_name |b_display_name |campaign_id_reviews |campaign_id_reviews_phone |campaign_id |campaign_name |network  |url 
--------|---------------|---------------|---------------|---------------|---------------|-----------------------|---------------------------|---------------|---------------|---------------|------------------ 
1  |example.com |1    |8    |hard456  |easy123  |3      |4       |1    |Hard456  |Hard Network |exampleURL 
2  |example.org |1    |8    |hard456  |easy123  |3      |4       |1    |Hard456  |Hard Network |exampleURL 
3  |example.net |8    |8    |easy123  |easy123  |3      |4       |8    |easy123  |Easy Network |exampleURLLoaction 

結果查詢在回答:

s_id |sname   |c_id_a |c_id_b |c_id_rev |c_id_rev_phone |c_name_a |c_name_b |c_name_rev |c_name_rev_phone 
------------------------|-------|-------|-----------|---------------|-----------|-----------|-----------|---------------- 
1  |example.com |1  |8  |3   |4    |Hard456 |easy123 |medium678 |none23 
2  |example.org |1  |8  |3   |4    |Hard456 |easy123 |medium678 |none23 
3  |example.net |8  |8  |3   |4    |easy123 |easy123 |medium678 |none23 

campaign_id_acampaign_id_bcampaign_id_reviews等注意如何活動名稱是單獨取出。

這裏是會給你完整的答案查詢:

SELECT 
r3.*, 
c4.campaign_name c_name_rev_phone, 
o4.hits hits_rev_phone 
FROM 
    (SELECT 
      r2.*, 
      c3.campaign_name c_name_rev, 
      o3.hits hits_rev 
    FROM 
     (SELECT 
      r1.*, 
      c2.campaign_name c_name_b, 
      o2.hits hits_b 
     FROM 
      (SELECT 
       s1.site_id s_id, 
       s1.site_name sname, 
       s1.campaign_id_a c_id_a, 
       s1.campaign_id_b c_id_b, 
       s1.campaign_id_reviews c_id_rev, 
       s1.campaign_id_reviews_phone c_id_rev_phone, 
       c1.campaign_name c_name_a, 
       o1.hits hits_a 
      FROM sites s1 JOIN campaigns c1 ON s1.campaign_id_a = c1.campaign_id JOIN `out` o1 ON (c1.campaign_id=o1.campaign_id AND o1.site_id=s1.site_id)) r1 
     JOIN campaigns c2 ON c2.campaign_id=r1.c_id_b JOIN `out` o2 ON (c2.campaign_id=o2.campaign_id AND o2.site_id=r1.s_id)) r2 
    JOIN campaigns c3 ON c3.campaign_id=r2.c_id_rev JOIN `out` o3 ON (c3.campaign_id=o3.campaign_id AND o3.site_id=r2.s_id)) r3 
JOIN campaigns c4 on c4.campaign_id=r3.c_id_rev_phone JOIN `out` o4 ON (c4.campaign_id=o4.campaign_id AND o4.site_id=r3.s_id); 

用於設置採樣數據的提供了,因爲很多campaign_idsite_id組合中不存在的表這將給空的結果out。由於我們正在進行INNER加入,因此您會忽略此信息。如果要將hits報告爲0,那麼當site_idcampaign_id組合不存在時,則需要使用LEFT JOIN

如果這不是您想要的,請隨時恢復。

+0

我認爲這個概念是在正確的軌道上,但你創建的查詢返回的結果與上面的查詢相同,但沒有「INNER JOIN'out' o ON s.campaign_id_a = o.campaign_id AND s.site_id = o。 SITE_ID」。我的主要問題是爲網站表中的每個campaign_id找出表中的匹配。我已經嘗試過無數次嘗試添加出表,但似乎無法弄清楚。 –

+0

這不會返回相同的結果。在您的情況下,如果您將聯合移除爲「out」,則輸出將僅返回來自站點表的campaign_id_a的一個campaign_name。如果你明白這一點,那麼你可以很容易地將它擴展到out.hits。這是因爲列campaign_name的值是從第一次內部聯接時引用的第一個引用中提取的。我會更新答案以包含out.hits,但重要的是要了解問題中查詢的錯誤。 – Sohaib

0

您似乎會加入兩次廣告系列,但只會返回與compaign_id_a匹配的任何內容。 Campaign_id_b在結果中被忽略,而其他兩個廣告系列標識根本沒有處理。

分割後拿到每個廣告系列ID和聯合在一起的結果: -

(SELECT s.site_id, 
     s.site_name, 
     s.campaign_id_a, 
     s.campaign_id_b, 
     s.a_display_name, 
     s.b_display_name, 
     s.campaign_id_reviews, 
     s.campaign_id_reviews_phone, 
     o.out_id, 
     o.hits, 
     o.date_last_hit, 
     c.campaign_id, 
     c.campaign_name, 
     c.network, 
     c.url 
FROM sites s 
INNER JOIN campaigns c ON s.campaign_id_a = c.campaign_id 
INNER JOIN `out` o ON c.campaign_id = o.campaign_id AND s.site_id = o.site_id 
WHERE s.site_id NOT IN (100,101)) 
UNION 
(SELECT s.site_id, 
     s.site_name, 
     s.campaign_id_a, 
     s.campaign_id_b, 
     s.a_display_name, 
     s.b_display_name, 
     s.campaign_id_reviews, 
     s.campaign_id_reviews_phone, 
     o.out_id, 
     o.hits, 
     o.date_last_hit, 
     c.campaign_id, 
     c.campaign_name, 
     c.network, 
     c.url 
FROM sites s 
INNER JOIN campaigns c ON s.campaign_id_b = c.campaign_id 
INNER JOIN `out` o ON c.campaign_id = o.campaign_id AND s.site_id = o.site_id 
WHERE s.site_id NOT IN (100,101)) 
UNION 
(SELECT s.site_id, 
     s.site_name, 
     s.campaign_id_a, 
     s.campaign_id_b, 
     s.a_display_name, 
     s.b_display_name, 
     s.campaign_id_reviews, 
     s.campaign_id_reviews_phone, 
     o.out_id, 
     o.hits, 
     o.date_last_hit, 
     c.campaign_id, 
     c.campaign_name, 
     c.network, 
     c.url 
FROM sites s 
INNER JOIN campaigns c ON s.campaign_id_reviews = c.campaign_id 
INNER JOIN `out` o ON c.campaign_id = o.campaign_id AND s.site_id = o.site_id 
WHERE s.site_id NOT IN (100,101)) 
UNION 
(SELECT s.site_id, 
     s.site_name, 
     s.campaign_id_a, 
     s.campaign_id_b, 
     s.a_display_name, 
     s.b_display_name, 
     s.campaign_id_reviews, 
     s.campaign_id_reviews_phone, 
     o.out_id, 
     o.hits, 
     o.date_last_hit, 
     c.campaign_id, 
     c.campaign_name, 
     c.network, 
     c.url 
FROM sites s 
INNER JOIN campaigns c ON s.campaign_id_reviews_phone = c.campaign_id 
INNER JOIN `out` o ON c.campaign_id = o.campaign_id AND s.site_id = o.site_id 
WHERE s.site_id NOT IN (100,101)) 
ORDER BY site_id ASC 
+0

儘管我希望能夠這樣工作,但我一直在訂單上發生錯誤,因此我將其拿出。然後我不斷收到「c.campaign_id_a」上的內部連接錯誤。我也沒有完全理解這些工會如何工作 –

+0

修復了一些錯別字,現在它應該可以工作。同時在SELECT語句中專門列出列以避免重複的列名稱。 – Kickstart