我有一个小问题,想要一些建议。
我想要做的是从 tableA 中选择所有内容,其中 tableB 中有一个条目,其中 tableB 中的条目是表中的第一个条目,并且该条目在特定日期范围内。
因此,开始日期为 2013-01-01 00:00:00 和结束日期为 2013-01-31 23:59:59 我需要做这样的事情
SELECT * FROM tblsites WHERE ID IN(SELECT
IF(DateRequired >= '2013-01-01 00:00:00' AND DateRequired <= '2013-01-31 23:59:59', SiteID, '' ) AS SiteID FROM `tblmovements` WHERE TicketStatus IN ( 0, 1 ) GROUP BY SiteID) AND LENGTH(SiteName)>0 ORDER BY SiteName ASC
基本上,它应该返回一个站点数据列表,其中该站点在所选日期范围内首次移动。DateRequired 列是我在 tblmovements 中的移动日期,并且 tblmovements 将 SiteID 存储为列。您可以忽略工单状态,它只是一个标志,表示工单处于活动状态,它不应该有查询结果。
所以我的理论是,如果我在 tblmovements 中选择它们处于活动状态的所有票证并将它们分组到 siteid 上,那么如果 DateRequired 在我的输入日期之间,我可以让子查询仅返回站点 ID,这将允许我这样做在站点表上进行简单的 SELECT WHERE IN()。LENGTH 子句仅仅是因为 if 在 else 子句中返回零长度,所以我不想在脚本中将其过滤掉,而是在查询时过滤掉它们。
查询运行没有错误,但绝对慢得要命(30 分钟 + 并且仍在运行)我一辈子都想不出更好的写法,它可能只是周五早上的忧郁,但有任何建议可以唤醒我起来将不胜感激。
如果你能理解我上面的漫无边际的话,一个更好的完全写它的方法也很好。
编辑: 虚拟表。
--
-- Table structure for table `tblmovements`
--
CREATE TABLE IF NOT EXISTS `tblmovements` (
`ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`SiteID` bigint(20) unsigned NOT NULL,
`TicketStatus` smallint(3) NOT NULL DEFAULT '1',
`DateRequired` datetime DEFAULT NULL,
PRIMARY KEY (`ID`),
KEY `SiteID` (`SiteID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ;
--
-- Dumping data for table `tblmovements`
--
INSERT INTO `tblmovements` (`ID`, `SiteID`, `TicketStatus`, `DateRequired`) VALUES
(1, 1, 1, '2013-01-02 00:00:00'),
(2, 1, 1, '2013-01-02 00:00:00'),
(3, 1, 1, '2013-02-02 00:00:00'),
(4, 1, 1, '2013-02-02 00:00:00'),
(5, 1, 1, '2013-02-02 00:00:00'),
(6, 2, 1, '2012-02-02 00:00:00'),
(7, 2, 1, '2012-02-02 00:00:00'),
(8, 2, 1, '2012-01-20 00:00:00'),
(9, 2, 1, '2013-01-02 00:00:00'),
(10, 2, 1, '2013-01-02 00:00:00');
-- --------------------------------------------------------
--
-- Table structure for table `tblsites`
--
CREATE TABLE IF NOT EXISTS `tblsites` (
`ID` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`SiteName` varchar(100) DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
--
-- Dumping data for table `tblsites`
--
INSERT INTO `tblsites` (`ID`, `SiteName`) VALUES
(1, 'Site 1'),
(2, 'Site 2');
编辑2:
好的,史蒂夫的建议我已经把查询改成了这个
SELECT tblmovements.SiteID, tblsites.SiteName FROM tblmovements
INNER JOIN tblsites
ON tblmovements.SiteID = tblsites.ID
WHERE (tblmovements.TicketStatus = 0 OR tblmovements.TicketStatus = 1)
AND tblmovements.DateRequired>='2013-01-01 00:00:00' AND tblmovements.DateRequired<='2013-01-31 23:59:59'
GROUP BY tblmovements.SiteID
现在是半工作状态。我现在遇到的问题是,这只是选择该日期范围之间是否有票。我现在需要做的只是如果 tblmovements 中的条目是该表中该站点 ID 的第一次出现,则返回结果集。如果您返回主查询,您会注意到子选择上有一个 IF。
编辑 3
是的,我想我已经根据史蒂夫的输入和非星期五早上的白痴突然闪现了它。
SELECT tblmovements.SiteID, tblsites.SiteName FROM tblmovements
INNER JOIN tblsites
ON tblmovements.SiteID = tblsites.ID
WHERE (tblmovements.TicketStatus = 0 OR tblmovements.TicketStatus = 1)
AND tblmovements.DateRequired>='2013-01-01 00:00:00' AND tblmovements.DateRequired<='2013-01-31 23:59:59'
AND (SELECT COUNT(*) FROM tblmovements t3 WHERE t3.DateRequired<'2013-01-01 00:00:00' AND t3.SiteID=tblmovements.SiteID)<=0
GROUP BY tblmovements.SiteID
添加了一个额外的条件,只在开始日期之前给我一个票数,所以理论上如果它返回一个结果集,其中在我要求的日期之间有票并且在开始日期之前没有票,那么所有返回的 siteid 应该是我的要求。
到目前为止的测试正在返回我期望的数据集,这很好,而且它的查询执行时间明显更快 0.5711 秒奖金。