2015-08-26 31 views
3

我有4個表格。一個用於公司,一個用於公司地址的產品,另一個用於公司董事。在MySql中選擇與一對多對應關係匹配的行

產品,董事和地址表與公司表格有着一對多的關係。

因此,一家公司可以有許多產品,許多地址和許多董事。

CREATE TABLE IF NOT EXISTS `companies` (
    `company_id` int(11) NOT NULL AUTO_INCREMENT, 
    `company_name` varchar(50) NOT NULL, 
    PRIMARY KEY (`company_id`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ; 

CREATE TABLE IF NOT EXISTS `products` (
    `product_id` int(11) NOT NULL AUTO_INCREMENT, 
    `company_id` int(11) NOT NULL, 
    `product` varchar(50) NOT NULL, 
    PRIMARY KEY (`product_id`), 
    KEY `company_id` (`company_id`), 
    KEY `product` (`product`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ; 

CREATE TABLE IF NOT EXISTS `directors` (
    `director_id` int(11) NOT NULL AUTO_INCREMENT, 
    `company_id` int(11) NOT NULL, 
    `surname` varchar(100) NOT NULL, 
    `dob` date NOT NULL, 
    PRIMARY KEY (`director_id`), 
    KEY `company_id` (`company_id`), 
    KEY `surname` (`surname`), 
    KEY `dob` (`dob`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ; 

CREATE TABLE IF NOT EXISTS `addresses` (
    `address_id` int(11) NOT NULL AUTO_INCREMENT, 
    `company_id` int(1) NOT NULL, 
    `postcode` varchar(10) NOT NULL, 
    PRIMARY KEY (`address_id`), 
    KEY `company_id` (`company_id`), 
    KEY `postcode` (`postcode`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ; 

INSERT INTO `companies` (`company_id`, `company_name`) VALUES 
(1, 'Honda'), 
(2, 'Toyota'); 

INSERT INTO `products` (`product_id`, `company_id`, `product`) VALUES 
(1, 1, 'Civic'), 
(2, 1, 'Accord'), 
(3, 2, 'Corolla'), 
(4, 2, 'Prius'), 
(5, 1, 'CRV'); 

INSERT INTO `directors` (`director_id`, `company_id`, `surname`, `dob`)  VALUES 
(1, 1, 'Jones', '1990-09-09'), 
(2, 1, 'Smith', '1980-08-08'), 
(3, 2, 'Lucas', '1970-07-07'), 
(4, 1, 'Kelly', '1960-06-06'), 
(5, 2, 'Monty', '1950-05-05'); 

INSERT INTO `addresses` (`address_id`, `company_id`, `postcode`) VALUES 
(6, 1, '12345'), 
(7, 2, '23456'), 
(8, 1, '34567'), 
(9, 2, '45678'), 
(10, 1, '56789'); 

我試着寫一個高效的查詢(使用MySQL/PDO)找到產品匹配匹配董事(姓氏和出生日期)及地址(郵編),公司。

我只想列出每行一個匹配的產品,而不是單獨列出每個導演或郵編。

到目前爲止,我有下面的查詢,這似乎工作,但它是醜陋的,我懷疑在速度和效率方面做出這種荒謬的方式。

SELECT product 
FROM products p 
LEFT JOIN companies c USING(company_id) 
WHERE :lname IN ( 
    SELECT surname 
    FROM directors d 
    WHERE c.company_id = d.company_id) 
AND :dob IN ( 
    SELECT dob 
    FROM directors d 
    WHERE c.company_id = d.company_id) 
AND :postcode IN ( 
    SELECT postcode 
    FROM addresses a 
    WHERE c.company_id = a.company_id) 

預先感謝您的幫助。

+0

你想工作'更好'的工作代碼是最好張貼在[codereview](http://codereview.stackexchange.com/) –

+0

我會重新考慮你的基礎數據結構...我不明白'姓氏' ','dob'和'postcode'都可以使用。如果你有'surname'和'dob',那麼你通過director表有'company_id' ...爲什麼你需要'postcode'中'addresses'表中的'company_id'?這沒有意義。 – upful

+0

謝謝@upful。並非所有公司都必須有地址記錄,並非所有公司都必須有董事。他們是兩個獨立的東西,必須簽署公司表,所以我能看到做到這一點的唯一方法是通過company_id – ratherBeKiting

回答

3

至少,directors上的兩個子查詢可以通過用exists運算符而不是in來重寫它們來統一。爲了獲得良好的措施,我改寫了這個運營商整個查詢,但它不是絕對必要的:

SELECT product 
FROM  products p 
LEFT JOIN companies c USING(company_id) 
WHERE  EXISTS (SELECT * 
        FROM directors d 
        WHERE c.company_id = d.company_id AND 
         (:lname = d.lanme OR :dob = d.dob)) AND 
      EXISTS (SELECT * 
        FROM addresses a 
        WHERE c.company_id = a.company_id AND :postcode = a.postcode) 
+0

謝謝兩個。很有用。這是我最終使用的解決方案 – ratherBeKiting

4

不確定爲什麼你需要在所有的子查詢?

SELECT p.product FROM products p 
INNER JOIN companies c USING(company_id) 
INNER JOIN directors d ON d.company_id = c.company_id AND d.surname = 'Jones' AND d.dob = '1990-09-09' 
INNER JOIN addresses a ON a.company_id = c.company_id AND a.postcode = '12345' 

或者

SELECT p.product FROM products p 
INNER JOIN companies c USING(company_id) 
INNER JOIN directors d USING(company_id) 
INNER JOIN addresses a USING(company_id) 
WHERE d.surname = 'Jones' 
AND d.dob = '1990-09-09' 
AND a.postcode = '12345' 

如果你做一個關於這兩個查詢解釋,你會看到他們在內部落得相同。

+0

感謝您的答案。與此相關的問題是,它爲同一產品返回多行,每個債務人一個或郵政編碼 – ratherBeKiting

+0

啊,那麼你可以使用DISTINCT。例如'SELECT DISTINCT p.product ...' – rjdown