create table Numbers(id int, Number float);
insert into Numbers(id, Number)
values (1, 3.00),
(2, 3.30),
(3, 4.50),
(4, 2.25),
(5, 6.50);
select min(Number) from Numbers into @minNumber;
select id, Number, (Number - @minNumber) from Numbers;
我需要显示数字列表,并且要显示每个数字旁边的数字,我必须显示数字本身与当前行上方的最小数字(除当前行以外的所有先前行)之间的差。所以输出应该是。
3.00 3.00
3.30 0.30
4.50 1.50
2.25 -0.75
6.50 4.25
现在,它仅显示数字和所有数字的最小值(2.25)之间的差。不确定如何运行循环以使其起作用。
答案 0 :(得分:3)
假设您有一个主键列id
。 始终请记住,数据是以无序方式存储的,因此,如果没有PK,我们实际上无法定义当前行的“行上方”。
您可以利用Correlated Subqueries来确定当前行(Number
)上方各行中的最小t2.id < t1.id
对于第一行,上面没有任何数字,因此我们将不得不使用Coalesce()
函数将null
的值视为0:
SELECT
t1.id,
t1.Number,
(t1.Number - COALESCE((SELECT MIN(t2.Number)
FROM Numbers AS t2
WHERE t2.id < t1.id),0)) AS difference
FROM Numbers AS t1
ORDER BY t1.id
从MySQL 8.0.2 开始,我们也可以使用Window Functions with Frame。我们可以考虑从一开始(UNBOUNDED PRECEDING
)到当前行之前的一行(1 PRECEDING
)的“递增”帧,并确定最小值。
尝试以下操作(仅适用于 MySQL 8.0.2 + ):
SELECT
id,
Number,
(Number -
COALESCE(MIN(Number) OVER(ORDER BY id
ROWS BETWEEN UNBOUNDED PRECEDING
AND 1 PRECEDING)
,0)) AS difference
FROM Numbers
ORDER BY id
答案 1 :(得分:1)
可能最有效的方法是使用变量:
select n.*,
(number -
(case when (@min2 := @min) = NULL then 0 -- never happens
when @min := least(coalesce(@min, n.number), n.number) = NULL then 0 -- never happens
else coalesce(@min2, 0)
end)
) as diff
from numbers n cross join
(select @min := NULL) params
order by n.id;
答案 2 :(得分:0)
交叉连接怎么了?
SELECT n.id, n.Number, n.Number - MIN(n2.Number)
FROM Numbers n
CROSS JOIN Numbers n2
WHERE
n2.id < n.id
GROUP BY n.id, n.Number;