【问题标题】:A loop until in the stored procedure一个循环直到在存储过程中
【发布时间】:2009-10-29 06:40:12
【问题描述】:

我正在尝试编写一个程序,该程序将触发相同的选择查询,直到结果数超过 0。如果“间隔 2 小时”返回 0 条记录,则应使用“间隔 4 小时”标准,如果仍然没有提取记录,那么 lastupdate > current_date() 应该用在 where 子句中。

这些是过程中使用的 2 个基本查询。

select sql_calc_found_rows id from sometable where lastupdate > date_sub(now(), interval 2 hour) limit 10;

select found_rows();
+--------------+
| found_rows() |
+--------------+
|           41 | 
+--------------+

以下步骤是否正确?写SP的方法正确吗?以及如何在 PHP 代码中使用结果?

delimiter $$
create procedure mytest3()
begin 

  declare myvar int;

 select sql_calc_found_rows id 
   from sometable 
  where lastupdate > date_sub(now(), interval 2 hour) 
  limit 10;

 select found_rows() into myvar;

if (myvar > 0) 
  then select 'Found in 2 hours';
else
  select sql_calc_found_rows id 
    from sometable 
   where lastupdate > date_sub(now(), interval 4 hour) 
   limit 10;

select found_rows() into myvar;

if (myvar > 0) 
  then select 'Found in 4 hours';
else 
  select sql_calc_found_rows id 
    from sometable 
   where lastupdate > current_date() 
   limit 10;
end if;
end if; 
end$$ 

【问题讨论】:

  • 你为什么要做这样的事情?你能描述一下这个场景吗?
  • 您想研究使用 WHILE 循环:dev.mysql.com/doc/refman/5.0/en/while-statement.html
  • 为什么?航空公司飞行计划;尝试在 2 小时的时段内查找航班,如果 2 小时的时段内没有航班,则返回 4 小时,如果 4 小时的时段内没有,则返回一整天。作为一个“例子”,当然......

标签: php sql mysql


【解决方案1】:

我突然想到,虽然您在文本的标题和正文中都要求循环,但您真正想要做的是获取“在过去 X 小时内修改的行”的列表,其中返回一些(非空)行集的最小 X...

这是实现这一目标的一种方法:

delimiter $$
create procedure recently_modified_rows()
begin 

  declare tablelastupdate int; -- how many hours ago table was last updated.
  declare showperiod datetime; -- what time interval to show
  declare showtext  text;      -- text describing time interval

  select hour(timediff(now(), max(lastupdate))) into tablelastupdate
    from sometable;

  if(tablelastupdate < 2)
     set showperiod = time_sub(now(), interval 2 hours);
     set showtext = "modified in the last 2 hours";
  elseif (tablelastupdate < 4)
     set showperiod = time_sub(now(), interval 4 hours);
     set showtext = "modified in the last 4 hours";
  else
     set showperiod = current_date();
     set showtext = "modified today";
  end if

  select sql_calc_found_rows id, 
         showtext description
     from sometable 
     where lastupdate > showperiod 
     limit 10;

end$$

并从 php 调用它:

$query = mysql_query("call recently_modified_rows()") or die( mysql_error() );
$numrows = mysql_numrows($query);

if ($numrows != 0)
{
    /* print out what time interval we used */
    $description = mysql_result($query, 0, 'description');
    echo "Found $numrows rows $description";

    /* print out the rows */
    while ($row = mysql_fetch_array($query)) 
    {
       echo "Id: {$row['id']}";
    }

}
else 
{
    /* happens only if there were no records modified in any of the three versions */
    echo "no records were modified in the last 2 hours, 4 hours, or today";
}

【讨论】:

    【解决方案2】:

    根据您的情况,最好在您的数据库上设置触发器 (http://dev.mysql.com/doc/refman/5.0/en/triggers.html)。这使您可以仅在相关数据发生更改时进行任何必要的工作/重新计算,而不是在数据库中没有任何更改的情况下通过不断轮询使您的服务器不必要地忙碌。

    【讨论】:

      【解决方案3】:

      这是我第一次尝试在 StackOverflow 上发布答案。希望对你有帮助。。

      我在下面使用本地 MySQL 数据库编写了一个测试程序。它设置为运行整整 10 秒,如果没有记录,则返回一个空的结果集。如果在它运行的十秒内插入了一行,它将退出循环并返回新的结果。

      Sleep 功能可防止程序在运行时消耗过多的 CPU,方法是每秒仅运行一次 Select Count(*)。您可以将其设置为您想要的任何间隔。

      虽然此程序运行良好,但我必须同意 natevw 使用 Triggers 代替。

       DELIMITER $$
      
       CREATE PROCEDURE sp_TestQueryResultsTimeout()
       BEGIN
      
      
         DECLARE v_interval, ct, v_time INT;
      
         /* This will keep track of how much time has passed*/
         SET v_interval = 0;
      
         /* This is used for comparing the rowcount*/
         SET ct = 0;
      
         /* This is used to keep the procedure from returning the Sleep functions results'
            This could also be used to keep a more accurate count of the amount of Sleep time has passed by adding the results of the sleep function to it on every iteration*/
         SET v_time = 0;
      
         /* This while statement should run for slightly longer than ten seconds
            The amount of extra time will begin to add up depending on how long the select count (*) takes
            and how many iterations you want to make'*/
      
         WHILE v_interval < 10 DO
      
         /*Get the count from your table*/
             SET ct = (SELECT count(*) FROM tbUsers);
      
           /*If the count is greater than 0, exit the while by satisfying the condition*/
         if (ct > 0) then
          SET v_interval = 10;
         else
          /*If the count is less than 0, sleep for 1 second*/
               SET v_time = (SELECT SLEEP(1));
         end if;
      
             /*Increment*/
             SET v_interval = v_interval + 1;
         END WHILE;
      
         SELECT * FROM tbUsers;
      
       END$$
      
       DELIMITER ;
      

      【讨论】:

        【解决方案4】:

        来自 MySQL 文档:

        CREATE PROCEDURE dowhile()
        BEGIN
          DECLARE v1 INT DEFAULT 5;
        
          WHILE v1 > 0 DO
            ...
            SET v1 = v1 - 1;
          END WHILE;
        END
        

        【讨论】:

          【解决方案5】:

          PHP 页面将由用户触发,因此您必须将结果保存到数据库中,直到有人打开该页面并显示结果。

          您可以使用 PHP cronjob,而不是在数据库中使用无限循环。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2015-01-19
            • 1970-01-01
            • 1970-01-01
            • 2013-03-04
            • 2019-02-09
            • 2010-10-26
            相关资源
            最近更新 更多