2

我有一组存储在 MySQL 数据库中的清单记录。架构如下:

CREATE TABLE `manifests` (
    `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `carrier_id` INT(10) UNSIGNED NOT NULL COMMENT 'The carrier for which this manifest is being made',
    `opened` DATETIME NOT NULL COMMENT 'Time the manifest was created',
    `closed` DATETIME NULL DEFAULT NULL COMMENT 'Time the manifest was picked up and closed',
    PRIMARY KEY (`id`),
    INDEX `manifests_to_carriers_id` (`carrier_id`),
    CONSTRAINT `manifests_to_carriers_id` FOREIGN KEY (`carrier_id`) REFERENCES `carriers` (`id`)
)
COMMENT='List of manifests that have been created by the system'
COLLATE='utf8_general_ci'
ENGINE=InnoDB;

白天可能有几个清单关闭和发送。我可以很容易地获得某一天的所有清单,按照它们发送的顺序。例如,我可以像这样获取今天发送的所有清单。

select * 
from manifests 
where date(closed) = date(now())
order by closed

这将产生如下数据:

"id"  "carrier_id"  "opened"               "closed"
"4"   "1"           "2012-07-24 11:10:06"  "2012-07-24 11:10:32"
"5"   "1"           "2012-07-24 11:10:40"  "2012-07-24 11:11:08"
"6"   "1"           "2012-07-24 11:11:17"  "2012-07-24 11:11:59"

承运人也需要在我们发送给他们的数据中包含一个序列号。在特定日期发送的第一个应该是 1,第二个应该是 2,依此类推。在这种情况下,记录 4 需要序列号 1,记录 5 需要序列号 2,记录 6 需要序列号 3,依此类推。

当我拉一个清单进行传输时,我只需按 ID 选择它

select * from manifests where id = 5

是否可以让 MySQL 计算上述记录的序数并将其包含在结果中?基本上我认为我需要的是计算在较早时间创建的记录数量,然后是感兴趣的记录,但这些记录也是在同一天创建的。是否有一个聚合函数可以做到这一点,或者我可以使用其他一些技巧来通过 MySQL 实现这一点?

4

2 回答 2

4
SET @var_record = 0;

SELECT *, (@var_record := @var_record + 1) AS ordinality
FROM manifests 
WHERE DATE(closed) = DATE(NOW())
ORDER BY closed;

这是你想要的?

编辑:新查询:

SELECT a.*, SUM(IF(b.id IS NOT NULL, 1, 0)) AS ordinality
FROM   manifests a
       LEFT JOIN manifests b
           ON (DATE(a.closed) = DATE(b.closed) AND a.closed > b.closed)
GROUP BY a.id;

在性能方面,与在内部创建内存临时表的子查询方法相比,此查询将更快、更高效。

要进一步优化上述查询,您可以再创建一列closed_date DATE并在该字段上创建索引并在连接中使用该列。

您还可以使用 EXPLAIN EXTENDEX 在表上尝试复合索引,请参阅使用 EXPLAIN 优化查询

如果可能,然后在表上创建一个覆盖索引以获得最佳性能:

ALTER TABLE manifests ADD KEY ix1(closed_date, id, ... /*all columns used in select*/)
于 2012-07-24T11:40:27.037 回答
1

我确实想出了一些可行的方法,但我认为它不是非常理想的,所以如果有更好的方法,我仍在寻找它。

SELECT *, (
    SELECT COUNT(closed) 
    FROM manifests AS b 
    WHERE DATE(b.closed) = DATE(a.closed) 
    AND b.closed <= a.closed) AS ordinality
FROM manifests AS a
WHERE a.id=5
于 2012-07-24T11:44:22.063 回答