sql中的高级循环

uqxowvwt  于 2021-06-20  发布在  Mysql
关注(0)|答案(3)|浏览(269)
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)之间的差值。不知道如何运行循环以使其工作。

qfe3c7zg

qfe3c7zg1#

交叉连接有什么问题?

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;

db小提琴演示

x9ybnkn6

x9ybnkn62#

最有效的方法可能是使用变量:

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;

db小提琴演示

ie3xauqp

ie3xauqp3#

假设您有一个主键列 id . 永远记住数据是以无序的方式存储的,因此如果没有pk,我们真的无法定义当前行之上的“行”。
您可以利用相关子查询来确定最小值 Number 在当前行上方的行中( t2.id < t1.id )
对于第一行,上面没有任何数字,所以我们必须使用 Coalesce() 要考虑的功能 null 值为0:

db小提琴演示

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

在MySQL8.0.2以后的版本中,我们也可以使用带有框架的窗口函数。我们可以从一开始就考虑“增加”的框架( UNBOUNDED PRECEDING )到当前行之前的一行( 1 PRECEDING ),并确定最小值。
请尝试以下操作(仅限mysql 8.0.2+):

db小提琴演示

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

相关问题