条件SQL查询帮助

时间:2017-09-29 18:49:21

标签: mysql sql

问题

使用下面提供的所有示例和数据, 还有另一种方法 可以获得预期结果,而不是UNION表?

我的麻烦

基本上我需要有条件逻辑:

  1. 如果在 定义的时间段内找到记录 ,则从表中获取所有记录(多个)

  2. 如果在 定义的时间段内找不到记录 ,则从表格中获取最新的1条记录。 定义的时间段

  3. 步骤

    只需创建表格并按照我在下面列出的逻辑插入数据,然后运行我在每个示例中提供的每个查询,您就可以轻松模拟我所指的内容。

    上下文&澄清

    • 也许使用临时/内存表代替@Now~变量,并在相关临时表中有TRUE条件UNION,或者可能是一些精心设计(或对某些人而言可能很简单)数据表JOIN方法?

    • 我指的是" 定义的时间段"下面或单词意思相同,并且通过这些话我说的是特定的开始时间和特定的结束时间以及这两点之间的所有时间 - 这就是我在使用时所谈论的内容这个词。

      • 有一个报告系统可以生成这些开始和结束时间帧,并且我已经调用了存储过程中的逻辑,并且传入了日期时间。

        • 我只提供了部分存储过程,并从中提出了一些选择查询,以提供问题的示例以及预期或需要的结果。

    创建数据

    通过以下内容,您可以在MySQL数据库中创建三个表格,这也将填充我在运行的查询中使用的数据,以显示结果,以及每个表格下方的数据,以便您可以跟随并使用数据甚至可能用解决方案或一两个指针帮我解决。

    注意: 在确定将<DBName>更改为MySQL实例上的实际数据库名称或架构之前。

    USE <DBName>; 
    CREATE TABLE `ponumber` (
      `TimeStr` datetime NOT NULL,
      `Value` int(11) NOT NULL,
      UNIQUE KEY `uk_Times` (`TimeStr`));
    
    CREATE TABLE `batch_number` (
      `TimeStr` datetime NOT NULL,
      `Value` int(11) NOT NULL,
      UNIQUE KEY `uk_Times` (`TimeStr`));
    
    CREATE TABLE `batchweight` (
      `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);
    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);
    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);
    

    查询一个

    USE <DBName>; 
    
    SET @bStartTime   = '2017-09-29 11:10:00';
    SET @bEndTime     = '2017-09-29 12:48:00';
    
    SELECT TimeStr, CONCAT('Set Load Number: ',Value) AS Value
    FROM ponumber 
    WHERE TimeStr BETWEEN @bStartTime AND @bEndTime
    
    UNION 
    
    SELECT TimeStr, CONCAT('Set Batch Number: ',Value) AS Value
    FROM batch_number 
    WHERE TimeStr BETWEEN @bStartTime AND @bEndTime
    
    UNION 
    
    SELECT TimeStr, 
        CONCAT('Batch Weight: ',Value) AS Value
    FROM batchweight
    WHERE TimeStr BETWEEN @bStartTime AND @bEndTime
    
    ORDER BY TimeStr;
    

    查询一个结果

    enter image description here

    正如您所看到的,没有Set Load Number,因为PONumber表中没有@bStartTime@bEndTime变量定义的时间记录 - 定义的时间周期。

    如果在定义的时间段内PONumber表中没有数据记录,那么结果应该列出该表中的最新记录,即使那些记录超出定义的时间段,所以我构建了查询二

    查询二

    USE <DBName>; 
    SET @bStartTime   = '2017-09-29 11:10:00';
    SET @bEndTime     = '2017-09-29 12:48:00';
    
    SET @LastPONumber = (SELECT Value FROM PONumber ORDER BY TimeStr DESC LIMIT 1); 
    SET @NowPONumber  = (SELECT Value FROM PONumber WHERE TimeStr BETWEEN @bStartTime AND @bEndTime ORDER BY TimeStr DESC LIMIT 1);
    SET @LastPONumTimeStr  = (SELECT TimeStr FROM PONumber ORDER BY TimeStr DESC LIMIT 1); 
    SET @NowPONumTimeStr   = (SELECT TimeStr FROM PONumber WHERE TimeStr BETWEEN @bStartTime AND @bEndTime ORDER BY TimeStr DESC LIMIT 1);
    
    SELECT DISTINCT TimeStr, Value FROM  
        (SELECT 
            CASE 
            WHEN TimeStr = 1 THEN 
                (SELECT @NowPONumTimeStr AS TimeStr) 
                    ELSE 
                (SELECT @LastPONumTimeStr AS TimeStr)
                    END AS TimeStr,
            CASE 
            WHEN Value = 1 THEN 
                (SELECT (CONCAT('Set Load Number: ',@NowPONumber)) AS Value) 
                    ELSE 
                (SELECT (CONCAT('Set Load Number: ',@LastPONumber)) AS Value)
                    END AS Value
        FROM PONumber) AS X
    
    UNION 
    
    SELECT TimeStr, CONCAT('Set Batch Number: ',Value) AS Value
    FROM batch_number 
    WHERE TimeStr BETWEEN @bStartTime AND @bEndTime
    
    UNION 
    
    SELECT TimeStr, 
        CONCAT('Batch Weight: ',Value) AS Value
    FROM batchweight
    WHERE TimeStr BETWEEN @bStartTime AND @bEndTime
    
    ORDER BY TimeStr;
    

    查询两个结果

    enter image description here

    所以查询二是我创建@LastPONumber@NowPONumber@LastPONumTimeStr@NowPONumTimeStr变量的位置,并将这些值设置为使用SELECTORDER BY DESC的{​​{1}}查询结果取决于使用LIMIT 1表达式的条件。

    结果现在显示最近的CASE WHEN表记录,因为在定义的时间段之间没有找到,因此这允许它在定义的时间段之外进一步返回。

    现在有一个要求,如果在定义的时间段内PONumber表中没有数据记录列出最新记录,就像在中使用Batch_Number表一样查询二,因此我使用相同条件PONumber逻辑等构建了查询三,因为{strong>查询二用于CASE WHEN

    查询三

    PONumber

    查询三个结果

    enter image description here

    查询三的结果检测到USE <DBName>; SET @bStartTime = '2017-09-29 11:10:00'; SET @bEndTime = '2017-09-29 12:48:00'; ## - PONumber Table Variables SET @LastPONumber = (SELECT Value FROM PONumber ORDER BY TimeStr DESC LIMIT 1); SET @NowPONumber = (SELECT Value FROM PONumber WHERE TimeStr BETWEEN @bStartTime AND @bEndTime ORDER BY TimeStr DESC LIMIT 1); SET @LastPONumTimeStr = (SELECT TimeStr FROM PONumber ORDER BY TimeStr DESC LIMIT 1); SET @NowPONumTimeStr = (SELECT TimeStr FROM PONumber WHERE TimeStr BETWEEN @bStartTime AND @bEndTime ORDER BY TimeStr DESC LIMIT 1); ## - Batch_Number Table Variables SET @LastBatNumber = (SELECT Value FROM Batch_Number ORDER BY TimeStr DESC LIMIT 1); SET @NowBatNumber = (SELECT Value FROM Batch_Number WHERE TimeStr BETWEEN @bStartTime AND @bEndTime ORDER BY TimeStr DESC LIMIT 1); SET @LastBatNumTimeStr = (SELECT TimeStr FROM Batch_Number ORDER BY TimeStr DESC LIMIT 1); SET @NowBatNumTimeStr = (SELECT TimeStr FROM Batch_Number WHERE TimeStr BETWEEN @bStartTime AND @bEndTime ORDER BY TimeStr DESC LIMIT 1); SELECT DISTINCT TimeStr, Value FROM (SELECT CASE WHEN TimeStr = 1 THEN (SELECT @NowPONumTimeStr AS TimeStr) ELSE (SELECT @LastPONumTimeStr AS TimeStr) END AS TimeStr, CASE WHEN Value = 1 THEN (SELECT (CONCAT('Set Load Number: ',@NowPONumber)) AS Value) ELSE (SELECT (CONCAT('Set Load Number: ',@LastPONumber)) AS Value) END AS Value FROM PONumber) AS X UNION SELECT DISTINCT TimeStr, Value FROM (SELECT CASE WHEN TimeStr = 1 THEN (SELECT @NowBatNumTimeStr AS TimeStr) ELSE (SELECT @LastBatNumTimeStr AS TimeStr) END AS TimeStr, CASE WHEN Value = 1 THEN (SELECT (CONCAT('Set Batch Number: ',@NowBatNumber)) AS Value) ELSE (SELECT (CONCAT('Set Batch Number: ',@LastBatNumber)) AS Value) END AS Value FROM Batch_Number) AS X UNION SELECT TimeStr, CONCAT('Batch Weight: ',Value) AS Value FROM batchweight WHERE TimeStr BETWEEN @bStartTime AND @bEndTime ORDER BY TimeStr; 在定义的时间段之间确实有记录时,它只列出最近的一条记录并且不会#39; t列出其他两个批次编号值(Batch_Number),如查询两个结果中所示。这显然是由于5521, and 5520查询变量仅包含最近的1条记录。

    问题

    • 我需要能够检查a之间的@NowBatNumber条记录 定义的时间段,并做两件事之一:

      1. 如果该时间段之间的记录存在,则列出所有记录,而不仅仅是最近的一条记录

      2. 如果在定义的时间段内未找到任何记录,则在该时间段之外回顾并列出最近的一条记录

    基本上对于Batch_Number表以及我在查询三中的尝试方式,我希望结果看起来与查询两个结果完全相同,并且仍在使用条件逻辑,以显示其他需要的东西。

    请再次阅读问题,因为它现在可能更有意义了。

1 个答案:

答案 0 :(得分:1)

简短的问题往往比长期/复杂的问题更受关注。这不是因为我们无法回答,但由于问题太多,而且志愿者的时间很少,所以很难证明是时候阅读大问题了。

但是我觉得你的基本要求并不复杂。您想要一种方法来检索落在时间范围内的行,或者如果不在该范围内,则提供与该范围最接近的行。

在支持ROW_NUMBER()OVER()的数据库中,这非常简单(MySQL 8.x计划支持此功能),但在此之前模拟row_number(),您可以使用变量和有序子查询。

您可以在SQL Fiddle

处试用此解决方案

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

<强>查询

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)

那么,它的作用是计算一个&#34; RowNumber&#34;从每个源表的最新行开始于1。然后,按时间范围过滤此派生表,如果不在时间范围内,则按行号过滤。

另请注意,我未使用 UNION,而是使用了UNION ALL。性能有很大差异,应该根据需要学习使用。如果使用UNION,请不要使用select distinct,因为您只是在浪费精力。

<强> Results

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