为每个新行

时间:2017-11-18 20:51:06

标签: mysql

我正在尝试执行一个查询,它会为我执行以下选项。我得到一张桌子( testdata1 )说:

 YearS                    CountS($)
 2015                     360
 2016                     1000
 2017                     2000
 2018                     3500

从这张表中我必须创建另一个表( testdata2 ),如下所示:

YearS                       NewCountS($)
2015                        360
2016                        640(i.e 1000 - 360)
2017                        1000(i.e. 2000 - 1000)
2018                        1500(i.e. 3500 - 2000)

我需要记住的另一件事是,在 testdata1 中可以给我任意数量的行,因此我尝试的是:

set @diffr := 0;

update testdata1
set cd = (@diffr := CountS - @diffr)
order by yearS;
=================================
insert into testdata2(yearS, NewCountS)
Select yearS, cd
from testdata1;

此查询有效,但会生成此输出:

YearS                       NewCountS($)
2015                        360
2016                        640
2017                        1360
2018                        2140

我发现this链接可以提供帮助,但由于我是mysql中的tyro,因此无法理解答案的解释。 我的问题:

  
      
  1. 如何达到预期效果?
  2.   
  3. 是否有更好的方法可以将 testdata1 表中的数据转换为 testdata2 表(即无需在 testdata1中创建 cd )?
  4.   

欢迎任何帮助......

1 个答案:

答案 0 :(得分:3)

无需执行testdata1的更新。只需编写一个查询,获取需要插入testdata2的行。

如果我们想要使用用户定义的变量,首先测试该语句以验证它是否返回我们期望的结果。

SELECT r.years
     , r.counts
  FROM (
         SELECT s.years
              , s.counts - @prev_counts  AS `counts`
              , @prev_counts := s.counts AS `prev_counts`
           FROM ( SELECT @prev_counts := 0 ) i
          CROSS
           JOIN testdata1 s
          ORDER BY s.years
       ) r
 ORDER BY r.years

请注意,内联视图i在语句开头初始化用户定义的变量,基本上等同于运行单独的SET @prev_counts = 0;语句。

对于每一行,用户定义变量的值设置为counts的值,以便在我们处理下一行时它可用。请注意,在前面的表达式中引用了之后,我们期望MySQL执行此赋值操作

请注意,使用此类(评估顺序)的用户定义变量的这种行为(在MySQL参考手册中)记录为" undefined"。我们确实通过精心构造的SQL观察到一致的行为,但是我们应该注意到正式的这种行为是不能保证的。

测试完SELECT后,我们可以将其变成INSERT ... SELECT

不使用用户定义变量的替代方法,我们可以在SELECT列表的表达式中使用相关子查询。 (获取,写这是一个SELECT语句并首先测试它,然后再把它变成iNSERT ... SELECT)

SELECT q.years
     , q.counts
     - IFNULL(
               ( SELECT r.counts
                   FROM testdata1 r
                  WHERE r.years < q.years
                  ORDER BY r.years DESC
                  LIMIT 1
               )
       ,0) AS `counts`
   FROM testdata1 q
  ORDER BY q.years

编辑以添加上述查询的说明

从这样的简单查询开始:

SELECT q.years
     , q.counts
   FROM testdata1 q
  ORDER BY q.years

对于从testdata1返回的每一行,将评估SELECT列表中的表达式,并返回一个值。在这种情况下,这两个表达式是简单的简单列引用,我们得到存储在列中的值。

我们可以在SELECT列表中使用更复杂的表达式,例如:

SELECT q.years
     , q.years - 2000  AS `yy`
     , REVERSE(q.years) AS `sraey`
     , CONCAT('for ',s.years,' the count is ',s.counts) AS `cs`  
     , ... 

对于SELECT列表中的那些表达式,对于返回的每一行,对这些表达式进行求值,并返回一个值,也会发生同样的事情。

也可以使用查询作为表达式,但有一些限制。查询必须返回单个列(单个表达式),并且最多只能返回一行。

当查询处理行years-2017时,将评估SELECT列表中的表达式。

规范是我们希望获得前一年counts的值years=2016 SELECT r.years , r.counts FROM testdata1 r WHERE r.years = '2016' 。我们可以通过执行如下查询来获取该行:

LIMIT 1

要将这样的查询用作SELECT列表中的表达式,我们需要确保它不会返回多行。我们可以添加 SELECT r.counts FROM testdata1 r WHERE r.years = 2016 LIMIT 1 子句以确保它没有。我们只需返回一列......

2016

但总是得到2016行。我们现在可以做的是更改它以引用外部查询中的行而不是文字 SELECT ( SELECT r.counts FROM testdata1 r WHERE r.years = ( q.years - 1 ) LIMIT 1 ) AS `prev_years_counts` , q.counts , q.years FROM testdata1 q ORDER BY q.years

q.years

请注意,子查询中的q是对外部查询中的行的引用。当正在处理来自q.years的行时,MySQL使用WHERE子句中的q.years值执行子查询。对于外部查询处理的每一行,执行子查询。由于外部查询中的q.years=2015引用,我们说它是相关的子查询。

如果没有返回任何行(就像IFNULL的情况一样),子查询返回一个NULL值。我们将整个子查询包装在NULL函数中,所以如果子查询返回{ {1}},我们将返回0

最终结果是一个值。我们可以在SELECT列表中编写减法表达式,例如

 SELECT q.counts - 540 AS `counts_minus_540`

在文字540中,我们可以使用表达式或列引用...

 SELECT q.counts - foo AS `counts_minus_foo`

我们可以使用相关的子查询表达式来代替foo,就像我们在这个答案中的第二个查询中所做的那样:

 SELECT q.years
      , q.counts - IFNULL( crsq ,0) AS `counts`
   FROM ... 

其中crsq是相关子查询

 SELECT q.years
      , q.counts - IFNULL( 

          SELECT r.counts
           FROM testdata1 r
          WHERE r.years = ( q.years - 1 )
          LIMIT 1

        ,0) AS `counts`
   FROM testdata1 q
  ORDER BY q.years

使用给定的示例数据,此查询等同于答案中的第二个查询。如果years值中存在z空格(例如,没有years=2016行。查询结果将不同,因为相关子查询将返回q.years-2017的不同内容。< / p>