sql >> Databáze >  >> RDS >> Mysql

Podmíněná pomoc s dotazem SQL

Krátké a jednoduché otázky mají tendenci získat více pozornosti než ty dlouhé/složité. Není to proto, že bychom nedokázali odpovědět, ale s tolika otázkami a tak malým dobrovolným časem, který můžeme věnovat, je těžké ospravedlnit čas na čtení velkých otázek.

Myslím si však, že váš základní požadavek není tak složitý. Chcete způsob, jak načíst řádky, které spadají do časového rozsahu, NEBO pokud nejsou v tomto rozsahu, poskytnout řádky nejbližší tomuto rozsahu.

V databázích, které podporují ROW_NUMBER() OVER() je to docela snadné (a MySQL 8.x je plánováno to podporovat), ale do té doby můžete k emulaci row_number() používat proměnné a uspořádaný poddotaz.

Toto řešení si můžete vyzkoušet zde na SQL Fiddle

Nastavení schématu 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);

Dotaz :

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)

Takže to, co to udělá, je vypočítat "RowNumber", které začíná na 1 pro nejnovější řádek pro každou zdrojovou tabulku. Poté je tato odvozená tabulka filtrována buď podle časového rozsahu, nebo podle čísla řádku, pokud není v časovém rozsahu.

Všimněte si také, že NEPOUŽÍVÁM UNION ale místo toho použili UNION ALL . Existuje velký rozdíl ve výkonu a měli byste se naučit používat každý podle potřeby. Pokud používáte UNION nepoužívejte také select distinct protože jen plýtváte úsilím.

Výsledky :

|     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. Jak získat přístup k Oracle DB ve VirtualBoxu z hostitele (Windows)

  2. Příklad funkce Oracle k získání počtu dní mezi dvěma daty

  3. Jak Atan() funguje v PostgreSQL

  4. Získejte seznam podporovaných časových pásem v SQL Server (T-SQL)