mysql – 通过UNION计算,合并查询重复代码
作者:互联网
我正在努力解决这个问题,主要是因为重复可能会减少 – 希望如此.
一般的想法是显示给定月份的每个表的总和并将其显示为数据透视表.
目前的代码在我看来非常混乱和重复,但主要的是它不允许我进行计算,因为UNION加入.
对于每个月如下(我假设这必须是一个衍生表,它取另一个的值并计算每个月的这个公式):
Calculation Formula = (
employees_salaries +
employees_salaries_insurence_costs +
employees_agreement +
employees_agreement_insurence_cost +
employees_extras +
employees_to_hand +
employees_delegations ) - employees_deductions
当前查询工作正常显示所有内容但问题和所需输出:
>问题:是否有任何可能的查询缩小
– 可能的查询结构以启用计算公式
期望的输出:当前的布局是需要保留的
我尝试了几天,但我无法完成我想要的结果,任何提示都会非常有用.
产量
+------------------------------------+---------------------+------+-------+-------+-----+------+-------+----------+-----------+---------+----------+----------+
| employees_salaries | January | Febr | March | April | May | June | July | August | September | October | November | December |
+------------------------------------+---------------------+------+-------+-------+-----+------+-------+----------+-----------+---------+----------+----------+
| employees_salaries | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 15826.12 | 0 | 0 | 0 | 0 |
| Calculations | Calculation Formula | | | | | | | | | | | |
| employees_salaries_insurence_costs | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 5044.44 | 0 | 0 | 0 | 0 |
| employees_agreement | 0 | 0 | 0 | 0 | 0 | 0 | 250 | 0 | 0 | 0 | 0 | 3550 |
| employees_agreement_insurence_cost | 0 | 0 | 0 | 0 | 0 | 0 | 71.05 | 0 | 0 | 0 | 0 | 178.65 |
| employees_extras | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1.00 | 0 | 0 |
| employees_deductions | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 45.60 | 0 | 1.00 | 0 | 0 |
| employees_to_hand | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 111.00 | 555.00 | 0 |
| employees_delegations | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2520 | 540 | 0 | 0 |
+------------------------------------+---------------------+------+-------+-------+-----+------+-------+----------+-----------+---------+----------+----------+
MCVE示例架构:https://www.db-fiddle.com/f/8RvfD3uA4cSSVgmhoP2co6/9
解决方法:
扩展关于减少查询employees_salaries和employees_agreement表的次数的评论/问题……
我们可以使用笛卡尔积(也就是交叉连接)和2行虚拟表来解开这些表,例如:
select case when c.col1 = 'a'
then 'employees_salaries'
else 'employees_salaraies_insurence_cost'
end as ctype,
mmonth as cdate,
case when c.col1 = 'a'
then gross
else insurence_cost1+insurence_cost2
end as camount
from employees_salaries
cross
join (select 'a' as col1
union all
select 'b') c
where year(mmonth) = year(curdate())
ctype cdate camount
---------------------------------- ---------- -------
employees_salaries 2017-08-01 1000
employees_salaraies_insurence_cost 2017-08-01 308.7
employees_salaries 2017-08-01 2000
employees_salaraies_insurence_cost 2017-08-01 666.4
....
然后,我们将这些“unpivot”查询放入我们之前的派生表中.
关于生成计算记录的要求(根据给定的计算公式每月总结),首先是一些假设:
>所有数值均为正数(包括扣除)
>根据OP的评论,目标数据库是Maria 10.1,它不支持cte
为了计算我们的总数,我们将使用一组12个变量(@ s1 – @ s12)来保持每月值的运行记录,同时进行调整以防止为变量显示单独的列…
样本数据:
create table t1(a int);
insert into t1 values (1),(2),(3);
首先使用@s来保持运行总和:
select 'raw',a,@s:=@s+a
from t1
cross
join (select @s:=0) v; /* initialize our variable */
a @s:=@s+a
---- -- --------
raw 1 1
raw 2 3
raw 3 6
注意我们的变量赋值如何显示为第3列,显示的值是变量的“新”值.
我们可以消除第3列并仍然执行我们的计算:a)将变量赋值的结果乘以零(0)和b)将此归零结果添加到另一个数字(例如,在这种情况下我们的列),例如:
select 'raw',a + (0* @s:=@s+a) as 'a'
from t1
cross
join (select @s:=0) v;
a
---- --
raw 1
raw 2
raw 3
最后,我们可以使用union all来显示我们的最终总和,如下所示:
select 'raw',a + (0* @s:=@s+a) as 'a'
from t1
cross
join (select @s:=0) v
union all
select 'sum',@s;
a
---- --
raw 1
raw 2
raw 3
sum 6 <=== @s
对于实际计算…我们想要添加所有数字,扣除值除外.虽然我们可以添加一堆case表达式来确定何时添加vs减去一个值,而是我们将:
>当我们从基表中提取时,自动否定所有扣减值
>为了显示目的,我们将应用abs(.. value ..);这将允许我们将扣减行显示为正值
>对于我们的变量赋值,我们只需按原样添加当前的camount(对于大多数列,它都是正数,对于减去的负数是负数)
当我们将abs()和zero’d-out变量赋值绑定在一起时,我们会得到这样的结果:
select ctype as employees_salaries,
/* need to make sure the variable assignments take place inside
the `sum()` constructs for the `group by` to function properly.
*/
COALESCE(SUM(case when month(cdate)=1 then abs(camount) + (0*@s1:=@s1 +camount) end),0) As January,
COALESCE(SUM(case when month(cdate)=2 then abs(camount) + (0*@s2:=@s2 +camount) end),0) As Febr,
....
from
( /* dual-unpivot, multi-union query of the source tables */ )
cross /* initialize our variables */
join (select @s1:=0, @s2:=0, @s3:=0, @s4:=0, @s5:=0, @s6:=0,
@s7:=0, @s8:=0, @s9:=0, @s10:=0, @s11:=0, @s12:=0) v
group by ctype, year(cdate)
union all
/* display our monthly totals
*/
select 'Calculations',
@s1, @s2, @s3, @s4, @s5, @s6,
@s7, @s8, @s9, @s10, @s11, @s12
最后但并非最不重要的是,我们将添加一些复杂的order by子句,以确保我们的计算行最后显示,同时按其ctype / name排序其他记录;对于所有源记录,我们将生成零(0),对于Calculations行,我们将生成一(1);然后我们按生成的数字和ctype / name值排序:
order by case when employees_salaries != 'Calculations' then 0 else 1 end, employees_salaries
这是这个univot @variables解决方案的更新fiddle.
注意:一些总和显示超过2个小数位的准确性…不确定那里的问题…应该很容易根据需要重新格式化数据.
标签:mysql-5-7,mysql 来源: https://codeday.me/bug/20190807/1605654.html