简体   繁体   English

在Mysql中从右表加入四个没有重复的表?

[英]Joining Four Tables without Duplicates From Right Tables in Mysql?

I have to fetch data of all users from database, the database structure is as following, which is just few columns from each table, but enough for proof of concept我必须从数据库中获取所有用户的数据,数据库结构如下,每个表中只有几列,但足以证明概念

 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`))

now I am running the query below to get the person name, IDs of his education and ID's of his training, and the last request number he has sent现在我正在运行下面的查询来获取人名、他的教育 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;

the problem is that I have Cartesian product as a result, shows result for only one employee as below问题是我有笛卡尔积,结果显示只有一名员工的结果如下

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

How can I get employee data with all his training and education without duplicates如何在没有重复的情况下获得所有培训和教育的员工数据

Running Example of Database can be found below 可以在下面找到数据库的运行示例

If you don't mind a bit of string aggregation如果你不介意一些字符串聚合

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;

Result:结果:

\nintCompNo | intCompNo | strName |字符串名称 | intReqIdList | intReqIdList | intEduIdList | intEduIdList | intTrainIdList | intTrainIdList | intTrainIds内部列车 ID\n--------: | --------: | :-------- | :-------- | :----------- | :----------- | :----------- | :----------- | :--------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------- -------------------------------------------------- ------------------------------------------ | ----------: ----------:\n    12368 | 12368 | TEST_USER | TEST_USER | 213 |第213话107, 109 | 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 | 5194, 5203, 5575, 5580, 5585, 5591, 5636, 5666, 5676, 5680, 5682, 5685, 5688, 5694, 5700, 5709, 5, 7, 5, 7, 5, 7, 50, 7, 5, 7, 50, 7, 5, 5, 5 24 24\n

A test on db<>fiddle heredb<>fiddle 的测试在这里

Or how do you feel about uniting them?或者你对联合他们有什么看法?

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 db<> 在这里摆弄

Or maybe this variation of using unions?或者也许是使用联合的这种变体?

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;

But perhaps you're more looking for a solution like this one that works in MySql 8.0 .但是,也许您更希望找到一种适用于 MySql 8.0 的解决方案。 It re-uses a CTE (Common Table Expression).它重用了 CTE(通用表表达式)。
And uses the window function ROW_NUMBER.并使用窗口函数 ROW_NUMBER。
Basically, it links the edu & requests on the same calculated row number of the bigger training table.基本上,它在更大的训练表的相同计算行号上链接 edu 和请求。

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;
\nintCompNo | intCompNo | PersonName |人名 | intReqId |请求 ID | intEduId |国际化 | intTrainId内部列车ID\n--------: | --------: | :--------- | :--------- | -------: | -------: | -------: | -------: | ---------: ---------:\n    12368 | 12368 | TEST_USER | TEST_USER | 213 |第213话107 | 107 | 5194 5194\n    12368 | 12368 | TEST_USER | TEST_USER | null || 109 | 109 | 5203 5203\n    12368 | 12368 | TEST_USER | TEST_USER | null || null || 5575 5575\n    12368 | 12368 | TEST_USER | TEST_USER | null || null || 5580 5580\n    12368 | 12368 | TEST_USER | TEST_USER | null || null || 5585 5585\n    ... ...\n\n

Test on db<>fiddle here这里测试db<>fiddle

You seem to be after something like this, which, if not correct, at least has the appearance of a valid query.你似乎在追求这样的事情,如果不正确,至少看起来是一个有效的查询。

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; 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM