Question

I have a collection of manifest records stored in a MySQL database. The schema is as follows:

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;

During the day there may be several manifests closed and dispatched. I can easily get all the manifests for a particular day, in the order they were dispatched. For example I can get all the manifests that were dispatched today like this.

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

This will produce data like this:

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

The carrier needs a sequence number to be included in the data we send them as well. The first one sent on a particular day should be 1, the second one 2 and so on. In this case record 4 would need a sequence number of 1, record 5 would need a number of 2, record 6 would need a sequence number of 3 and so on.

When I pull a manifest for transmission I just select it by ID

select * from manifests where id = 5

Is it possible to get MySQL to compute the ordinality of the above record and include it in the result as well? Basically I think what I need is a count of the number of records that were created at an earlier time then the record of interest, but which were also created on the same day. Is there an aggregate function that could do this, or is there some other trick I can use to achieve this with MySQL?

Was it helpful?

Solution

SET @var_record = 0;

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

is this what you are looking for?

EDIT: new query:

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;

performance wise this query is going to be faster and more efficient as compared to a sub-query approach which internally creates a in-memory temporary table.

to further optimize the above query you can create one more column closed_date DATE and create an index on this field and use this column in joins.

you can also try composite indexes on a table with EXPLAIN EXTENDEX see Optimizing Queries with EXPLAIN

if possible then create a covering index on table for the best performance as:

ALTER TABLE manifests ADD KEY ix1(closed_date, id, ... /*all columns used in select*/)

OTHER TIPS

I did come up with something that works, but I don't think it's very optimal, so if there's a better method I'm still looking for it.

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top