如何选择MySQL中当前时间戳内10分钟的所有记录?

时间:2012-01-26 03:04:33

标签: mysql

我在名为“last_seen”的表列中有时间戳,如下所示:

2012-01-25 18:46:42
2012-01-23 08:19:04
2012-01-23 08:19:04

etc...

如何获取时间戳在当前时间戳10分钟内的所有记录(以最有效的方式)?

4 个答案:

答案 0 :(得分:45)

最有效的方法是将时间戳(和时间戳,不使用其上的任何函数)与可以计算为每行的常量的表达式进行比较,这样mysql可以使用在timestamp列上定义的索引。

SELECT * FROM myTable
WHERE last_seen >= NOW() - INTERVAL 10 MINUTE

您始终可以尝试EXPLAIN SELECT ...查看索引是否可用于查找满足WHERE条件的行,而无需检查表中的每一行。

答案 1 :(得分:3)

您的问题要求在当前时间戳的10分钟内记录,但我认为这意味着过去(不是将来)不超过十分钟:

SELECT col1, col2, col3 
FROM table
WHERE DATE_ADD(last_seen, INTERVAL 10 MINUTE) >= NOW();

这会使last_seen增加10分钟,并将其与当前时间进行比较。如果值更大,last_seen小于十分钟前。

有关如何使用的说明,请参阅documentation on DATE_ADD()

答案 2 :(得分:0)

以防该方法对某些人无效。

在我在date()函数(由@karam qubsi建议)中添加timestamp列之前,以上答案中的“ where”条件对我而言不起作用:

  

SELECT * FROM myTable

     

日期(最后一次看到)的位置> = NOW()-间隔10分钟

只有那时我才开始获得正确的结果。

答案 3 :(得分:0)

对于希望将问题扩展到仅一张表之外并在过去(例如)5分钟内找到具有date_modified的数据库中任何表中任何条目的任何人,请尝试使用此脚本。

调整数据库条目(我使用了名为mgmt2go的数据库),并将下面的文件保存到可执行的.sql文件中。

根据情况进行自适应,但是,如果仅更改数据库设置,它将对数据库执行相同的操作。

我从命令行运行此SQL脚本,然后将结果输出到文件中,以便在调试将所有设置都写入MySQL(实际上是MariaDB)数据库的系统时,可以参考输出。我需要弄清楚通过系统用户界面进行更改时受到的影响。

# For this setup, it is best to send the output to a file
# and then read the file to see what records in what tables are found
# Save this file as list_tables.sql (or whatever you want to save it as)
# and use it by entering, at the CLI
# mysql --user=UserName --password=UserPassword -vv 2>&1 < path_to_executable_file/list_tables.sql > path_to_output_file/test.output.txt
# If you want the filename to include the time period, 
# concatentate the bash date function with the filename 
# ie: "mgmt2goDbaseChangesSince_"$(date +%Y-%m-%d_%H:%M:%S --date -'5 min')  
# so the full sql comand would now look like
# mysql --user=UserName --password=UserPassword -vv 2>&1 < path_to_executable_file/list_tables.sql > "path_to_output_file/mgmt2goDbaseChangesFrom_"$(date +%Y-%m-%d_%H:%M:%S --date -'5 min')"_to_"$(date +%H:%M:%S)


# Set the delimeter so you can distingish the delimiter surrounding the Procedure 
# (as an intact entity to be passed to the server)
# from the statements inside the Procedure calls
DELIMITER $$

# In case a previous script run created the procedure, 
# delete it before running this script again
DROP PROCEDURE IF EXISTS `mgmt2go`.rc_list_tables_procedure$$

# Create a procedure to identify all the tables in the database 
# (in this case, I have a database named mgmt2go)
# that contain multiple fields (id, date_modified) against which you want to search
CREATE PROCEDURE `mgmt2go`.rc_list_tables_procedure( IN rc_cutoff_date DATETIME )
BEGIN
    # Always DECLARE in sequence: Variables, Cursors, Handler
    # Variables
    DECLARE rc_last_record BOOLEAN DEFAULT FALSE;
    DECLARE rc_table_name varchar(64);
    # Cursor
    DECLARE rc_table_list CURSOR FOR SELECT DISTINCT `TABLE_NAME` 
        FROM `INFORMATION_SCHEMA`.`COLUMNS` 
        WHERE `INFORMATION_SCHEMA`.`COLUMNS`.`TABLE_SCHEMA` = 'mgmt2go' 
        AND `INFORMATION_SCHEMA`.`COLUMNS`.`COLUMN_NAME` 
            IN ( 'id' , 'date_modified' ) 
        GROUP BY TABLE_NAME HAVING COUNT( DISTINCT COLUMN_NAME ) = 2 
        ORDER BY `INFORMATION_SCHEMA`.`COLUMNS`.`TABLE_NAME`;
    # Handler
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET rc_last_record = TRUE;
    # Activate the LOOP
    OPEN rc_table_list;
        rc_for_each_loop: LOOP
            # Test if the previous iteration of the LOOP fetched the last record
            # and if so, exit the LOOP
            FETCH FROM rc_table_list INTO rc_table_name;
            IF rc_last_record = TRUE THEN
                LEAVE rc_for_each_loop;
            END IF;
            # Eliminate the entries in the job_queue table 
            # since they are just temporary system entries
            IF rc_table_name = 'job_queue' THEN
                ITERATE rc_for_each_loop;
            END IF;
            # Find all records in all tables with a date_modified field
            # greater than or equal to the specified value in the CALL
            # We cannot directly use a variable in a SELECT statement
            # So we prepare a SELECT statement by concatenation
            # and then use the Prepare and Execute functions to run the SELECT
            SET @rc_query_for_modified := CONCAT( 
                'SELECT "' , rc_table_name , '" , `id` ,`date_modified` '
                'FROM `mgmt2go`.`' , rc_table_name , '` '
                'WHERE '
                'TIMESTAMP( `mgmt2go`.`' , rc_table_name , '`.`date_modified` )'
                ' >= "' , rc_cutoff_date , '" '
                );
            PREPARE rc_test_modified_statement FROM @rc_query_for_modified;
            EXECUTE rc_test_modified_statement;
            DEALLOCATE PREPARE rc_test_modified_statement;
        END LOOP rc_for_each_loop;
    CLOSE rc_table_list;
END$$

# Reset the delimiter back to the default
DELIMITER ;$$

# Invoke the Procedure, providing the cutoff date = date record more current than
# You can provide an absolute time using
# CALL `mgmt2go`.rc_list_tables_procedure( "2019-01-02 16:49:28" );
# Or you can provide a time n (Seconds/Minutes/...) before a stated time (like NOW()
CALL `mgmt2go`.rc_list_tables_procedure( DATE_SUB( NOW() , INTERVAL 5 MINUTE ) );

# If you are also trying to see if any files have changed in the last n minutes
# and want to NOT search in a particular child directory (/cache in this case)
# at the CLI enter 
# find path_to_directory -path path_to_child_directory_to_exclude -prune , -type f -mmin -120
# or
# find path_to_directory -mmin -120 -iname "*.*" | egrep -v "(child_directory_to_exclude)"
# where -120 is the number of minutes to look back (120 in this case)
# -mmin is minutes since modification and -cmin is minutes since creation
# -mtime is days since modification and -ctime is days since creation