Mysql SQL SELECT语句表达式值对其他表达式的重用
我在mysql中有一个行数巨大的表(尽管我正在寻找通用的SQL解决方案) 我想要SELECT语句Mysql SQL SELECT语句表达式值对其他表达式的重用,mysql,sql,sql-server,Mysql,Sql,Sql Server,我在mysql中有一个行数巨大的表(尽管我正在寻找通用的SQL解决方案) 我想要SELECT语句 SELECT a, (b + c) as expression1, (b + c + a) AS expression2 -- basically (expression1 + a) FROM very_big_table WHERE ... GROUP BY a ORDER BY a DESC 只要表达式1简单,它看起来就很好且易于阅读。 但是当CASE-when/IFNULL
SELECT a,
(b + c) as expression1,
(b + c + a) AS expression2 -- basically (expression1 + a)
FROM very_big_table
WHERE ...
GROUP BY a
ORDER BY a DESC
只要表达式1简单,它看起来就很好且易于阅读。但是当CASE-when/IFNULL()/SUM()/MIN()/STRCAT()或某些运算符在这些表达式中起作用时,很难读取和调试 我已经讨论了一些已经提出的问题
但是如果我使用下面描述的方法
SELECT a,
expression1,
(expression1 + a) AS expression2
FROM
(SELECT a,
(b + c) AS expression1
FROM very_big_table
WHERE ...
GROUP BY a) as inner_table
ORDER BY a DESC
这可以很好地工作,但执行此查询要多花70倍的时间。至少在我发射它的时候,虽然只有一次。如果输出列中有多个级别的表达式,该怎么办 有什么优雅的方法可以在不影响可读性的情况下处理这个问题吗
顺便问一下,为什么SQL标准或供应商不支持select语句中的表达式重用或别名引用?(假设在单个SELECT语句表达式中没有循环求值。在这种情况下,编译器会失败)解决方法假定表达式不是sql SELECT子子句,而是纯粹作用于原始“SELECT from”中检索的数据的嵌套运算符/函数子句,因此手头的任务纯粹是使代码“看起来漂亮”: 创建用户定义的函数 那么您的查询将如下所示
select a
, myfunction( b, c)
, myfunction( b, c) + a
...
好处-这将清除“选择代码”,这是您声明的目标,您还可以集中管理更复杂的逻辑
缺点-这不是将移植到其他系统的“通用sql”,如果功能很少被重复使用,可能不值得在时间上进行投资 将实际查询用作子查询
select a,exp1,exp1+a as exp2
from (SELECT a
,(b + c) as exp1
FROM very_big_table
WHERE ...
GROUP BY a
)V
ORDER BY a DESC
或者为查询添加外部应用语句
SELECT a
,OA.exp1 as expression1
,(OA.exp1 + a) AS expression2 -- basically (expression1 + a)
FROM very_big_table
outer apply (select (b + c) as exp1) OA
WHERE ...
GROUP BY a
ORDER BY a DESC
我想第二个选项,使用外部应用,更适合阅读
请记住,每行都会运行外部应用程序
因此,如果exp1必须从表中访问大量数据,这可能是个坏主意
无论如何,只要使用您在实际查询中已经得到的字段即可
添加它不会有很大的成本
所以。。您将选择什么方式?您可以使用用户定义的变量来解决您的问题。您的SQL可以重写为:
SELECT a,
@expr1 := (b + c) as expression1,
(@expr1 + a) AS expression2
FROM very_big_table
WHERE ...
GROUP BY a
ORDER BY a DESC
Postgresql用户可参考。
如果您想最大限度地提高复杂计算和/或逻辑的可读性,请将计算封装在它自己的函数中
create table x
(
a int not null,
b int not null,
c int not null
);
create table y
(
a int not null,
z int not null
);
select * from x;
insert into x VALUES
(1,2,3), (4,5,6);
insert into y values
(1, 100);
具有复杂计算和/或逻辑的功能:
测试查询:
select x.a, x.b, x.c, y.z, answer.*
from x
join y on x.a = y.a
cross join lateral computer(x,y) answer
with data_source as
(
select x.*, y.z
from x
join y on x.a = y.a
)
select ds.*, answer.*
from data_source ds
cross join lateral computer_b(ds) answer
输出:
如果您只需要快速测试函数的返回值,可以使用括号星号语法对其进行扩展:
select x.a, x.b, x.c, y.z, (computer(x, y)).*
from x
join y on x.a = y.a
但是不要在生产中使用它,如果函数有50个返回列,那么函数将被调用50次。在生产中使用横向交叉连接。见:
如果函数本身不需要考虑数据源的来源,只需使用函数参数上的记录类型即可
create or replace function computer_b
(
anon record,
out expression1 int, out expression2 int, out expression3 int
)
as $$
begin
expression1 := anon.b + anon.c;
expression2 := expression1 + anon.a;
expression3 := expression2 + anon.z;
end;
$$ language 'plpgsql';
测试查询:
select x.a, x.b, x.c, y.z, answer.*
from x
join y on x.a = y.a
cross join lateral computer(x,y) answer
with data_source as
(
select x.*, y.z
from x
join y on x.a = y.a
)
select ds.*, answer.*
from data_source ds
cross join lateral computer_b(ds) answer
为什么您认为能够重用表达式别名将导致执行时间减少70倍?您能展示一个实际执行计划的实际查询和.sqlplan文件的实例吗?我几乎可以保证,执行时间上的这种差异不是由于添加了子查询造成的——其他的东西肯定不同。@Quail仍然无法想象这样一种情况,即这是唯一的差异,它会导致70倍的性能差异。我在Aaron编辑完他的评论后删除了我的评论。对于后人来说,它说,“我想他是在比较它,明确地指定每一列。”至于为什么,让我们不要重新散列:这个非常大的表有主键吗?它是什么?为什么外部应用
而不是交叉应用
?