我正在尝试执行一个查询,它会为我执行以下选项。我得到一张桌子( 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,因此无法理解答案的解释。
我的问题:
- 如何达到预期效果?
- 是否有更好的方法可以将 testdata1 表中的数据转换为 testdata2 表(即无需在 testdata1中创建 cd 列)?
醇>
欢迎任何帮助......
答案 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>