[英]MySQL multiple table joins
我正在建立一個支持系統,來自某個國家/地區的用戶提出某個類別的問題,來自該國家、行政部門和類別的專家被分配該問題。
來自Germany
的前用戶 zip 代碼1000
在Software
類別上出現問題。 來自Germany
國家和/或 zip 代碼邊界MIN_PROVINCE_ZIPCODE <= 1000 >= MAX_PROVINCE_ZIPCODE
的省份和/或Software
代碼邊界MIN_REGION_ZIPCODE <= 1000 >= MAX_REGION_ZIPCODE
<= 1000 和/或區域的專家
Ie: Select all issues where issue country is equal to expert country, and issue category is equal to one of experts' categories, and/or issue zip code is greater or equal to minimum province zip code and smaller or equal to maximum province zip code , 和/或發布 zip 代碼大於或等於區域最小值 zip 代碼並且發布代碼小於或等於 zip 代碼。
“和/或”是指是否指派專家處理特定行政部門的問題,如果不是,則指派與他們的國家和類別相匹配的所有內容
*記住!*
a) 專家可以參與...
b) 如果專家不是...
CREATE TABLE IF NOT EXISTS `categories` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(300) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `provinces` (
`id` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
`country` varchar(300) NOT NULL,
`province` varchar(300) NOT NULL,
`min_zipcode` int(5) unsigned NOT NULL,
`max_zipcode` int(5) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `regions` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`provinceid` int(11) unsigned NOT NULL,
`region` varchar(300) NOT NULL,
`min_zipcode` int(5) unsigned NOT NULL,
`max_zipcode` int(5) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `issues` (
`id` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
`categoryid` int(11) unsigned NOT NULL,
`country` varchar(150) NOT NULL,
`zipcode` int(5) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `experts` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`country` varchar(150) NOT NULL DEFAULT 'none',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `experts_categories` (
`expertid` int(11) unsigned NOT NULL,
`categoryid` int(11) unsigned NOT NULL,
PRIMARY KEY (`expertid`,`categoryid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `experts_provinces` (
`expertid` int(11) unsigned NOT NULL,
`provinceid` int(11) unsigned NOT NULL,
PRIMARY KEY (`expertid`,`provinceid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `experts_regions` (
`expertid` int(11) NOT NULL,
`regionid` int(11) NOT NULL,
PRIMARY KEY (`expertid`,`regionid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `categories` (`id`, `name`) VALUES
(1, 'Software'),
(2, 'Hardware');
INSERT INTO `experts` (`id`, `country`) VALUES
(1, 'Germany'),
(2, 'France'),
(3, 'Germany');
INSERT INTO `experts_categories` (`expertid`, `categoryid`) VALUES
(1, 1),
(1, 2),
(2, 1),
(3, 1);
INSERT INTO `experts_provinces` (`expertid`, `provinceid`) VALUES
(1, 4),
(2, 6),
(2, 7);
INSERT INTO `experts_regions` (`expertid`, `regionid`) VALUES
(1, 8),
(1, 10);
INSERT INTO `issues` (`id`, `categoryid`, `country`, `zipcode`) VALUES
(1, 2, 'Germany', 2100),
(2, 1, 'France', 1900),
(3, 1, 'Germany', 1500),
(4, 2, 'Germany', 2800),
(5, 2, 'France', 1850);
INSERT INTO `provinces` (`id`, `country`, `province`, `min_zipcode`, `max_zipcode`) VALUES
(1, 'Germany', 'Province One', 1000, 1299),
(2, 'Germany', 'Province Two', 1300, 1499),
(3, 'Germany', 'Province Three', 1500, 1999),
(4, 'Germany', 'Province Four', 2000, 2899),
(5, 'France', 'Province One', 1000, 1799),
(6, 'France', 'Province Two', 1800, 2199),
(7, 'France', 'Province Three', 2200, 2399);
INSERT INTO `regions` (`id`, `provinceid`, `region`, `min_zipcode`, `max_zipcode`) VALUES
(1, 1, 'Region One', 1000, 1099),
(2, 1, 'Region Two', 1100, 1159),
(3, 1, 'Region Three', 1160, 1299),
(4, 2, 'Region One', 1300, 1400),
(5, 2, 'Region Two', 1401, 1499),
(6, 3, 'Region One', 1500, 1699),
(7, 3, 'Region Two', 1700, 1999),
(8, 4, 'Region One', 2000, 2299),
(9, 4, 'Region Two', 2300, 2599),
(10, 4, 'Region Three', 2600, 2699),
(11, 4, 'Region Four', 2700, 2899),
(12, 5, 'Region One', 1000, 1699),
(13, 5, 'Region Two', 1700, 1799),
(14, 6, 'Region One', 1800, 2000),
(15, 6, 'Region Two', 2001, 2199),
(16, 7, 'Region One', 2200, 2299),
(17, 7, 'Region Two', 2300, 2399);
mysql> DESC `categories`;
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(300) | NO | | NULL | |
+-------+------------------+------+-----+---------+----------------+
mysql> DESC `provinces`;
+-------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------------+------+-----+---------+----------------+
| id | bigint(11) unsigned | NO | PRI | NULL | auto_increment |
| country | varchar(300) | NO | | NULL | |
| province | varchar(300) | NO | | NULL | |
| min_zipcode | int(5) unsigned | NO | | NULL | |
| max_zipcode | int(5) unsigned | NO | | NULL | |
+-------------+---------------------+------+-----+---------+----------------+
mysql> DESC `regions`;
+-------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| provinceid | int(11) unsigned | NO | | NULL | |
| region | varchar(300) | NO | | NULL | |
| min_zipcode | int(5) unsigned | NO | | NULL | |
| max_zipcode | int(5) unsigned | NO | | NULL | |
+-------------+------------------+------+-----+---------+----------------+
mysql> DESC `issues`;
+------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------------------+------+-----+---------+----------------+
| id | bigint(11) unsigned | NO | PRI | NULL | auto_increment |
| categoryid | int(11) unsigned | NO | | NULL | |
| country | varchar(150) | NO | | NULL | |
| zipcode | int(5) | NO | | NULL | |
+------------+---------------------+------+-----+---------+----------------+
mysql> DESC `experts`;
+---------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| country | varchar(150) | NO | | none | |
+---------+------------------+------+-----+---------+----------------+
mysql> DESC `experts_categories`;
+------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+-------+
| expertid | int(11) unsigned | NO | PRI | NULL | |
| categoryid | int(11) unsigned | NO | PRI | NULL | |
+------------+------------------+------+-----+---------+-------+
mysql> DESC `experts_provinces`;
+------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+-------+
| expertid | int(11) unsigned | NO | PRI | NULL | |
| provinceid | int(11) unsigned | NO | PRI | NULL | |
+------------+------------------+------+-----+---------+-------+
mysql> DESC `experts_regions`;
+----------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+---------+------+-----+---------+-------+
| expertid | int(11) | NO | PRI | NULL | |
| regionid | int(11) | NO | PRI | NULL | |
+----------+---------+------+-----+---------+-------+
mysql> SELECT * FROM `categories`;
+----+----------+
| id | name |
+----+----------+
| 1 | Software |
| 2 | Hardware |
+----+----------+
mysql> SELECT * FROM `provinces`;
+----+---------+----------------+-------------+-------------+
| id | country | province | min_zipcode | max_zipcode |
+----+---------+----------------+-------------+-------------+
| 1 | Germany | Province One | 1000 | 1299 |
| 2 | Germany | Province Two | 1300 | 1499 |
| 3 | Germany | Province Three | 1500 | 1999 |
| 4 | Germany | Province Four | 2000 | 2899 |
| 5 | France | Province One | 1000 | 1799 |
| 6 | France | Province Two | 1800 | 2199 |
| 7 | France | Province Three | 2200 | 2399 |
+----+---------+----------------+-------------+-------------+
mysql> SELECT * FROM `regions`;
+----+------------+--------------+-------------+-------------+
| id | provinceid | region | min_zipcode | max_zipcode |
+----+------------+--------------+-------------+-------------+
| 1 | 1 | Region One | 1000 | 1099 |
| 2 | 1 | Region Two | 1100 | 1159 |
| 3 | 1 | Region Three | 1160 | 1299 |
| 4 | 2 | Region One | 1300 | 1400 |
| 5 | 2 | Region Two | 1401 | 1499 |
| 6 | 3 | Region One | 1500 | 1699 |
| 7 | 3 | Region Two | 1700 | 1999 |
| 8 | 4 | Region One | 2000 | 2299 |
| 9 | 4 | Region Two | 2300 | 2599 |
| 10 | 4 | Region Three | 2600 | 2699 |
| 11 | 4 | Region Four | 2700 | 2899 |
| 12 | 5 | Region One | 1000 | 1699 |
| 13 | 5 | Region Two | 1700 | 1799 |
| 14 | 6 | Region One | 1800 | 2000 |
| 15 | 6 | Region Two | 2001 | 2199 |
| 16 | 7 | Region One | 2200 | 2299 |
| 17 | 7 | Region Two | 2300 | 2399 |
+----+------------+--------------+-------------+-------------+
mysql> SELECT * FROM `issues`;
+----+------------+---------+---------+
| id | categoryid | country | zipcode |
+----+------------+---------+---------+
| 1 | 2 | Germany | 2100 |
| 2 | 1 | France | 1900 |
| 3 | 1 | Germany | 1500 |
| 4 | 2 | Germany | 2800 |
| 5 | 2 | France | 1850 |
+----+------------+---------+---------+
mysql> SELECT * FROM `experts`;
+----+---------+
| id | country |
+----+---------+
| 1 | Germany |
| 2 | France |
| 3 | Germany |
+----+---------+
mysql> SELECT * FROM `experts_categories`;
+----------+------------+
| expertid | categoryid |
+----------+------------+
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 3 | 1 |
+----------+------------+
mysql> SELECT * FROM `experts_provinces`;
+----------+------------+
| expertid | provinceid |
+----------+------------+
| 1 | 4 |
| 2 | 6 |
| 2 | 7 |
+----------+------------+
mysql> SELECT * FROM `experts_regions`;
+----------+----------+
| expertid | regionid |
+----------+----------+
| 1 | 8 |
| 1 | 10 |
+----------+----------+
我已經設法想出了一半的解決方案。
SELECT
`i`.`id` `issue_id`,
`e`.`id` `expert_id`
FROM `issues` `i`
INNER JOIN `experts` `e`
ON `i`.`country` = `e`.`country`
INNER JOIN `experts_categories` `ec`
ON `e`.`id` = `ec`.`expertid`
AND `i`.`categoryid` = `ec`.`categoryid`
ORDER BY `e`.`id`, `ec`.`categoryid` ASC
+----------+-----------+
| issue_id | expert_id |
+----------+-----------+
| 3 | 1 |
| 1 | 1 |
| 4 | 1 |
| 2 | 2 |
| 3 | 3 |
+----------+-----------+
+----------+-----------+
| issue_id | expert_id |
+----------+-----------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
+----------+-----------+
首先,讓我們獲得一個“完全連接”,以便我們進行比較:
d) 查詢:
SELECT
`i`.`id` `issue_id`, `e`.`id` `expert_id`, `i`.`categoryid` `issue_category_id`, `ec`.`categoryid` `expert_category_id`,
`i`.`country` `issue_country`, `e`.`country` `expert_country`,
`i`.`zipcode` `issue_zipcode`,
`p`.`id` `province_id`, `p`.`min_zipcode` `province_min_zipcode`, `p`.`max_zipcode` `province_max_zipcode`,
`r`.`id` `region_id`, `r`.`min_zipcode` `region_min_zipcode`, `r`.`max_zipcode` `region_max_zipcode`
FROM `issues` `i`
INNER JOIN `experts` `e`
ON `i`.`country` = `e`.`country`
INNER JOIN `experts_categories` `ec`
ON `ec`.`expertid` = `e`.`id`
AND `i`.`categoryid` = `ec`.`categoryid`
LEFT JOIN `experts_provinces` `ep`
ON `e`.`id` = `ep`.`expertid`
LEFT JOIN `provinces` `p`
ON `ep`.`provinceid` = `p`.`id`
LEFT JOIN `experts_regions` `er`
ON `e`.`id` = `er`.`expertid`
LEFT JOIN `regions` `r`
ON `er`.`regionid` = `r`.`id`
AND `p`.`id` = `r`.`provinceid`
ORDER BY `e`.`id`,`ec`.`categoryid` ASC
e) 結果:
+----------+-----------+-------------------+--------------------+---------------+----------------+---------------+-------------+----------------------+----------------------+-----------+--------------------+--------------------+
| issue_id | expert_id | issue_category_id | expert_category_id | issue_country | expert_country | issue_zipcode | province_id | province_min_zipcode | province_max_zipcode | region_id | region_min_zipcode | region_max_zipcode |
+----------+-----------+-------------------+--------------------+---------------+----------------+---------------+-------------+----------------------+----------------------+-----------+--------------------+--------------------+
| 3 | 1 | 1 | 1 | Germany | Germany | 1500 | 4 | 2000 | 2899 | 10 | 2600 | 2699 |
| 3 | 1 | 1 | 1 | Germany | Germany | 1500 | 4 | 2000 | 2899 | 8 | 2000 | 2299 |
| 1 | 1 | 2 | 2 | Germany | Germany | 2100 | 4 | 2000 | 2899 | 10 | 2600 | 2699 |
| 1 | 1 | 2 | 2 | Germany | Germany | 2100 | 4 | 2000 | 2899 | 8 | 2000 | 2299 |
| 4 | 1 | 2 | 2 | Germany | Germany | 2800 | 4 | 2000 | 2899 | 10 | 2600 | 2699 |
| 4 | 1 | 2 | 2 | Germany | Germany | 2800 | 4 | 2000 | 2899 | 8 | 2000 | 2299 |
| 2 | 2 | 1 | 1 | France | France | 1900 | 7 | 2200 | 2399 | NULL | NULL | NULL |
| 2 | 2 | 1 | 1 | France | France | 1900 | 6 | 1800 | 2199 | NULL | NULL | NULL |
| 3 | 3 | 1 | 1 | Germany | Germany | 1500 | NULL | NULL | NULL | NULL | NULL | NULL |
+----------+-----------+-------------------+--------------------+---------------+----------------+---------------+-------------+----------------------+----------------------+-----------+--------------------+--------------------+
所以比較(b)查詢結果和(c),手動修復結果,我們可以注意到......
issue_id
編號3
不能分配給expert_id
編號1
,因為issue_id
編號1
來自國家Germany
,就像專家一樣,被分配在category_id
編號2
上,就像專家一樣,但有一個expert_id
代碼1500
和專家編號1
被分配僅從該province_id
的province
ID 號4
和regions_id
號8
和10
處理issues
。 所以regions
zip 代碼范圍從2000
到2299
和從2600
到2699
,我們的issue
zip 代碼不屬於這些區域。issue_id
number 1
可以分配給expert_id
number 1
,因為issue_id
number 1
來自國家Germany
,就像專家一樣,被分配在category_id
編號2
上,就像專家一樣,有一個 zip 代碼2100
,它在邊界之間省內的province_id
4
號和region_id
8
號,分配給expert_id
1
號覆蓋。issue_id
number 4
不能分配給expert_id
number 1
,因為issue_id
number 4
來自國家Germany
,就像專家一樣,被分配在category_id
number 4
上,但是有一個 zip 代碼2800
,它在province_id
編號的邊界內4
,但不在region_id
編號8
和10
的邊界內,它被分配為由expert_id
編號1
覆蓋issue_id
number 2
可以分配給expert_id
number 2
,因為issue_id
number 2
來自國家France
,就像專家一樣,被分配在category_id
編號1
上,就像專家一樣,有一個 zip 代碼1900
,在邊界內province_id
編號6
,分配給該專家。issue_id
number 3
可以分配給expert_id
number 3
,因為issue_id
number 3
來自國家Germany
,就像專家一樣,被分配在category_id
編號1
上,就像專家一樣。 而且,這位專家沒有任何行政區划限制。 也就是說,這位專家可以issues
所有Germany
的問題因此,我們列出了所有可以分配給experts
的issues
。
如您所見,我的半解決方案沒有考慮行政區划限制。
我不能使用過程或視圖來實現這一點,但是,如果有幫助的話,我可以將其拆分為多個查詢。
數據庫為 MySQL (5.0.1 - MySQL 社區服務器 (GPL)),編程語言為 PHP (5.1)。
我只是修改了@krubo 的答案。
如果你想要子查詢,查詢將是:
SELECT
tis.id AS issue_id,
tex.id AS expert_id,
tis.categoryid AS issue_category_id,
tex.categoryid AS expert_category_id,
tis.country AS issue_country,
tex.country AS expert_country,
tis.zipcode AS issue_zipcode,
tis.provinceid AS province_id,
tis.province_minzipcode AS province_minzipcode,
tis.province_maxzipcode AS province_maxzipcode,
tis.regionid AS region_id,
tis.region_minzipcode AS region_minzipcode,
tis.region_maxzipcode AS region_maxzipcode
FROM
(
SELECT
i.id, categoryid, i.country, zipcode,
provinces.id AS provinceid, provinces.min_zipcode AS province_minzipcode,
provinces.max_zipcode AS province_maxzipcode, regions.id AS regionid,
regions.min_zipcode AS region_minzipcode,
regions.max_zipcode AS region_maxzipcode
FROM
issues AS i
LEFT JOIN provinces ON i.country=provinces.country
AND i.zipcode BETWEEN provinces.min_zipcode AND provinces.max_zipcode
LEFT JOIN regions on provinces.id=regions.provinceid
AND i.zipcode BETWEEN regions.min_zipcode AND regions.max_zipcode
) AS tis
JOIN
(
SELECT
e.id, country, categoryid, provinceid, regionid
FROM
experts e
JOIN experts_categories ON e.id=experts_categories.expertid
LEFT JOIN experts_provinces ON e.id=experts_provinces.expertid
LEFT JOIN experts_regions ON e.id=experts_regions.expertid
) AS tex
WHERE
tis.country=tex.country
AND tis.categoryid=tex.categoryid
AND (tis.provinceid IS NULL
OR tex.provinceid IS NULL
OR tis.provinceid=tex.provinceid)
AND (tis.regionid IS NULL
OR tex.regionid IS NULL
OR tis.regionid=tex.regionid);
結果是:
+----------+-----------+-------------------+--------------------+---------------+----------------+---------------+-------------+----------------------+----------------------+-----------+--------------------+--------------------+
| issue_id | expert_id | issue_category_id | expert_category_id | issue_country | expert_country | issue_zipcode | province_id | province_min_zipcode | province_max_zipcode | region_id | region_min_zipcode | region_max_zipcode |
+----------+-----------+-------------------+--------------------+---------------+----------------+---------------+-------------+----------------------+----------------------+-----------+--------------------+--------------------+
| 1 | 1 | 2 | 2 | Germany | Germany | 2100 | 4 | 2000 | 2899 | 8 | 2000 | 2299 |
| 2 | 2 | 1 | 1 | France | France | 1900 | 6 | 2000 | 2199 | 14 | 1800 | 2000 |
| 3 | 3 | 1 | 1 | Germany | Germany | 1500 | 3 | 2000 | 1999 | 6 | 1500 | 1699 |
如果您不使用至少一個視圖來組織它,您的 SQL 將非常復雜。 嘗試使用此視圖將每個問題與省和地區匹配:
create view viewissues as
select issues.id, categoryid, issues.country, zipcode,
provinces.id as provinceid, regions.id as regionid
from issues
left join provinces on issues.country=provinces.country
and issues.zipcode between provinces.min_zipcode and provinces.max_zipcode
left join regions on provinces.id=regions.provinceid
and issues.zipcode between regions.min_zipcode and regions.max_zipcode;
此視圖根據專家的類別、省份(如果有)和地區(如果有)列出專家:
create view viewexperts as
select experts.id, country, categoryid, provinceid, regionid
from experts
join experts_categories on experts.id=experts_categories.expertid
left join experts_provinces on experts.id=experts_provinces.expertid
left join experts_regions on experts.id=experts_regions.expertid;
現在,通過基於這些視圖進行選擇,您的最終查詢可以更易於管理:
select distinct viewissues.id, viewexperts.id
from viewissues join viewexperts
where viewissues.country=viewexperts.country
and viewissues.categoryid=viewexperts.categoryid
and (viewissues.provinceid is null
or viewexperts.provinceid is null
or viewissues.provinceid=viewexperts.provinceid)
and (viewissues.regionid is null
or viewexperts.regionid is null
or viewissues.regionid=viewexperts.regionid);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.