从 Mysql 中的右表连接四个表而不重复?
Joining Four Tables without Duplicates From Right Tables in Mysql?
我必须从数据库中获取所有用户的数据,数据库结构如下,每个 table 只有几列,但足以证明概念
CREATE TABLE `tblpersonal` (
`intCompNo` int(11) NOT NULL,
`strName` varchar(500) COLLATE utf8_bin NOT NULL)
CREATE TABLE `tbledu` (
`intEduId` int(11) NOT NULL AUTO_INCREMENT,
`intCompNo` int(11) NOT NULL,
`intEduType` varchar(64) COLLATE utf8_bin DEFAULT NULL)
CREATE TABLE `tbltrain` (
`intTrainId` int(5) NOT NULL AUTO_INCREMENT,
`intCompNo` int(5) NOT NULL,
`strCourseName` varchar(300) COLLATE utf8_bin NOT NULL)
CREATE TABLE `tblrequests` (
`intReqId` int(11) NOT NULL AUTO_INCREMENT,
`intCompNo` int(11) NOT NULL,
`strNotes` varchar(512) COLLATE utf8_bin NOT NULL,
`dateOfSubmit` datetime NOT NULL,
PRIMARY KEY (`intReqId`))
现在我是运行下面的查询,以获取人名、他的教育 ID 和他的培训 ID,以及他发送的最后一个请求编号
SELECT tblpersonal.intCompNo, tblpersonal.strName, tbltrain.intTrainId, tbledu.intEduId, tblrequests.intReqId
FROM tblpersonal
LEFT JOIN tblrequests ON tblpersonal.intCompNo = tblrequests.intCompNo
AND tblrequests.intReqId = (SELECT MAX(req.intReqId) FROM tblrequests AS req WHERE req.intCompNo = tblpersonal.intCompNo)
LEFT JOIN tbltrain ON tblpersonal.intCompNo = tbltrain.intCompNo
LEFT JOIN tbledu ON tblpersonal.intCompNo = tbledu.intCompNo
WHERE tblrequests.intReqId IS NOT NULL
AND tblpersonal.intCompNo = 12368
GROUP BY tblpersonal.intCompNo, tbltrain.intTrainId, tbledu.intEduId
ORDER BY tblpersonal.intCompNo, tbledu.intEduId, tbltrain.intTrainid;
问题是我的结果是笛卡尔积,仅显示一名员工的结果如下
+-----------+--------------------------+------------+----------+----------+
| intCompNo | strName | intTrainId | intEduId | intReqId |
+-----------+--------------------------+------------+----------+----------+
| 12368 | ????? ???? ???? ???????? | 5194 | 107 | 388 |
| 12368 | ????? ???? ???? ???????? | 5203 | 107 | 388 |
| 12368 | ????? ???? ???? ???????? | 5575 | 107 | 388 |
| 12368 | ????? ???? ???? ???????? | 5580 | 107 | 388 |
| 12368 | ????? ???? ???? ???????? | 5585 | 107 | 388 |
| 12368 | ????? ???? ???? ???????? | 5591 | 107 | 388 |
| 12368 | ????? ???? ???? ???????? | 5636 | 107 | 388 |
| 12368 | ????? ???? ???? ???????? | 5666 | 107 | 388 |
| 12368 | ????? ???? ???? ???????? | 5676 | 107 | 388 |
我怎样才能得到所有培训和教育的员工数据而不重复
你似乎在寻找这样的东西,即使不正确,至少看起来是一个有效的查询。
SELECT DISTINCT p.intCompNo
, p.strName
, t.intTrainId
, e.intEduId
, r.intReqId
FROM tblpersonal p
LEFT
JOIN tblrequests r
ON r.intCompNo = p.intCompNo
JOIN
( SELECT req.intCompNo
, MAX(req.intReqId) intreqid
FROM tblrequests req
GROUP
BY req.intCompNo
) x
ON x.intreqid = r.intReqId
AND x.intCompNo = p.intCompNo)
LEFT
JOIN tbltrain t
ON t.intCompNo = p.intCompNo
LEFT
JOIN tbledu e
ON e.intCompNo = p.intCompNo
WHERE r.intReqId IS NOT NULL
AND p.intCompNo = 12368
ORDER
BY p.intCompNo
, e.intEduId
, t.intTrainid;
如果您不介意一点字符串聚合
SELECT
tblpersonal.intCompNo
,tblpersonal.strName
,GROUP_CONCAT(DISTINCT tblrequests.intReqId ORDER BY tblrequests.intReqId SEPARATOR ', ') AS intReqIdList
,GROUP_CONCAT(DISTINCT tbledu.intEduId ORDER BY tbledu.intEduId SEPARATOR ', ') AS intEduIdList
,GROUP_CONCAT(DISTINCT tbltrain.intTrainId ORDER BY tbltrain.intTrainId SEPARATOR ', ') AS intTrainIdList
,COUNT(DISTINCT tbltrain.intTrainId) AS intTrainIds
FROM tblpersonal
INNER JOIN tblrequests
ON tblrequests.intCompNo = tblpersonal.intCompNo
AND tblrequests.intReqId = (SELECT MAX(req.intReqId) FROM tblrequests AS req WHERE req.intCompNo = tblpersonal.intCompNo)
LEFT JOIN tbltrain
ON tbltrain.intCompNo = tblpersonal.intCompNo
LEFT JOIN tbledu
ON tbledu.intCompNo = tblpersonal.intCompNo
WHERE tblpersonal.intCompNo = 12368
GROUP BY
tblpersonal.intCompNo
,tblpersonal.strName
ORDER BY tblpersonal.intCompNo;
结果:
intCompNo | strName | intReqIdList | intEduIdList | intTrainIdList | intTrainIds
--------: | :-------- | :----------- | :----------- | :--------------------------------------------------------------------------------------------------------------------------------------------- | ----------:
12368 | TEST_USER | 213 | 107, 109 | 5194, 5203, 5575, 5580, 5585, 5591, 5636, 5666, 5676, 5680, 5682, 5685, 5688, 5694, 5700, 5704, 5709, 5713, 5718, 5720, 5722, 5725, 7008, 7014 | 24
对 db<>fiddle here
的测试
或者你觉得他们团结起来怎么样?
SET @CompNo = 12368;
SELECT
person.intCompNo
,person.strName AS PersonName
,Src.Source
,Src.SrcId
FROM
(
SELECT req.intCompNo, 'req' AS Source, MAX(req.intReqId) AS SrcId
FROM tblrequests req
WHERE req.intCompNo = @CompNo
GROUP BY req.intCompNo
UNION ALL
SELECT train.intCompNo, 'trn', train.intTrainId
FROM tbltrain AS train
WHERE train.intCompNo = @CompNo
UNION ALL
SELECT edu.intCompNo, 'edu', edu.intEduId
FROM tbledu AS edu
WHERE edu.intCompNo = @CompNo
) AS Src
INNER JOIN tblpersonal AS person
ON Src.intCompNo = person.intCompNo
ORDER BY
person.intCompNo,
Src.Source,
Src.SrcId;
db<>fiddle here
或者也许是这种使用联合的变体?
SET @CompNo = 12368;
SELECT
person.intCompNo
,person.strName AS PersonName
,Src.intReqId
,Src.intTrainId
,Src.intEduId
FROM
(
SELECT req.intCompNo
, MAX(req.intReqId) AS intReqId
, 0 AS intTrainId
, 0 AS intEduId
FROM tblrequests req
WHERE req.intCompNo = @CompNo
GROUP BY req.intCompNo
UNION ALL
SELECT train.intCompNo
, 0 AS intReqId
, train.intTrainId
, 0 AS intEduId
FROM tbltrain AS train
WHERE train.intCompNo = @CompNo
UNION ALL
SELECT edu.intCompNo
, 0 AS intReqId
, 0 AS intTrainId
, edu.intEduId
FROM tbledu AS edu
WHERE edu.intCompNo = @CompNo
) AS Src
INNER JOIN tblpersonal AS person
ON Src.intCompNo = person.intCompNo
ORDER BY
person.intCompNo,
Src.intTrainId, Src.intEduId, Src.intReqId;
但也许您更想寻找像这样适用于 MySql 8.0 的解决方案。
它重新使用了 CTE(通用 Table 表达式)。
并使用 window 函数 ROW_NUMBER.
基本上,它将 edu 和请求链接到更大训练的相同计算行号 table。
WITH PERSONAL AS
(
SELECT intCompNo, strName
FROM tblpersonal
WHERE intCompNo IN (12368)
)
SELECT
person.intCompNo
,person.strName AS PersonName
,req.intReqId
,edu.intEduId
,trn.intTrainId
FROM PERSONAL AS person
LEFT JOIN
(
SELECT t.intCompNo, t.intTrainId
, ROW_NUMBER()
OVER (PARTITION BY t.intCompNo
ORDER BY t.intTrainId) AS rn
FROM tbltrain AS t
JOIN PERSONAL p
ON p.intCompNo = t.intCompNo
) AS trn
ON trn.intCompNo = person.intCompNo
LEFT JOIN
(
SELECT t.intCompNo
, MAX(t.intReqId) AS intReqId
, 1 AS rn
FROM tblrequests t
JOIN PERSONAL p
ON p.intCompNo = t.intCompNo
GROUP BY t.intCompNo
) AS req
ON req.intCompNo = trn.intCompNo
AND req.rn = trn.rn
LEFT JOIN
(
SELECT t.intCompNo, t.intEduId
, ROW_NUMBER()
OVER (PARTITION BY t.intCompNo
ORDER BY t.intEduId) AS rn
FROM tbledu AS t
JOIN PERSONAL p
ON p.intCompNo = p.intCompNo
) AS edu
ON edu.intCompNo = trn.intCompNo
AND edu.rn = trn.rn
ORDER BY person.intCompNo;
intCompNo | PersonName | intReqId | intEduId | intTrainId
--------: | :--------- | -------: | -------: | ---------:
12368 | TEST_USER | 213 | 107 | 5194
12368 | TEST_USER | null | 109 | 5203
12368 | TEST_USER | null | null | 5575
12368 | TEST_USER | null | null | 5580
12368 | TEST_USER | null | null | 5585
...
测试 db<>fiddle here
我必须从数据库中获取所有用户的数据,数据库结构如下,每个 table 只有几列,但足以证明概念
CREATE TABLE `tblpersonal` (
`intCompNo` int(11) NOT NULL,
`strName` varchar(500) COLLATE utf8_bin NOT NULL)
CREATE TABLE `tbledu` (
`intEduId` int(11) NOT NULL AUTO_INCREMENT,
`intCompNo` int(11) NOT NULL,
`intEduType` varchar(64) COLLATE utf8_bin DEFAULT NULL)
CREATE TABLE `tbltrain` (
`intTrainId` int(5) NOT NULL AUTO_INCREMENT,
`intCompNo` int(5) NOT NULL,
`strCourseName` varchar(300) COLLATE utf8_bin NOT NULL)
CREATE TABLE `tblrequests` (
`intReqId` int(11) NOT NULL AUTO_INCREMENT,
`intCompNo` int(11) NOT NULL,
`strNotes` varchar(512) COLLATE utf8_bin NOT NULL,
`dateOfSubmit` datetime NOT NULL,
PRIMARY KEY (`intReqId`))
现在我是运行下面的查询,以获取人名、他的教育 ID 和他的培训 ID,以及他发送的最后一个请求编号
SELECT tblpersonal.intCompNo, tblpersonal.strName, tbltrain.intTrainId, tbledu.intEduId, tblrequests.intReqId
FROM tblpersonal
LEFT JOIN tblrequests ON tblpersonal.intCompNo = tblrequests.intCompNo
AND tblrequests.intReqId = (SELECT MAX(req.intReqId) FROM tblrequests AS req WHERE req.intCompNo = tblpersonal.intCompNo)
LEFT JOIN tbltrain ON tblpersonal.intCompNo = tbltrain.intCompNo
LEFT JOIN tbledu ON tblpersonal.intCompNo = tbledu.intCompNo
WHERE tblrequests.intReqId IS NOT NULL
AND tblpersonal.intCompNo = 12368
GROUP BY tblpersonal.intCompNo, tbltrain.intTrainId, tbledu.intEduId
ORDER BY tblpersonal.intCompNo, tbledu.intEduId, tbltrain.intTrainid;
问题是我的结果是笛卡尔积,仅显示一名员工的结果如下
+-----------+--------------------------+------------+----------+----------+
| intCompNo | strName | intTrainId | intEduId | intReqId |
+-----------+--------------------------+------------+----------+----------+
| 12368 | ????? ???? ???? ???????? | 5194 | 107 | 388 |
| 12368 | ????? ???? ???? ???????? | 5203 | 107 | 388 |
| 12368 | ????? ???? ???? ???????? | 5575 | 107 | 388 |
| 12368 | ????? ???? ???? ???????? | 5580 | 107 | 388 |
| 12368 | ????? ???? ???? ???????? | 5585 | 107 | 388 |
| 12368 | ????? ???? ???? ???????? | 5591 | 107 | 388 |
| 12368 | ????? ???? ???? ???????? | 5636 | 107 | 388 |
| 12368 | ????? ???? ???? ???????? | 5666 | 107 | 388 |
| 12368 | ????? ???? ???? ???????? | 5676 | 107 | 388 |
我怎样才能得到所有培训和教育的员工数据而不重复
你似乎在寻找这样的东西,即使不正确,至少看起来是一个有效的查询。
SELECT DISTINCT p.intCompNo
, p.strName
, t.intTrainId
, e.intEduId
, r.intReqId
FROM tblpersonal p
LEFT
JOIN tblrequests r
ON r.intCompNo = p.intCompNo
JOIN
( SELECT req.intCompNo
, MAX(req.intReqId) intreqid
FROM tblrequests req
GROUP
BY req.intCompNo
) x
ON x.intreqid = r.intReqId
AND x.intCompNo = p.intCompNo)
LEFT
JOIN tbltrain t
ON t.intCompNo = p.intCompNo
LEFT
JOIN tbledu e
ON e.intCompNo = p.intCompNo
WHERE r.intReqId IS NOT NULL
AND p.intCompNo = 12368
ORDER
BY p.intCompNo
, e.intEduId
, t.intTrainid;
如果您不介意一点字符串聚合
SELECT
tblpersonal.intCompNo
,tblpersonal.strName
,GROUP_CONCAT(DISTINCT tblrequests.intReqId ORDER BY tblrequests.intReqId SEPARATOR ', ') AS intReqIdList
,GROUP_CONCAT(DISTINCT tbledu.intEduId ORDER BY tbledu.intEduId SEPARATOR ', ') AS intEduIdList
,GROUP_CONCAT(DISTINCT tbltrain.intTrainId ORDER BY tbltrain.intTrainId SEPARATOR ', ') AS intTrainIdList
,COUNT(DISTINCT tbltrain.intTrainId) AS intTrainIds
FROM tblpersonal
INNER JOIN tblrequests
ON tblrequests.intCompNo = tblpersonal.intCompNo
AND tblrequests.intReqId = (SELECT MAX(req.intReqId) FROM tblrequests AS req WHERE req.intCompNo = tblpersonal.intCompNo)
LEFT JOIN tbltrain
ON tbltrain.intCompNo = tblpersonal.intCompNo
LEFT JOIN tbledu
ON tbledu.intCompNo = tblpersonal.intCompNo
WHERE tblpersonal.intCompNo = 12368
GROUP BY
tblpersonal.intCompNo
,tblpersonal.strName
ORDER BY tblpersonal.intCompNo;
结果:
intCompNo | strName | intReqIdList | intEduIdList | intTrainIdList | intTrainIds --------: | :-------- | :----------- | :----------- | :--------------------------------------------------------------------------------------------------------------------------------------------- | ----------: 12368 | TEST_USER | 213 | 107, 109 | 5194, 5203, 5575, 5580, 5585, 5591, 5636, 5666, 5676, 5680, 5682, 5685, 5688, 5694, 5700, 5704, 5709, 5713, 5718, 5720, 5722, 5725, 7008, 7014 | 24
对 db<>fiddle here
的测试或者你觉得他们团结起来怎么样?
SET @CompNo = 12368;
SELECT
person.intCompNo
,person.strName AS PersonName
,Src.Source
,Src.SrcId
FROM
(
SELECT req.intCompNo, 'req' AS Source, MAX(req.intReqId) AS SrcId
FROM tblrequests req
WHERE req.intCompNo = @CompNo
GROUP BY req.intCompNo
UNION ALL
SELECT train.intCompNo, 'trn', train.intTrainId
FROM tbltrain AS train
WHERE train.intCompNo = @CompNo
UNION ALL
SELECT edu.intCompNo, 'edu', edu.intEduId
FROM tbledu AS edu
WHERE edu.intCompNo = @CompNo
) AS Src
INNER JOIN tblpersonal AS person
ON Src.intCompNo = person.intCompNo
ORDER BY
person.intCompNo,
Src.Source,
Src.SrcId;
db<>fiddle here
或者也许是这种使用联合的变体?
SET @CompNo = 12368;
SELECT
person.intCompNo
,person.strName AS PersonName
,Src.intReqId
,Src.intTrainId
,Src.intEduId
FROM
(
SELECT req.intCompNo
, MAX(req.intReqId) AS intReqId
, 0 AS intTrainId
, 0 AS intEduId
FROM tblrequests req
WHERE req.intCompNo = @CompNo
GROUP BY req.intCompNo
UNION ALL
SELECT train.intCompNo
, 0 AS intReqId
, train.intTrainId
, 0 AS intEduId
FROM tbltrain AS train
WHERE train.intCompNo = @CompNo
UNION ALL
SELECT edu.intCompNo
, 0 AS intReqId
, 0 AS intTrainId
, edu.intEduId
FROM tbledu AS edu
WHERE edu.intCompNo = @CompNo
) AS Src
INNER JOIN tblpersonal AS person
ON Src.intCompNo = person.intCompNo
ORDER BY
person.intCompNo,
Src.intTrainId, Src.intEduId, Src.intReqId;
但也许您更想寻找像这样适用于 MySql 8.0 的解决方案。
它重新使用了 CTE(通用 Table 表达式)。
并使用 window 函数 ROW_NUMBER.
基本上,它将 edu 和请求链接到更大训练的相同计算行号 table。
WITH PERSONAL AS
(
SELECT intCompNo, strName
FROM tblpersonal
WHERE intCompNo IN (12368)
)
SELECT
person.intCompNo
,person.strName AS PersonName
,req.intReqId
,edu.intEduId
,trn.intTrainId
FROM PERSONAL AS person
LEFT JOIN
(
SELECT t.intCompNo, t.intTrainId
, ROW_NUMBER()
OVER (PARTITION BY t.intCompNo
ORDER BY t.intTrainId) AS rn
FROM tbltrain AS t
JOIN PERSONAL p
ON p.intCompNo = t.intCompNo
) AS trn
ON trn.intCompNo = person.intCompNo
LEFT JOIN
(
SELECT t.intCompNo
, MAX(t.intReqId) AS intReqId
, 1 AS rn
FROM tblrequests t
JOIN PERSONAL p
ON p.intCompNo = t.intCompNo
GROUP BY t.intCompNo
) AS req
ON req.intCompNo = trn.intCompNo
AND req.rn = trn.rn
LEFT JOIN
(
SELECT t.intCompNo, t.intEduId
, ROW_NUMBER()
OVER (PARTITION BY t.intCompNo
ORDER BY t.intEduId) AS rn
FROM tbledu AS t
JOIN PERSONAL p
ON p.intCompNo = p.intCompNo
) AS edu
ON edu.intCompNo = trn.intCompNo
AND edu.rn = trn.rn
ORDER BY person.intCompNo;
intCompNo | PersonName | intReqId | intEduId | intTrainId --------: | :--------- | -------: | -------: | ---------: 12368 | TEST_USER | 213 | 107 | 5194 12368 | TEST_USER | null | 109 | 5203 12368 | TEST_USER | null | null | 5575 12368 | TEST_USER | null | null | 5580 12368 | TEST_USER | null | null | 5585 ...
测试 db<>fiddle here