在下面的代码中,我试图逐行浏览endDateTable
的结果,将当前行的endDate
与上一行的endDate
进行比较。如果自上次以来没有任何变化,我们将增加@revisionNum
。但是,在填充新表后,所有@revisionNum
条目都是0
。我在做什么错了?
注意:我正在以这种方式使用准备好的语句,因为对SELECT
子句不允许在我们的MySQL版本中使用变量,直接对变量执行LIMIT
会产生语法错误。 / p>
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 $$
答案 0 :(得分:1)
您不需要循环,可以使用INSERT INTO ... 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
答案 1 :(得分:0)
LIMIT
子句中的偏移量值很小,没有ORDER BY
。
没有ORDER BY
子句,MySQL可以按任意顺序自由返回结果。
不能保证LIMIT 41,1
将返回LIMIT 42,1
之前的行,也不保证它不会返回与LIMIT 13,1
完全相同的行。
(关系数据库中的表表示无序的元组集,表中没有保证的“顺序”或行。)
但是仅向查询中添加ORDER BY
不足以解决Rube-Goldberg式的僵局。
在所示的代码中,每次循环似乎都在endDateTable
中插入finalTable
的副本。如果endDateTable中有1,000行,我们将在finalTable中插入1,000,000行(1,000 x 1,000)。根本不清楚为什么我们需要那么多副本。
鉴于显示的代码,不清楚目标是什么。看起来我们有条件地增加了versionNum,其最终结果是最高的修订num。只是在这里猜测。
如果在某种过程的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执行效率更高。