Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Unterstützung bei bedingten SQL-Abfragen

Kurze und einfache Fragen erhalten tendenziell mehr Aufmerksamkeit als lange/komplexe. Das liegt nicht daran, dass wir sie nicht beantworten können, aber bei so vielen Fragen und so wenig ehrenamtlicher Zeit ist es schwer, die Zeit zum Lesen großer Fragen zu rechtfertigen.

Ich denke jedoch, dass Ihre Grundanforderung nicht so komplex ist. Sie möchten eine Möglichkeit, Zeilen abzurufen, die in einen Zeitbereich fallen, ODER, wenn sie nicht in diesem Bereich liegen, die diesem Bereich am nächsten liegenden Zeilen bereitzustellen.

In Datenbanken, die ROW_NUMBER() OVER() unterstützen, ist dies recht einfach (und MySQL 8.x soll dies unterstützen), aber bis dahin können Sie zur Emulation von row_number() Variablen und eine geordnete Unterabfrage verwenden.

Sie können diese Lösung hier unter SQL Fiddle testen

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

Abfrage :

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)

Dies berechnet also eine "RowNumber", die bei 1 für die neueste Zeile für jede Quelltabelle beginnt. Dann wird diese abgeleitete Tabelle entweder nach dem Zeitbereich oder nach der Zeilennummer gefiltert, wenn sie nicht innerhalb des Zeitbereichs liegt.

Beachten Sie auch, dass ich NICHT verwendet habe UNION sondern haben stattdessen UNION ALL verwendet . Es gibt einen großen Unterschied in der Leistung und Sie sollten lernen, jeden nach Bedarf zu verwenden. Bei Verwendung von UNION verwenden Sie nicht auch select distinct weil Sie nur Mühe verschwenden.

Ergebnisse :

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