Korta och enkla frågor tenderar att få mer uppmärksamhet än långa/komplexa. Det beror inte på att vi inte kan svara, men med så många frågor och så lite volontärtid att ge, är det svårt att motivera tiden att läsa stora frågor.
Men jag tror att ditt grundläggande krav inte är så komplicerat. Du vill ha ett sätt att hämta rader som faller inom ett tidsintervall ELLER, om de inte är inom det intervallet, tillhandahålla de rader som ligger närmast det intervallet.
I databaser som stöder ROW_NUMBER() OVER() är detta ganska enkelt (och MySQL 8.x är planerat att stödja detta), men tills dess för att emulera row_number() kan du använda variabler och en ordnad underfråga.
Du kan testa den här lösningen här på SQL Fiddle
MySQL 5.6 Schema Setup :
CREATE TABLE `ponumber` (
`TimeStr` datetime NOT NULL,
`Value` int(11) NOT NULL,
UNIQUE KEY `uk_Times` (`TimeStr`));
INSERT INTO `PONumber` (`TimeStr`,`Value`) VALUES ('2017-09-28 10:47:55',0);
INSERT INTO `PONumber` (`TimeStr`,`Value`) VALUES ('2017-09-28 06:26:07',1217911);
INSERT INTO `PONumber` (`TimeStr`,`Value`) VALUES ('2017-09-28 05:24:18',1217906);
CREATE TABLE `batch_number` (
`TimeStr` datetime NOT NULL,
`Value` int(11) NOT NULL,
UNIQUE KEY `uk_Times` (`TimeStr`));
INSERT INTO `batch_number` (`TimeStr`,`Value`) VALUES ('2017-09-29 12:46:18',5522);
INSERT INTO `batch_number` (`TimeStr`,`Value`) VALUES ('2017-09-29 12:25:33',5521);
INSERT INTO `batch_number` (`TimeStr`,`Value`) VALUES ('2017-09-29 11:44:45',5520);
INSERT INTO `batch_number` (`TimeStr`,`Value`) VALUES ('2017-09-28 06:26:05',5519);
INSERT INTO `batch_number` (`TimeStr`,`Value`) VALUES ('2017-09-28 05:22:58',5518);
CREATE TABLE `batchweight` (
`TimeStr` datetime NOT NULL,
`Value` int(11) NOT NULL,
UNIQUE KEY `uk_Times` (`TimeStr`));
INSERT INTO `batchweight` (`TimeStr`,`Value`) VALUES ('2017-09-29 12:46:19',38985);
INSERT INTO `batchweight` (`TimeStr`,`Value`) VALUES ('2017-09-28 06:26:07',38985);
INSERT INTO `batchweight` (`TimeStr`,`Value`) VALUES ('2017-09-28 05:23:03',31002);
Fråga :
SET @bStartTime := '2017-09-29 11:10:00'
SET @bEndTime := '2017-09-29 12:48:00'
SELECT
SrcTable, TimeStr, Value
FROM (
SELECT
@row_num :=IF( @prev_value=u.SrcTable, @row_num + 1 ,1) AS RowNumber
, u.*
, @prev_value := u.SrcTable
FROM (
select 'ponumber' SrcTable , TimeStr, `Value`
from ponumber
union all
select 'batch_number' SrcTable , TimeStr, `Value`
from batch_number
union all
select 'batchweight' SrcTable , TimeStr, `Value`
from batchweight
) u
CROSS JOIN (SELECT @row_num := 1, @prev_value :='') vars
ORDER BY SrcTable, TimeStr DESC
) d
WHERE (d.TimeStr between @bStartTime and @bEndTime)
OR (TimeStr < @bStartTime AND RowNumber = 1)
Så vad detta gör är att beräkna ett "RowNumber" som börjar på 1 för den senaste raden för varje källtabell. Sedan filtreras denna härledda tabell antingen efter tidsintervallet eller efter radnumret om det inte ligger inom tidsintervallet.
Observera också att jag INTE använt UNION
men istället har använt UNION ALL
. Det är stor skillnad i prestanda och bör lära sig att använda var och en efter behov. Om du använder UNION
använd inte också select distinct
eftersom du bara slösar bort ansträngning.
Resultat :
| SrcTable | TimeStr | Value |
|--------------|----------------------|-------|
| batchweight | 2017-09-29T12:46:19Z | 38985 |
| batch_number | 2017-09-29T12:46:18Z | 5522 |
| batch_number | 2017-09-29T12:25:33Z | 5521 |
| batch_number | 2017-09-29T11:44:45Z | 5520 |
| ponumber | 2017-09-28T10:47:55Z | 0 |