【问题标题】:Select mySQL based only on month and year仅根据月份和年份选择 mySQL
【发布时间】:2012-02-24 15:46:38
【问题描述】:

我的 mySQL DB 中有一个包含一些行的列。其中一行是 DATE,如下所示:2012-02-01

我想要实现的是仅基于年份和月份使用 PHP 进行 SELECT。

SELECT 的逻辑如下:

$q="SELECT * FROM projects WHERE Date="SELECT HERE THE SPECIFIC YEAR AND MONTH"";

特定的月份和年份将从$_POST 变量中传递,例如$_POST['period']="2012-02";

我该怎么做?

【问题讨论】:

  • 可以使用 BETWEEN 语句

标签: php mysql


【解决方案1】:
SELECT * FROM projects WHERE YEAR(Date) = 2011 AND MONTH(Date) = 5

【讨论】:

  • 您的查询不会扩展,因为它需要进行全表扫描,除非 MySQL 中有一些我不知道的优化。
  • EXTRACT(YEAR_MONTH FROM Date) 是这样吗?
【解决方案2】:

如果你有

$_POST['period'] = "2012-02";

首先,找出当月的第一天:

$first_day = $_POST['period'] . "-01"

那么这个查询将使用Date 上的索引,如果你有的话:

$q = "
    SELECT *  
    FROM projects 
    WHERE Date BETWEEN '$first_day' 
                   AND LAST_DAY( '$first_day' )
     " ;

也可以使用包含-排除间隔,效果很好(您不必担心列是DATEDATETIMETIMESTAMP,也不用担心精度:

$q = "
    SELECT *  
    FROM projects 
    WHERE Date >= '$first_day' 
      AND Date  < '$first_day' + INTERVAL 1 MONTH 
     " ;

安全警告:

您应该正确地转义这些值或使用准备好的语句。简而言之,在 PHP 中使用这些天推荐的任何方法,以避免任何 SQL 注入问题。

【讨论】:

  • 是的,中间 +1,我最初使用的是年 + 月函数,但这样的函数没有缩放,也没有使用索引。
  • @sobelito 是的。我通常更喜欢包含-排除间隔。帖子已更新。
  • 请转义这些值或使用准备好的语句...?
【解决方案3】:

给你。将计算留给 PHP 并为您的数据库节省一些工作。这样您就可以有效地利用Date 列上的索引。

<?php
    $date = $_POST['period'];

    $start = strtotime($date);
    $end   = strtotime($date . ' 1 month - 1 second');

    $query = sprintf(
        'SELECT *
           FROM projects
          WHERE Date BETWEEN FROM_UNIXTIME(%u) AND FROM_UNIXTIME(%u)',
        $start,
        $end
    );

编辑
忘记了 Unix 时间戳转换。

【讨论】:

  • 它是索引友好的,但是 strtotime 给你 int 并且你需要先将它转换为日期为 mysql。
  • 应该是字符串拼接,而不是求和操作:$end = strtotime($date .' 1 month - 1 second');
【解决方案4】:

假设您有一个数据库字段 created_at 从时间戳中获取值。 您想从 created_at 日期开始按年和月搜索。

YEAR(date(created_at))=2019 AND MONTH(date(created_at))=2

【讨论】:

    【解决方案5】:
    $q="SELECT * FROM projects WHERE YEAR(date) = 2012 AND MONTH(date) = 1;
    

    【讨论】:

      【解决方案6】:

      这里,在 mySQL 中按 MONTH 和 DATE 查找记录

      这是您的 POST 值$_POST['period']="2012-02";

      只是,用破折号来爆炸价值$Period = explode('-',$_POST['period']);

      从爆炸值中获取数组:

      Array ( [0] => 2012 [1] => 02 )

      将值放入 SQL 查询中:

      SELECT * FROM projects WHERE YEAR(Date) = '".$Period[0]."' AND Month(Date) = '".$Period[0]."';

      按月和年获取结果。

      【讨论】:

        【解决方案7】:

        逻辑是:

        SELECT * FROM objects WHERE Date LIKE '$_POST[period]-%';
        

        LIKE 运算符将选择所有以 $_POST['period'] 开头的行,后跟破折号和月份

        http://dev.mysql.com/doc/refman/5.0/en/pattern-matching.html - 一些附加信息

        【讨论】:

        • -1 对内部表示为整数的数据的字符串操作!?你是认真的吗?
        • @Yaroslav 是的,我想效率很高:D
        • 无索引。它首先将日期值转换为字符串,然后匹配该字符串。在 MySQL 中,任何列类型都可以通过 LIKE 查询。但它仍然可以工作:D
        • 小鲍比桌有人吗?
        • 没有必要一直为性能而疯狂,现在可以了。有时,您为使其工作速度提高几微秒而付出的努力和时间并没有任何影响,但您浪费了那段时间。
        【解决方案8】:

        从日期列中获取月份和年份值

        select year(Date) as "year", month(Date) as "month" from Projects
        

        【讨论】:

          【解决方案9】:

          你可以这样做:

          $q="SELECT * FROM projects WHERE Year(Date) = '$year' and Month(Date) = '$month'";
          

          【讨论】:

          • 这也不使用索引
          【解决方案10】:

          你可以通过改变 $q 来做到这一点:

          $q="SELECT * FROM projects WHERE YEAR(date) = $year_v AND MONTH(date) = $month_v;
          

          【讨论】:

            【解决方案11】:

            似乎没有人在谈论性能,所以我在sample database from Mysql 上测试了两个最受欢迎的答案。该表有 280 万行结构

            CREATE TABLE `salaries` (
              `emp_no` int(11) NOT NULL,
              `salary` int(11) NOT NULL,
              `from_date` date NOT NULL,
              `to_date` date NOT NULL
            ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
            
            ALTER TABLE `salaries`
              ADD PRIMARY KEY (`emp_no`,`from_date`);
            

            这是执行的测试和结果

            SELECT * FROM `salaries` WHERE YEAR(from_date) = 1992 AND MONTH(from_date) = 6
            12339 results
            -----------------
            11.5 ms 
            12.1 ms
            09.5 ms
            07.5 ms
            10.2 ms
            -----------------
            10.2 ms Avg
            -----------------
            
            
            SELECT * FROM `salaries` WHERE from_date BETWEEN '1992-06-01' AND '1992-06-31'
            -----------------
            10.0 ms
            10.8 ms
            09.5 ms
            09.0 ms
            08.3 ms
            -----------------
            09.5 ms Avg
            -----------------
            
            
            SELECT * FROM `salaries` WHERE YEAR(to_date) = 1992 AND MONTH(to_date) = 6
            10887 results
            -----------------
            10.2 ms
            11.7 ms
            11.8 ms
            12.4 ms
            09.6 ms
            -----------------
            11.1 ms Avg
            -----------------
            
            
            SELECT * FROM `salaries` WHERE to_date BETWEEN '1992-06-01' AND '1992-06-31'
            -----------------
            09.0 ms
            07.5 ms
            10.6 ms
            11.7 ms
            12.0 ms
            -----------------
            10.2 ms Avg
            -----------------
            

            我的结论

            1. BETWEEN 在索引列和未索引列上都稍好一些。
            2. 未编入索引的列比已编入索引的列稍慢。

            【讨论】:

              【解决方案12】:

              您可以使用 mysql DATE_FORMAT 函数仅考虑日期的年+月部分:

              select * from table where DATE_FORMAT(column, '%Y%m') = '202105';
              

              【讨论】:

                【解决方案13】:

                这是我使用的一个查询,它会将一段时间内的每条记录作为总和返回。

                代码如下:

                $result = mysqli_query($conn,"SELECT emp_nr, SUM(az) 
                FROM az_konto 
                WHERE date BETWEEN '2018-01-01 00:00:00' AND '2018-01-31 23:59:59' 
                GROUP BY emp_nr ASC");
                
                echo "<table border='1'>
                <tr>
                <th>Mitarbeiter NR</th>
                <th>Stunden im Monat</th>
                </tr>";
                
                while($row = mysqli_fetch_array($result))
                {
                $emp_nr=$row['emp_nr'];
                $az=$row['SUM(az)'];
                echo "<tr>";
                echo "<td>" . $emp_nr . "</td>";
                echo "<td>" . $az . "</td>";
                echo "</tr>";
                }
                echo "</table>";
                $conn->close();
                ?>
                

                这列出了每个 emp_nr 以及它们累积的每月小时数的总和。

                【讨论】:

                  【解决方案14】:

                  从表格中获取具体的月份和年份数据

                  SELECT * FROM table WHERE DATE_FORMAT(column_name,'%Y-%m') = '2021-06'
                  

                  【讨论】:

                    【解决方案15】:

                    是的,这是有效的,但它只返回一行,而只有几行需要使用选定的列检索。 像 SELECT Title,Date FROM mytable WHERE YEAR(Date)=2017 AND MONTH(Date)=09 只返回一行。

                    【讨论】:

                      猜你喜欢
                      • 2018-03-02
                      • 2010-12-25
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2014-08-07
                      • 1970-01-01
                      • 2011-03-21
                      相关资源
                      最近更新 更多