Perguntas curtas e simples tendem a chamar mais atenção do que as longas/complexas. Isso não é porque não podemos responder, mas com tantas perguntas e tão pouco tempo voluntário para dar, é difícil justificar o tempo para ler grandes perguntas.
No entanto, acho que seu requisito básico não é tão complexo. Você deseja uma maneira de recuperar as linhas que se enquadram em um intervalo de tempo OU, se não estiver nesse intervalo, forneça as linhas mais próximas desse intervalo.
Em bancos de dados que suportam ROW_NUMBER() OVER() isso é bem fácil (e o MySQL 8.x está planejado para suportar isso), mas até então para emular row_number() você pode usar variáveis e uma subconsulta ordenada.
Você pode testar esta solução aqui em SQL Fiddle
Configuração do esquema MySQL 5.6 :
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);
Consulta :
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)
Então, o que isso faz é calcular um "RowNumber" que começa em 1 para a linha mais recente de cada tabela de origem. Em seguida, essa tabela derivada é filtrada pelo intervalo de tempo ou pelo número da linha, se não estiver dentro do intervalo de tempo.
Observe também que NÃO usei
UNION
mas em vez disso usou UNION ALL
. Há uma grande diferença de desempenho e deve-se aprender a usar cada um de acordo com a necessidade. Se estiver usando UNION
não use também select distinct
porque você está apenas desperdiçando esforço. Resultados :
| 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 |