MySQL 通过过程进行的变量分配无法正常工作

MySQL Variable Assignment via Procedure Not Working Correctly

在下面的代码中,我尝试逐行查看 endDateTable 的结果,将当前行的 endDate 与前一行的 endDate 进行比较。如果自上次以来有任何变化,我们增加 @revisionNum。但是,在填充新 table 后,所有 @revisionNum 条目都是 0。我做错了什么?

注意:我以这种方式使用准备好的语句,因为对变量执行直接 SELECT 会给出语法错误,因为 LIMIT 子句不允许在我们的版本中使用变量 MySQL.

BEGIN

 DECLARE _currentEndDate DATETIME DEFAULT now();
 DECLARE _priorEndDate DATETIME DEFAULT now();

 SET @ResultsCount = (SELECT COUNT(*) FROM mainTable);

 SET @j = 0;
    WHILE @j < @ResultsCount DO

        SET @revisionNum = 0;

        /*CURRENT END DATE*/
        SET @appResultQueryCurrent = CONCAT('
            SELECT 
                end_date
            INTO _currentEndDate
            FROM endDateTable 
            LIMIT ', @j, ', 1'
        );      

        PREPARE currentQueryStmt FROM @appResultQueryCurrent;
        EXECUTE currentQueryStmt;

        /*PREVIOUS END DATE*/
        SET @appResultQueryPrior = CONCAT('
            SELECT
                end_date
            INTO _priorAppEndDate
            FROM endDateTable
            LIMIT ', IF(@j = 0, 0, @j - 1), ', 1'
        );

        PREPARE priorQueryStmt FROM @appResultQueryPrior;
        EXECUTE priorQueryStmt; 

        SET @revisionNum = IF(
                @j = 0 OR (_currentEndDate = _priorEndDate),
                @revisionNum,
                IF(
                    _currentEndDate != _priorEndDate,
                    @revisionNum + 1,
                    @revisionNum
                )
            );

        INSERT INTO finalTable (RevisionNum)
        SELECT 
            @revisionNum AS RevisionNum 
        FROM endDateTable;

    SET @j = @j +1;

 END WHILE;

END $$

您不需要循环,您可以使用 INSERT INTO ... SELECT ...,在 select 查询中递增变量。

您还需要一个 ORDER BY 条件来指定在将一行与上一行进行比较时如何对行进行排序。

INSERT INTO finalTable (RevisionNum, otherColumn)
SELECT revision, otherColumn
FROM (
    SELECT IF(end_date = @prev_end_date, @revision, @revision := @revision + 1) AS revision,
            @prev_end_date := end_date,
            otherColumn
    FROM endDateTable
    CROSS JOIN (SELECT @prev_end_date := NULL, @revision := -1) AS vars
    ORDER BY id) AS x

DEMO

LIMIT 子句中的偏移值在没有 ORDER BY 的情况下很脆弱。

没有 ORDER BY 子句,MySQL 可以自由 return 结果以任何顺序排列。

无法保证 LIMIT 41,1 会 return LIMIT 42,1 之前的行,或者它不会 return 与 LIMIT 13,1 完全相同的行] 做到了。

(关系数据库中的 table 表示一组无序的元组,没有保证 "order" 或 table 中的行。)

但仅将 ORDER BY 添加到查询中不足以解决 Rube-Goldberg 式的冗长代码。

在显示的代码中,看起来每次通过循环,我们都将 endDateTable 的副本插入到 finalTable 中。如果在 endDateTable 中有 1,000 行,我们将在 finalTable 中插入 1,000,000 行 (1,000 x 1,000)。完全不清楚为什么我们需要这么多副本。

根据显示的代码,尚不清楚 objective 是什么。看起来我们正在有条件地递增 revisionNum,其最终结果是最高修订号。这里只是猜测。

如果在 LOOP 构造中有某种要求,在一个过程中,我想我们会做一个游标循环。我们可以使用过程变量与用户定义变量。

大致如下:

BEGIN
  DECLARE ld_current_end_date  DATETIME;
  DECLARE ld_prior_end_date    DATETIME;
  DECLARE li_done              INT;
  DECLARE li_revision_num      INT;
  DECLARE lcsr_end_date CURSOR FOR SELECT t.end_date FROM `endDateTable` t ORDER BY NULL;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET li_done = TRUE;
  SET li_done = FALSE;
  SET li_revision_num = 0;
  OPEN lcsr_end_date;
  FETCH lcsr_end_date INTO ld_current_end_date;
  SET ld_prior_end_date = ld_current_end_date;
  WHILE NOT li_done DO
    SET li_revision_num = li_revision_num + IF( ld_current_end_date <=> ld_prior_end_date ,0,1);
    SET ld_prior_end_date := ld_current_end_date;
    FETCH lcsr_end_date INTO ld_current_end_date;
  END WHILE;
  CLOSE lcsr_end_date;
  INSERT INTO `finalTable` (revisionnum) VALUES (li_revision_num);
END $$

请注意 SELECT 上的 "order by" 子句,不清楚行的排序顺序,因此我们使用文字作为占位符。

作为最终结果,我们将单行插入 finalTable

同样,不清楚问题中的代码应该实现什么,但是在有序行之间进行游标循环比获取单个行的大量动态 SQL 执行更有效。