sql >> Databasteknik >  >> RDS >> Mysql

Villkorlig hjälp med SQL-frågor

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 |



  1. UTF-8 MySQL och Charset

  2. Hur gör mysql omvänd upplösning av IP-adresser?

  3. Hur man hittar standardfilplatsen för datafiler och loggfiler i SQL Server

  4. Hur kan jag använda COALESCE() i WHERE-satsen optimalt?