【问题标题】:Using Date_Sub to subtract year with Aliases column使用 Date_Sub 用 Aliases 列减去年份
【发布时间】:2014-10-26 09:18:51
【问题描述】:

我有两列branddate_time,在选择期间我将它们分配给别名。下面的查询:

SELECT brand, 
YEAR(date_time) AS 'year', 
SUM( brand = 'KFC' ) AS kfc
SUM( brand = 'PZH' ) AS pzh, 
SUM( brand = 'SUB' ) AS sub
FROM scan_report
GROUP BY YEAR(date_time)

结果:

现在这是令人困惑的部分。如何使用Date_Sub 函数仅显示过去 5 年的数据。我的意思是用户将输入2014,并且只会显示/选择过去 5 年的记录,这意味着来自2010 to 2014

像这样使用WHERE给了我空记录:

SELECT  
YEAR(date_time) AS 'year', 
SUM( brand = 'KFC' ) AS kfc
SUM( brand = 'PZH' ) AS pzh, 
SUM( brand = 'SUB' ) AS sub
FROM scan_report WHERE DATE_SUB(2014, INTERVAL 5 YEAR)
GROUP BY YEAR(date_time)

或者这个

FROM scan_report WHERE DATE_SUB(year = 2014, INTERVAL 5 YEAR)

知道如何从过去 5 年的用户输入中检索记录吗?我更喜欢用 mysql 解决这个问题,如果没有找到解决方案,我将使用 php。提前致谢。

【问题讨论】:

    标签: php mysql datetime mysqli alias


    【解决方案1】:

    用 PHP 做这个简单的数学运算:

    $year = 2014; # from $_POST or anywhere else
    $from = ($year - 4) . '-01-01 00:00:00';
    $to = $year . '-12-31 23:59:59';
    

    然后在查询中使用这两个变量。

    $sql = "
        ...
        WHERE date_time BETWEEN '$from' AND '$to'
        ...
    ";
    

    demo

    更新(SQL 计算):

    如果你不想用 PHP 计算,你可以在 MySQL 中计算:

    $sql = "
        ...
        WHERE 
            date_time BETWEEN CONCAT({$year}-4, '-01-01 00:00:00') AND CONCAT({$year}, '-12-31 23:59:59')
        ...
    ";
    

    更新(不关心速度或索引):

    $sql = "
        ...
        WHERE 
            YEAR(date_time) AND {$year}-4 AND {$year}
        ...
    ";
    

    【讨论】:

    • 我其实更喜欢用mysql来解决它并尽量避免使用PHP(尽管它很简单)。如果没有找到解决方案,我将使用 PHP。
    【解决方案2】:

    您的问题是 WHERE 子句中的谓词为每一行返回 NULL,因此没有返回任何行。

    DATE_SUB 函数将 DATE 表达式作为第一个参数,而不是整数。也就是说,您可以指定'2014-01-01' 作为第一个参数,而不是2014。这将返回一个非零日期,其计算结果为 TRUE(在布尔上下文中),因此将返回所有行。

    要包含具有特定 date_time 值的行,您需要在谓词中使用比较(WHERE 子句)。要返回 date_time 值为“2009-01-01”及以后的行...

    SELECT YEAR(t.date_time)      AS year
         , SUM( t.brand = 'KFC' ) AS kfc
         , SUM( t.brand = 'PZH' ) AS pzh
         , SUM( t.brand = 'SUB' ) AS sub
      FROM scan_report t 
     WHERE t.date_time >= DATE_SUB('2014-01-01', INTERVAL 5 YEAR)
     GROUP BY YEAR(date_time)
    

    一些附加说明:如果您需要(或想要)转义标识符(例如,列名,因为它是保留字),请将标识符括在反引号字符中,而不是单引号中,例如

    SELECT YEAR(`t`.`date_time`)  AS `year`
    

    【讨论】:

    • 感谢它有效,但必须这样设置才能获取过去 5 年的记录 WHERE t.date_time >= DATE_SUB( '2014-12-31', INTERVAL 5 YEAR )。我不明白这是t.date_time,因为通常t 用于表名,例如scan_report.date_time,但不知何故你可以用其他东西替换它。同样在这里FROM scan_report t,您是否将scan_report 分配给t 并在上面的所有列中使用它?欣赏一些解释。再次感谢。
    • 是的,t 是在查询中分配给表 scan_report 的短别名。我们可以使用短别名来限定列引用,例如t.date_time 是对scan_report 表中的date_time 列的引用。 SQL 不需要限定列引用,但在引用多个表的查询中,它是一种提供显着优势的模式。我们在单表查询中遵循相同的模式,以保持一致性(您可以删除 t 别名并删除 t. 限定符;查询将是相同的。)
    • 请注意,我们使用的是 >= 运算符(大于或等于比较。如果我们比较 @987654342 @,这将包括从 12 月 31 日开始的 date_time 值。没有任何无效的 SQL 方式,但可能不是预期的。就个人而言,我会避免使用 DATE_SUB 函数,而只需指定值, '2009-01-01''2014-01-01' - INTERVAL 5 YEAR,但这没有任何区别。(规范“过去五年”可以解释。我想我们'想要一年的所有行,而不仅仅是从 12 月 31 日开始。)
    • 如果我们不想包含 2009 年以来的任何行,我们会指定 date_time >= '2014-01-01' - INTERVAL 4 YEAR'。 (即今年(2014 年)和前 年(2010 年至 2013 年)。
    • @sg552:日期文字周围缺少单引号,INTERVAL 4 YEAR 周围有单引号。 (这与我在评论中显示的相同。'2014-01-01'(单引号)是日期日期文字,但2014-01-01(未包含在单引号)在日期或数字上下文中计算为NULL。在INTERVAL 4 YEAR 周围添加单引号,将其转换为字符串文字。在数字上下文中计算为0。NULL+0NULL,所以我们不'不期望任何行匹配。试试我的建议:date_time >= '2014-01-01' - INTERVAL 4 YEAR
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-19
    • 2020-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多