在我的数据库中,我有5个包含详细信息的表格,为了从每个表格中提取详细信息,我需要再加入3个表格。
我还需要(在结果查询表中)获取一些数据(每个IdLite
总是相同的数据)并将它们添加到每一行。
我写了一个有效的查询,但它非常慢,所以我不能使用它
我曾两次使用CONCAT
:
第一次从每个细节表中获取详细信息;
第二次从其他表中获取数据(这些数据总是相同的)。
此外,CONCAT
之前的数据始终相同(对于每个IdLite
)
如何改进查询?我在考虑使用变量,但我无法做到。
(
SELECT
t.Office,
li.Year,
li.RIFNUM,
1 IdTable,
li.IdLite,
IdLiteUser,
d1.IdEvent,
CONCAT_WS('_',
IFNULL(d1.TypeT,''),
IFNULL(d1.In_Date,''),
IFNULL(d1.Out_Date,'')
) AS Dett,
CONCAT_WS('_',
IFNULL(li.Section,''),
IFNULL(li.InDate,''),
IFNULL(li.Type,''),
IFNULL(li.Subject,''),
IFNULL(li.DCU_Instance,''),
IFNULL(li.DC_Instance,'')
) AS Essential
FROM TRDetails1 d1
INNER JOIN TRUserLite lU USING (IdLite)
INNER JOIN TRLite li USING (IdLite)
INNER JOIN TR t USING(IdOffice)
WHERE lU.IdUser= '@myVarInsertedEachTime'
AND lU.Status = 0
AND d1.IdEvent NOT IN (
SELECT IdEvent
FROM TRInfo
WHERE IdUser= '@myVarInsertedEachTime'
AND IdTable = 1
AND IdEvent = d1.IdEvent
AND Date > d1.Changed)
)
UNION
(
SELECT
t.Office,
li.Year,
li.RifNum,
2 IdTable,
li.IdLite,
IdLiteUser,
d2.IdEvent,
CONCAT_WS('_',
IFNULL(DocType,''),
IFNULL(d2.Number,''),
IFNULL(d2.Side,''),
IFNULL(d2.InDate,'')
) AS Dett,
CONCAT_WS('_',
IFNULL(li.Section,''),
IFNULL(li.InDate,''),
IFNULL(li.Type,''),
IFNULL(li.Subject,''),
IFNULL(li.DCU_Instance,''),
IFNULL(li.DC_Instance,'')
) AS Essential
FROM TRDetails2 d2
INNER JOIN TRUserLite lU USING (IdLite)
INNER JOIN TRLite li USING (IdLite)
INNER JOIN TR t USING(IdOffice)
WHERE lU.IdUser= '@myVarInsertedEachTime'
AND lU.Status = 0
AND d2.IdEvent NOT IN (
SELECT IdEvent
FROM TRInfo
WHERE IdUser= lU.IdUser
AND IdTable= 2)
)
UNION
(
SELECT
t.Office,
li.Year,
li.RifNum,
3 IdTable,
li.IdLite,
IdLiteUser,
d3.IdEvent,
CONCAT_WS('_',
IFNULL(d3.UdiDate,''),
IFNULL(d3.UdiType,''),
IFNULL(d3.UdiResult,''),
IFNULL(d3.Supervisor,''),
IFNULL(d3.GroupIn,''),
IFNULL(d3.ROrder,'')
) AS Dett,
CONCAT_WS('_',
IFNULL(li.Section,''),
IFNULL(li.InDate,''),
IFNULL(li.Type,''),
IFNULL(li.Subject,''),
IFNULL(li.DCU_Instance,''),
IFNULL(li.DC_Instance,'')
) AS Essential
FROM TRDetails3 d3
INNER JOIN TRUserLite lU USING (IdLite)
INNER JOIN TRLite li USING (IdLite)
INNER JOIN TR t USING(IdOffice)
WHERE lU.IdUser= '@myVarInsertedEachTime'
AND lU.Status = 0
AND d3.IdEvent NOT IN (
SELECT IdEvent
FROM TRInfo
WHERE IdUser= lU.IdUser
AND IdTable= 3)
)
UNION
(
SELECT
t.Office,
li.Year,
li.RifNum,
4 IdTable,
li.IdLite,
IdLiteUser,
d4.IdEvent,
CONCAT_WS('_',
IFNULL(d4.Type,''),
IFNULL(d4.Number,''),
IFNULL(d4.Supervisor,''),
IFNULL(d4.PubDate,''),
IFNULL(d4.UdiDate,''),
IFNULL(d4.UdiType,''),
IFNULL(d4.Result,'')
) AS Dett,
CONCAT_WS('_',
IFNULL(li.Section,''),
IFNULL(li.InDate,''),
IFNULL(li.Type,''),
IFNULL(li.Subject,''),
IFNULL(li.DCU_Instance,''),
IFNULL(li.DC_Instance,'')
) AS Essential
FROM TRDetails4 d4
INNER JOIN TRUserLite lU USING (IdLite)
INNER JOIN TRLite li USING (IdLite)
INNER JOIN TR t USING(IdOffice)
WHERE lU.IdUser= '@myVarInsertedEachTime'
AND lU.Status = 0
AND d4.IdEvent NOT IN (
SELECT IdEvent
FROM TRInfo
WHERE IdUser= lU.IdUser
AND IdTable= 4)
)
UNION
(
SELECT
t.Office,
li.Year,
li.RifNum,
5 IdTable,
li.IdLite,
IdLiteUser,
d5.IdEvent,
CONCAT_WS('_',
IFNULL(d5.Type,''),
IFNULL(d5.Number,''),
IFNULL(d5.Supervisor,''),
IFNULL(d5.PubDate,''),
IFNULL(d5.Result,'')
) AS Dett,
CONCAT_WS('_',
IFNULL(li.Section,''),
IFNULL(li.InDate,''),
IFNULL(li.Type,''),
IFNULL(li.Subject,''),
IFNULL(li.DCU_Instance,''),
IFNULL(li.DC_Instance,'')
) AS Essential
FROM TRDetails5 d5
INNER JOIN TRUserLite lU USING (IdLite)
INNER JOIN TRLite li USING (IdLite)
INNER JOIN TR t USING(IdOffice)
WHERE lU.Idutente = '@myVarInsertedEachTime'
AND lU.Status = 0
AND d5.IdEvent NOT IN (
SELECT IdEvent
FROM TRInfo
WHERE IdUser= lU.Idutente
AND IdTable= 5)
)
ORDER BY Office, Year, RifNum, IdTable
编辑:
我的DB的结构是:
IdLite
是基本数据的ID
每个IdLite
有一个Office
,一个Year
,一个RifNum
,一个TR
。
每个IdLite
在5个详细信息表中都有许多记录(TRDetails1
,TRDetails2
,TRDetails3
,TRDetails4
,TRDetails5
)。
每个User
都有许多IdLite
(由TRUserLite
中的ref存储)并且需要知道每个event
(存储在每个5个表中)IdLite
1}}。
当User
知道详细信息时,它(rif)会存储到TRInfo
我需要检索每个IdLite
(链接到特定User
)并且他不了解的事件(来自所有5个表)。
EDIT2:
这些是我的表结构:
CREATE TABLE IF NOT EXISTS `TRDetails1` (
`IdEvent` bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`IdLite` bigint(20) NOT NULL,
`TypeT` varchar(50) DEFAULT NULL,
`In_Date` date DEFAULT NULL,
`Out_Date` date DEFAULT NULL,
`Changed` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `TRDetails2` (
`IdEvent` bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`IdLite` bigint(20) NOT NULL,
`DocType` varchar(200) DEFAULT NULL,
`Number` int(10) DEFAULT NULL,
`Side` varchar(50) DEFAULT NULL,
`InDate` date DEFAULT NULL,
`Updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `TRDetails3` (
`IdEvent` bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`IdLite` bigint(20) NOT NULL,
`UdiDate` date DEFAULT NULL,
`UdiType` varchar(50) DEFAULT NULL,
`UdiResult` varchar(200) DEFAULT NULL,
`Supervisor` varchar(50) DEFAULT NULL,
`GroupIn` varchar(50) DEFAULT NULL,
`ROrder` int(5) DEFAULT NULL,
`Updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `TRDetails4` (
`IdEvent` bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`IdLite` bigint(20) NOT NULL,
`TypeT` varchar(50) DEFAULT NULL,
`Number` int(10) DEFAULT NULL,
`Supervisor` varchar(50) DEFAULT NULL,
`PubDate` date DEFAULT NULL,
`UdiDate` date DEFAULT NULL,
`UdiType` varchar(50) DEFAULT NULL,
`Result` varchar(50) DEFAULT NULL,
`Updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `TRDetails5` (
`IdEvent` bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`IdLite` bigint(20) NOT NULL,
`TypeT` varchar(50) DEFAULT NULL,
`Number` int(10) DEFAULT NULL,
`Supervisor` varchar(50) DEFAULT NULL,
`PubDate` date DEFAULT NULL,
`Result` varchar(50) DEFAULT NULL,
`Updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `TRLite` (
`IdLite` bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`Region` char(30) NOT NULL,
`IdOffice` smallint(4) NOT NULL,
`RIFNUM` int(11) NOT NULL,
`Year` mediumint(4) NOT NULL,
`Sub` tinyint(2) DEFAULT NULL,
`Section` tinyint(2) NOT NULL,
`InDate` date NOT NULL,
`Type` varchar(50) NOT NULL,
`Subject` varchar(200) NOT NULL,
`DCU_Instance` char(1) DEFAULT NULL,
`DC_Instance` char(1) DEFAULT NULL,
`Defined` tinyint(2) DEFAULT NULL,
`DefinedDate` date DEFAULT NULL,
`Updated` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`Scroll_Table` set
('00001','00010','00011','00100','00101','00110','00111','01000','01001','01010','01011','01100','01101
','01110','01111','10000','10001','10010','10011','10100','10101','10110','10111','11000','11001','1101
0','11011','11100','11101','11110','11111') DEFAULT NULL
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `TRUserLite` (
`IdUser` bigint(20) NOT NULL,
`IdLite` bigint(20) NOT NULL,
`IdLiteUser` varchar(150) DEFAULT NULL,
`Status` tinyint(5) NOT NULL DEFAULT '0',
PRIMARY KEY (`IdUser`,`IdLite`),
KEY `IdLite` (`IdLite`)
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `TR` (
`IdOffice` smallint(4) NOT NULL PRIMARY KEY,
`IdRegion` tinyint(2) NOT NULL,
`Office` char(200) NOT NULL,
`IdWebOffice` varchar(30) NOT NULL
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `TRInfo` (
`IdInfo` bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`IdUser` bigint(20) NOT NULL,
`IdLite` bigint(20) NOT NULL,
`IdTable` tinyint(1) NOT NULL,
`IdEvent` bigint(20) NOT NULL,
`InfoDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS `Users` (
`IdUser` bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`User` varchar(50) NOT NULL,
`Status` tinyint(5) NOT NULL DEFAULT '0'
) ENGINE=InnoDB;
ALTER TABLE `TRUserLite`
ADD CONSTRAINT `TRUserLite_ibfk_1` FOREIGN KEY (`IdUser`) REFERENCES `Users` (`IdUser`),
ADD CONSTRAINT `TRUserLite_ibfk_2` FOREIGN KEY (`IdLite`) REFERENCES `TRLite` (`IdLite`);
编辑3 :(数据库插入数据标准)
每个IdLite可以有许多细节(在5个细节表中的一个或多个上)
当发生某些事情时,我会在一个(或多个)详细信息表中插入一条新记录
之后,每个用户都需要知道(仅)新的细节
为此,我将已知详细信息保存到TRInfo中,并且仅向每个用户提供新的详细信息(指向与用户链接的IdLite)。
所以我需要提取所有未知的细节。
编辑4 :(如何修改数据库插入标准)
如果我理解你的提示,你建议在知道详细信息之前插入TRInfo,并添加一个字段来检查相对用户是否已知道它。
所以我将所有细节都包含在TRInfo中,我将切断已知的。
这是你告诉我这样做的方式吗?
答案 0 :(得分:1)
现在,那就是说,您正在寻找与给定用户相关的交易。从这里,我们可以直接使用TRUserLite表开始。
从TRUserLite表中,我们可以加入IdLite ID上的相应Details表1-5,同时保留详细信息表中的IdEvent及其对应的1-5值。最后,我们可以对TRInfo表执行LEFT-JOIN,以获得相同的用户,事件和表ID#。通过左连接,它比NOT IN子选择更快。我们通过在WHERE子句中包含
来消除那些已经“完成”的记录 AND TRInfo.IdEvent IS NULL
现在,以上所述,如果准确,以下查询应该帮助你。它可能有一些您可能能够解决的小问题(别名,字段等)。
现在我将解释一下这个问题。为了简化原始查询的所有额外连接,我开始使用TRUserLite并获取符合条件的条目,而无需额外连接到TRLite和TR表。我只是加入/ UNIONing他们的细节和TRInfo来获得那些合格的记录。在加入Details表时,我将各个连接字段作为常用的“Dett”结果列。完成所有合格记录后,只有我连接回TRLite和TR才能获取最终查询的附加数据。这使得内部查询更加紧密,有限的细节,然后拉其余部分。
Recommended indexes
table index
TRUserLite ( IdUser, Status ) to optimize the WHERE clause.
TRInfo ( IdUser, IdLite, IdEvent, IdTable )
SELECT
TR.Office,
TRL.`Year`,
TRL.RIFNum,
All5.IdTable
All5.IdLite,
All5.IdLiteUser,
All5.IdEvent,
All5.IdUser,
All5.Dett,
U.User,
U.Status as UserStatus,
CONCAT_WS('_',
IFNULL( TRL.Section,''),
IFNULL( TRL.InDate,''),
IFNULL( TRL.Type,''),
IFNULL( TRL.Subject,''),
IFNULL( TRL.DCU_Instance,''),
IFNULL( TRL.DC_Instance,'') ) AS Essential
from
( SELECT
TRUL.IDUser,
TRUL.IdLite,
TRUL.IdLiteUser,
1 as IdTable,
TD1.IdEvent,
CONCAT_WS('_',
IFNULL( TD1.TypeT,''),
IFNULL( TD1.In_Date,''),
IFNULL( TD1.Out_Date,'') ) AS Dett
from
TRUserLite TRUL
JOIN TRDetails1 TD1
ON TRUL.IdLite = TD1.IdLite
LEFT JOIN TRInfo
ON TRUL.IdUser = TRInfo.IdUser
AND TRUL.IdLite = TRInfo.IdLite
AND TD1.IdEvent = TRInfo.IdEvent
AND TRInfo.IdTable = 1
where
TRUL.IdUser = '@myVarInsertedEachTime'
AND TRUL.Status = 0
AND TRInfo.IdEvent IS NULL
UNION ALL
SELECT
TRUL.IDUser,
TRUL.IdLite,
TRUL.IdLiteUser,
2 as IdTable,
TD2.IdEvent,
CONCAT_WS( '_',
IFNULL( TD2.DocType,''),
IFNULL( TD2.Number,''),
IFNULL( TD2.Side,''),
IFNULL( TD2.InDate,'') ) AS Dett
from
TRUserLite TRUL
JOIN TRDetails2 TD2
ON TRUL.IdLite = TD2.IdLite
LEFT JOIN TRInfo
ON TRUL.IdUser = TRInfo.IdUser
AND TRUL.IdLite = TRInfo.IdLite
AND TD2.IdEvent = TRInfo.IdEvent
AND TRInfo.IdTable = 2
where
TRUL.IdUser = '@myVarInsertedEachTime'
AND TRUL.Status = 0
AND TRInfo.IdEvent IS NULL
UNION ALL
SELECT
TRUL.IDUser,
TRUL.IdLite,
TRUL.IdLiteUser,
3 as IdTable,
TD3.IdEvent,
CONCAT_WS('_',
IFNULL( TD3.UdiDate,''),
IFNULL( TD3.UdiType,''),
IFNULL( TD3.UdiResult,''),
IFNULL( TD3.Supervisor,''),
IFNULL( TD3.GroupIn,''),
IFNULL( TD3.ROrder,'') ) AS Dett
from
TRUserLite TRUL
JOIN TRDetails3 TD3
ON TRUL.IdLite = TD3.IdLite
LEFT JOIN TRInfo
ON TRUL.IdUser = TRInfo.IdUser
AND TRUL.IdLite = TRInfo.IdLite
AND TD3.IdEvent = TRInfo.IdEvent
AND TRInfo.IdTable = 3
where
TRUL.IdUser = '@myVarInsertedEachTime'
AND TRUL.Status = 0
AND TRInfo.IdEvent IS NULL
UNION ALL
SELECT
TRUL.IDUser,
TRUL.IdLite,
TRUL.IdLiteUser,
4 as IdTable,
TD4.IdEvent,
CONCAT_WS('_',
IFNULL( TD4.Type,''),
IFNULL( TD4.Number,''),
IFNULL( TD4.Supervisor,''),
IFNULL( TD4.PubDate,''),
IFNULL( TD4.UdiDate,''),
IFNULL( TD4.UdiType,''),
IFNULL( TD4.Result,'') ) AS Dett
from
TRUserLite TRUL
JOIN TRDetails4 TD4
ON TRUL.IdLite = TD4.IdLite
LEFT JOIN TRInfo
ON TRUL.IdUser = TRInfo.IdUser
AND TRUL.IdLite = TRInfo.IdLite
AND TD4.IdEvent = TRInfo.IdEvent
AND TRInfo.IdTable = 4
where
TRUL.IdUser = '@myVarInsertedEachTime'
AND TRUL.Status = 0
AND TRInfo.IdEvent IS NULL
UNION ALL
SELECT
TRUL.IDUser,
TRUL.IdLite,
TRUL.IdLiteUser,
5 as IdTable,
TD5.IdEvent,
CONCAT_WS('_',
IFNULL( TD5.Type,''),
IFNULL( TD5.Number,''),
IFNULL( TD5.Supervisor,''),
IFNULL( TD5.PubDate,''),
IFNULL( TD5.Result,'') ) AS Dett
from
TRUserLite TRUL
JOIN TRDetails5 TD5
ON TRUL.IdLite = TD5.IdLite
LEFT JOIN TRInfo
ON TRUL.IdUser = TRInfo.IdUser
AND TRUL.IdLite = TRInfo.IdLite
AND TD5.IdEvent = TRInfo.IdEvent
AND TRInfo.IdTable = 5
where
TRUL.IdUser = '@myVarInsertedEachTime'
AND TRUL.Status = 0
AND TRInfo.IdEvent IS NULL ) All5
JOIN Users U
ON All5.IdUser = U.IdUser
JOIN TRLite TRL
ON All5.IdLite = TRL.IdLite
JOIN TR
ON TRL.IdOffice = TR.IdOffice
ORDER BY
TR.Office,
TRL.`Year`,
TRL.RIFNum,
All5.IdTable
(顺便说一下,我将用户表添加到联接中,以防你想要那些列......可以轻松删除)
了解原始查询对此结果的执行时间会很有趣,即使它无法解析您的查询时间。
<强>反馈强>
您目前正在寻找不在TRInfo表中的内容。如果您可以重新构造它,以便向TRInfo添加状态列,例如“IsRecordOpen”(夸大列名称)并将其设置为1,并在此时插入TRDetails表。然后,当它完成时,将标志设置为零(不再是打开的任务)。因此,这是待完成工作的每个项目的基础,它通过事件ID指向相应的详细信息表。然后,您的查询将简化为类似..
select
TR.Office,
TRL.`Year`,
TRL.RIFNum,
TRI.IdTable
TRI.IdLite,
TRUL.IdLiteUser,
TRI.IdEvent,
TRI.IdUser,
case when TRI.IdTable = 1 THEN
CONCAT_WS('_',
IFNULL( TD1.TypeT,''),
IFNULL( TD1.In_Date,''),
IFNULL( TD1.Out_Date,'') )
when TRI.IdTable = 2 THEN
CONCAT_WS( '_',
IFNULL( TD2.DocType,''),
IFNULL( TD2.Number,''),
IFNULL( TD2.Side,''),
IFNULL( TD2.InDate,'') )
when TRI.IdTable = 3 THEN
CONCAT_WS('_',
IFNULL( TD3.UdiDate,''),
IFNULL( TD3.UdiType,''),
IFNULL( TD3.UdiResult,''),
IFNULL( TD3.Supervisor,''),
IFNULL( TD3.GroupIn,''),
IFNULL( TD3.ROrder,'') )
when TRI.IdTable = 4 THEN
CONCAT_WS('_',
IFNULL( TD4.Type,''),
IFNULL( TD4.Number,''),
IFNULL( TD4.Supervisor,''),
IFNULL( TD4.PubDate,''),
IFNULL( TD4.UdiDate,''),
IFNULL( TD4.UdiType,''),
IFNULL( TD4.Result,'') )
when TRI.IdTable = 5 THEN
CONCAT_WS('_',
IFNULL( TD5.Type,''),
IFNULL( TD5.Number,''),
IFNULL( TD5.Supervisor,''),
IFNULL( TD5.PubDate,''),
IFNULL( TD5.Result,'') )
END AS Dett,
CONCAT_WS('_',
IFNULL( TRL.Section,''),
IFNULL( TRL.InDate,''),
IFNULL( TRL.Type,''),
IFNULL( TRL.Subject,''),
IFNULL( TRL.DCU_Instance,''),
IFNULL( TRL.DC_Instance,'') ) AS Essential
from
TRInfo TRI
JOIN TRLite TRL
on TRI.IdLite = TRL.IdLite
JOIN TR
on TRL.IdOffice = TR.IdOffice
JOIN TRUserLite TRUL
on TRI.IdUser = TRUL.IdUser
AND TRI.IdLite = TRUL.IdLite
AND TRUL.Status = 0
LEFT JOIN TRDetails1 TD1
ON TRI.TableID = 1
AND TRI.IdEvent = TD1.IdEvent
LEFT JOIN TRDetails2 TD2
ON TRI.TableID = 2
AND TRI.IdEvent = TD2.IdEvent
LEFT JOIN TRDetails1 TD3
ON TRI.TableID = 3
AND TRI.IdEvent = TD3.IdEvent
LEFT JOIN TRDetails1 TD4
ON TRI.TableID = 4
AND TRI.IdEvent = TD4.IdEvent
LEFT JOIN TRDetails1 TD5
ON TRI.TableID = 5
AND TRI.IdEvent = TD5.IdEvent
where
TRI.IdUser = 'the user ID you want'
AND TRI.IsRecordOpen