Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Assistência condicional de consulta SQL


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 |