Php 选择与MySql中一对多关系右侧匹配的行
我有四张桌子。一个用于公司,一个用于产品,一个用于公司地址,一个用于公司董事 products、director和address表与company表具有一对多关系 因此,一家公司可以有许多产品、许多地址和许多董事Php 选择与MySql中一对多关系右侧匹配的行,php,mysql,sql,join,pdo,Php,Mysql,Sql,Join,Pdo,我有四张桌子。一个用于公司,一个用于产品,一个用于公司地址,一个用于公司董事 products、director和address表与company表具有一对多关系 因此,一家公司可以有许多产品、许多地址和许多董事 CREATE TABLE IF NOT EXISTS `companies` ( `company_id` int(11) NOT NULL AUTO_INCREMENT, `company_name` varchar(50) NOT NULL, PRIMARY KEY (
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)来为匹配主管(姓氏和dob)和地址(邮政编码)的公司查找产品
我只想每行列出一个匹配的产品,而不是单独列出每个导演或邮政编码
到目前为止,我有下面的查询,这似乎是可行的,但它是丑陋的,我怀疑这是一个荒谬的方式进行这方面的速度和效率
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 )
提前感谢您的帮助。至少,可以通过使用
exists
操作符而不是中的重写directors
上的两个子查询来统一它们。为了更好地度量,我用这个操作符重写了整个查询,尽管严格来说这不是必需的:
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)
不确定为什么需要子查询
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'
或
如果您对这两个查询进行解释,您会发现它们在内部是相同的。您希望“更好”的工作代码最好发布在上面,我会重新思考您的底层数据结构。。。我不知道如何使用姓氏
、出生地
、以及邮政编码
。如果您有姓氏
和dob
,则通过董事表您有公司id
。。。那么,您为什么需要邮政编码中地址表中的公司id
?这没有道理。谢谢你@upful。并非所有公司都必须有地址记录,也并非所有公司都必须有董事。它们是两个独立的东西,必须用墨水写在公司表上,因此我能看到的唯一方法是通过公司ID。在这种情况下,您可能会使用或操作符,而不是和。。。所以其中(姓氏=:姓氏和出生日期=:出生日期)或邮政编码=:杀虫剂
。。。此外,我认为确定哪家公司的产品与您的搜索结果相匹配是很重要的,而不仅仅是返回产品列表。谢谢您的回答。问题是,它为同一产品返回多行,每个债务人或邮政编码返回一行,然后您可以使用DISTINCT。e、 g.选择不同的p.product…
谢谢。非常有用。这就是我最终使用的解决方案
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'