1

我有一个小问题,想要一些建议。
我想要做的是从 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 秒奖金。

4

1 回答 1

2

加入而不是子查询和 IN 列表怎么样?

SELECT t1.SiteID, t2.* FROM tblmovements t1
WHERE (TicketStatus = 0 OR TicketStatus = 1)
AND t1.DateRequired BETWEEN '2013-01-01 00:00:00' AND '2013-01-31 23:59:59'
GROUP BY t1.SiteID)
INNER JOIN tblsites t2
 ON t1.SiteID = t2.ID

编辑 1 - 回复评论:

我在这里所做的是将您的 IF 评估转移到 WHERE 条件语句中。

原始查询将选择大量行,然后评估它们以写入其 SiteID 或“”。当您可以使用 where 条件缩小范围时,为什么要选择大范围?

于 2013-02-22T11:05:01.977 回答