Mysql
 sql >> Base de données >  >> RDS >> Mysql

Assistance aux requêtes SQL conditionnelles

Les questions courtes et simples ont tendance à attirer plus d'attention que les questions longues/complexes. Ce n'est pas parce que nous ne pouvons pas répondre, mais avec tant de questions et si peu de temps bénévole à consacrer, il est difficile de justifier le temps consacré à la lecture de grandes questions.

Cependant, je pense que votre exigence de base n'est pas si complexe. Vous voulez un moyen de récupérer les lignes qui se situent dans une plage de temps OU si elles ne se trouvent pas dans cette plage, fournissez les lignes les plus proches de cette plage.

Dans les bases de données qui prennent en charge ROW_NUMBER() OVER(), c'est assez simple (et MySQL 8.x est prévu pour le supporter), mais jusqu'à ce moment, pour émuler row_number(), vous pouvez utiliser des variables et une sous-requête ordonnée.

Vous pouvez tester cette solution ici sur SQL Fiddle

Configuration du schéma 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);

Requête :

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)

Donc, cela calcule un "RowNumber" qui commence à 1 pour la ligne la plus récente de chaque table source. Ensuite, cette table dérivée est filtrée soit par la plage de temps, soit par le numéro de ligne si elle n'est pas dans la plage de temps.

Notez également que je n'ai PAS utilisé UNION mais à la place ont utilisé UNION ALL . Il y a une grande différence de performances et il faut apprendre à les utiliser en fonction des besoins. Si vous utilisez UNION n'utilisez pas également select distinct parce que vous ne faites que gaspiller vos efforts.

Résultats :

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