简体   繁体   English

如何在MYSQL中减去两个声明的变量

[英]How do I subtract two declared variables in MYSQL

The question I am working on is as follows: 我正在研究的问题如下:

What is the difference in the amount received for each month of 2004 compared to 2003? 与2003年相比,2004年每个月收到的金额有何不同?

This is what I have so far, 这就是我到目前为止

    SELECT @2003 = (SELECT sum(amount) FROM Payments, Orders
                WHERE YEAR(orderDate) = 2003
                AND Payments.customerNumber = Orders.customerNumber
                    GROUP BY MONTH(orderDate));

    SELECT @2004 = (SELECT sum(amount) FROM Payments, Orders
                WHERE YEAR(orderDate) = 2004
                AND Payments.customerNumber = Orders.customerNumber
                    GROUP BY MONTH(orderDate));

    SELECT MONTH(orderDate), (@2004 - @2003) AS Diff 
           FROM Payments, Orders
              WHERE Orders.customerNumber = Payments.customerNumber
                 Group By MONTH(orderDate);

In the output I am getting the months but for Diff I am getting NULL please help. 在输出中,我得到了几个月,但对于Diff,我得到了NULL,请帮助。 Thanks 谢谢

I cannot test this because I don't have your tables, but try something like this: 我无法测试此数据,因为我没有您的表格,但是请尝试如下操作:

SELECT a.orderMonth, (a.orderTotal - b.orderTotal ) AS Diff 
FROM 
    (SELECT MONTH(orderDate) as orderMonth,sum(amount) as orderTotal 
    FROM Payments, Orders
    WHERE YEAR(orderDate) = 2004
    AND Payments.customerNumber = Orders.customerNumber
        GROUP BY MONTH(orderDate)) as a,
   (SELECT MONTH(orderDate) as orderMonth,sum(amount) as orderTotal FROM Payments, Orders
    WHERE YEAR(orderDate) = 2003
    AND Payments.customerNumber = Orders.customerNumber
        GROUP BY MONTH(orderDate)) as b
WHERE a.orderMonth=b.orderMonth

I think this is the problem: 我认为这是问题所在:
In @2003 and @2004, you select only the sum. 在@ 2003和@ 2004中,仅选择总和。 And even if you group by the month you still select one column ie each row does not say what month it is select for. 即使按月分组,您仍然会选择一列,即每一行都不会说它选择的月份。 So when you try to subtract SQL asks which row in @2003 should be subtracted from @2004. 因此,当您尝试减去SQL时,询问@ 2003中的哪一行应从@ 2004中减去。
So I think the solution is to select the month with the sum and do the subtract later based on the month. 因此,我认为解决方案是选择有总和的月份,然后根据该月份进行减法。

Q: How do I subtract two declared variables in MySQL. 问:如何在MySQL中减去两个声明的变量。

A: You'd first have to DECLARE them. 答:您首先需要对它们进行声明。 In the context of a MySQL stored program. 在MySQL存储程序的上下文中。 But those variable names wouldn't begin with an at sign character. 但是这些变量名不会以at符号字符开头。 Variable names that start with an at sign @ character are user-defined variables. @符号开头的变量名是用户定义的变量。 And there is no DECLARE statement for them, we can't declare them to be a particular type. 而且没有针对它们的DECLARE语句,我们无法将它们声明为特定类型。

To subtract them within a SQL statement 在SQL语句中减去它们

SELECT @foo - @bar AS diff

Note that MySQL user-defined variables are scalar values. 请注意,MySQL用户定义的变量是量值。

Assignment of a value to a user-defined variable in a SELECT statement is done with the Pascal style assignment operator := . 在SELECT语句中,使用Pascal样式分配运算符:=将值分配给用户定义的变量。 In an expression in a SELECT statement, the equals sign is an equality comparison operator. 在SELECT语句的表达式中,等号是一个相等比较运算符。

As a simple example of how to assign a value in a SQL SELECT statement 作为如何在SQL SELECT语句中分配值的简单示例

SELECT @foo := '123.45' ; 

In the OP queries, there's no assignment being done. 在OP查询中,没有完成分配。 The equals sign is a comparison, of the scalar value to the return from a subquery. 等号是标量值与子查询返回值的比较。 Are those first statements actually running without throwing an error? 那些第一条语句是否在实际运行中而不会引发错误?

User-defined variables are probably not necessary to solve this problem. 用户定义的变量可能对于解决此问题不是必需的。

You want to return how many rows? 您要返回多少行? Sounds like you want one for each month. 听起来您每个月要一个。 We'll assume that by "year" we're referring to a calendar year, as in January through December. 我们假设“年份”是指日历年,例如1月到12月。 (We might want to check that assumption. Just so we don't find out way too late, that what was meant was the "fiscal year", running from July through June, or something.) (我们可能想检查一下这个假设。只是为了避免太晚才发现,这意味着从7月到6月的“财政年度”之类的东西。)

How can we get a list of months? 我们如何获得月份清单? Looks like you've got a start. 看来您已经开始了。 We can use a GROUP BY or a DISTINCT. 我们可以使用GROUP BY或DISTINCT。

The question was... "What is the difference in the amount received ... " 问题是……“收款额有什么区别……”

So, we want amount received . 所以,我们希望收到的款项。 Would that be the amount of payments we received? 那就是我们收到的付款额吗? Or the amount of orders that we received? 还是我们收到的订单数量? (Are we taking orders and receiving payments? Or are we placing orders and making payments?) (我们是在接受订单并接收付款吗?还是在下订单并进行付款?)

When I think of "amount received", I'm thinking in terms of income. 当我想到“收到的金额”时,我在考虑收入。

Given the only two tables that we see, I'm thinking we're filling orders and receiving payments. 鉴于我们只看到两个表格,我想我们正在填写订单并收到付款。 (I probably want to check that, so when I'm done, I'm not told... "oh, we meant the number of orders we received" and/or "the payments table is the payments we made, the 'amount we received' is in some other table" (我可能想检查一下,所以完成后,不会告诉我……“哦,我们的意思是收到的订单数量”和/或“付款表是我们已付款的金额,我们收到的金额在其他表格中”

We're going to assume that there's a column that identifies the "date" that a payment was received, and that the datatype of that column is DATE (or DATETIME or TIMESTAMP), some type that we can reliably determine what "month" a payment was received in. 我们将假设有一列标识接收付款的“日期”,并且该列的数据类型为DATE(或DATETIME或TIMESTAMP),我们可以可靠地确定该日期的“月”已收到付款。

To get a list of months that we received payments in, in 2003... 为了获得我们在2003年收到付款的月份清单,...

 SELECT MONTH(p.payment_received_date)
   FROM payment_received p
  WHERE p.payment_received_date >= '2003-01-01'
    AND p.payment_received_date <  '2004-01-01'
  GROUP BY MONTH(p.payment_received_date)
  ORDER BY MONTH(p.payment_received_date)

That should get us twelve rows. 那应该给我们十二行。 Unless we didn't receive any payments in a given month. 除非我们在给定的月份没有收到任何付款。 Then we might only get 11 rows. 那么我们可能只会得到11行。 Or 10. Or, if we didn't receive any payments in all of 2003, we won't get any rows back. 或10。或者,如果我们在2003年全年都没有收到任何付款,我们将不会退回任何行。

For performance, we want to have our predicates (conditions in the WHERE clause0 reference bare columns. With an appropriate index available, MySQL will make effective use of an index range scan operation. If we wrap the columns in a function, eg 为了提高性能,我们希望使用谓词(WHERE子句中的条件引用裸列。使用适当的索引,MySQL将有效地使用索引范围扫描操作。如果将列包装在函数中,例如

  WHERE YEAR(p.payment_received_date) = 2003 

With that, we will be forcing MySQL to evaluate that function on every flipping row in the table, and then compare the return from the function to the literal. 这样,我们将强制MySQL在表中的每个翻转行上评估该函数,然后比较该函数与文字的返回值。 We prefer not do do that, and reference bare columns in predicates (conditions in the WHERE clause). 我们宁愿不这样做,而在谓词中引用裸列(WHERE子句中的条件)。

We could repeat the same query to get the payments received in 2004. All we need to do is change the date literals. 我们可以重复相同的查询以获取2004年收到的款项。我们要做的就是更改日期文字。

Or, we could get all the rows in 2003 and 2004 all together, and collapse that into a list of distinct months. 或者,我们可以将2003年和2004年的所有行汇总在一起,然后将其折叠为不同月份的列表。

We can use conditional aggregation. 我们可以使用条件聚合。 Since we're using calendar years, I'll use the YEAR() shortcut (rather than a range check). 由于我们使用的是日历年,因此我将使用YEAR()快捷方式(而不是范围检查)。 Here, we're not as concerned with using a bare column inside the expression. 在这里,我们不关心在表达式中使用裸列。

SELECT MONTH(p.payment_received_date) AS `mm`
     , MAX(MONTHNAME(p.payment_received_date)) AS `month`
     , SUM(IF(YEAR(p.payment_received_date)=2004,p.payment_amount,0)) AS `2004_month_total`
     , SUM(IF(YEAR(p.payment_received_date)=2003,p.payment_amount,0)) AS `2003_month_total`
     , SUM(IF(YEAR(p.payment_received_date)=2004,p.payment_amount,0))
     - SUM(IF(YEAR(p.payment_received_date)=2003,p.payment_amount,0)) AS `2004_2003_diff`
  FROM payment_received p
 WHERE p.payment_received_date >= '2003-01-01'
   AND p.payment_received_date <  '2005-01-01'
 GROUP
    BY MONTH(p.payment_received_date)
 ORDER
    BY MONTH(p.payment_received_date)

If this is a homework problem, I strongly recommend you work on this problem yourself. 如果这是一个家庭作业问题,我强烈建议您自己解决此问题。 There are other query patterns that will return an equivalent result. 还有其他查询模式将返回等效结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM