如何在一列中获取所有值mysql sum和subtract

时间:2017-11-01 03:18:26

标签: php mysql

我为会计应用程序创建了一个API。我在一栏中有收入和支出。如何将所有收入和支出相加并减去?

这是我的代码:

private function list_recap() {

    if($this->get_request_method() != "GET") {
        $this->response('', 406);
    }

    $year  = $this->_request['year'];
    $month = $this->_request['month'];

    $sqlPlus = $this->db->query("SELECT SUM(nominal) 
            FROM lap_keuangan 
                WHERE YEAR(tanggal) = '$year' 
                AND MONTH(tanggal) = '$month' 
           AND kategori = 1");

    $sqlMin  = $this->db->query("SELECT SUM(nominal) 
            FROM lap_keuangan 
                WHERE YEAR(tanggal) = '$year' 
                AND MONTH(tanggal) = '$month' 
                AND kategori = -1");


    $result = array();
    while($rowPlus = $sqlPlus->fetch(PDO::FETCH_ASSOC)) {
        $plus = $result[] = $rowPlus;
    }

    while($rowMin = $sqlMin->fetch(PDO::FETCH_ASSOC)) {
        $minus = $result[] = $rowMin;
    }

    $this->response($this->json($result), 200);
}

2 个答案:

答案 0 :(得分:1)

使用一个SELECT语句来检索" plus"," minus"和"总计"。我们可以使用条件聚合。给定WHERE子句中的条件可以保证kategori的值为1或-1,我们可以将nominal乘以该值,并将其与SUM相加。

虽然我们正在努力,但我们应该清除SQL Injection漏洞。我们从不希望在SQL文本中包含可能不安全的值。

https://www.owasp.org/index.php/SQL_Injection

我们要么在包含它们之前正确地转义值,要么使用带有绑定占位符的预准备语句。 (它并不那么难;并且没有任何有效的理由不去做其中一个。)

为了提高性能,我们希望在 bare 列上有条件,而不是在表达式中包装列。如果tanggal是DATE,DATETIME或TIMESTAMP数据类型,我们可以将该列的条件指定为值范围。 (如果有合适的索引,MySQL允许MySQL使用范围扫描操作,而不是评估表中每个行的表达式。)

我可能会将$year$month值转换为yyyy-mm-01格式的字符串,然后将该日期字符串传递给查询。但是我们可以将$ year和$ month值传递给查询,并让MySQL将其转换为我们的日期。

这样的事情:

# static SQL text (no variable interpolation) mitigates SQL Injection 
$sql = 
"SELECT SUM( k.nominal * IF(k.kategori=  1 ,1,0) )  AS kat_plus
      , SUM( k.nominal * IF(k.kategori= -1 ,1,0) )  AS kat_minus 
      , SUM( k.nominal * k.kategori              )  AS kat_total
   FROM lap_keuangan k 
  WHERE k.tanggal >= STR_TO_DATE(CONCAT( ? ,'-', ? ,'-01'),'%Y-%m-%d')
    AND k.tanggal <  STR_TO_DATE(CONCAT( ? ,'-', ? ,'-01'),'%Y-%m-%d') + INTERVAL 1 MONTH
    AND k.kategori IN (-1,1)";

# prepare
$sth = $this->db->prepare($sql);

使用bindValue为每个绑定占位符提供值并执行

# execute
$sth->bindValue(1, $year    ,PDO::PARAM_STR);
$sth->bindValue(2, $month   ,PDO::PARAM_STR);
$sth->bindValue(3, $year    ,PDO::PARAM_STR);
$sth->bindValue(4, $month   ,PDO::PARAM_STR);
$sth->execute(); 

或者使用位置绑定,我们可以跳过bindValue并只传递一个数组来执行:

# execute
$sth->execute(array($year,$month,$year,$month));

然后获取行,并访问数组成员

$row = $sth->fetch(PDO::FETCH_ASSOC);

$kat_plus  = $row['kat_plus'];
$kat_minus = $row['kat_minus'];
$kat_total = $row['kat_total'];

如果PDO没有被配置为抛出异常,即

$this->$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

然后添加每个PDO函数调用(准备,执行,获取)成功/失败的检查并处理代码中的错误。

答案 1 :(得分:0)

您可以使用CASE-THEN-ELSE构造,尝试执行此SQL语句:

SELECT
    SUM(CASE WHEN kategori = 1 THEN nominal ELSE 0 END) -
    SUM(CASE WHEN kategori = -1 THEN nominal ELSE 0 END)
FROM lap_keuangan
WHERE
    YEAR(tanggal) = '$year'
    AND MONTH(tanggal) = '$month'
    AND kategori = 1

PS:

您的代码容易受到SQL注入攻击。您不能使用字符串连接传递SQL查询参数。请改用PDO并绑定参数。