从 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 |

我怎样才能得到所有培训和教育的员工数据而不重复

Running Example of Database can be found below

你似乎在寻找这样的东西,即使不正确,至少看起来是一个有效的查询。

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