SQL避免基于LIKE表达式多次对行进行求和

时间:2011-08-27 12:06:48

标签: sql aggregate mutual-exclusion

我有一个包含列id,tDate,description,cashOut,cashIn的银行交易的表格。我想看看我是如何花钱的,特别是在亚马逊和一家名为Mazo的商店,所以我想得到这样的结果:

Month   Amazon   Mazo   Total
1       100      200    300

我试过这个:

SELECT
    MONTH(tDate) AS Month,
    SUM(IF(description LIKE '%amazon%',cashOut,0)) AS Amazon,
    SUM(IF(description LIKE '%mazo%',cashOut,0)) AS Mazo,
    SUM(cashOut) AS Total
FROM `transactions` 
GROUP BY Month

但是,我得到了以下内容:

Month   Amazon   Mazo   Total
1       100      300    300

这个SQL查询的问题在于“mazo”交易的总和是错误的,因为它也加起来了“亚马逊”交易。

我希望选择要相互排斥的事务或类似的事务,以便每个事务只是上述一个SUM的一部分(不依赖于PHP或类似事件)。 (我的表包含的数据远远超过此数据,而且我有很多搜索条件,因此使用'%mazo%'作为搜索词是不够的。我需要一个解决问题的通用解决方案。)

有人有建议吗?

表及其数据的详细信息:

CREATE TABLE `transactions` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`tDate` date NOT NULL,
`description` varchar(200) NOT NULL,
`cashOut` decimal(10,0) NOT NULL,
`cashIn` decimal(10,0) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB 

INSERT INTO `transactions` (`id`, `tDate`, `description`, `cashOut`, `cashIn`) VALUES
(1, '2010-01-05', 'amazon', '100', '0'),
(4, '2010-01-15', 'mazo', '200', '0');

4 个答案:

答案 0 :(得分:2)

您可以通过标记内部查询中的每一行,然后对其进行过滤来创建互斥组:

SELECT
    MONTH(tDate) AS Month,
    SUM(IF(flag = 'amazon', cashOut, 0)) AS Amazon,
    SUM(IF(flag = 'mazo', cashOut, 0)) AS Mazo,
    SUM(IF(flag = 'other', cashOut, 0)) AS Other,
    SUM(cashOut) AS Total
FROM (
    SELECT tDate, cashOut,
        CASE
            WHEN description LIKE '%amazon%' THEN 'amazon'
            WHEN description LIKE '%mazo%' THEN 'mazo'
            ELSE 'other'
        END AS flag
    FROM transactions
) x
GROUP BY Month

这样,如果某个事务匹配多个关键字,您将永远不会计算相同的事务两次。如果您不想在查询中重复两次相同的关键字,并且可以使用类似的列表:

Month   What     Sum
1       amazon   100
2       mazo     200

然后你可以使用:

SELECT
    MONTH(tDate) AS Month,
    flag AS What,
    SUM(cashOut) AS Total
FROM (
    SELECT tDate, cashOut,
        CASE
            WHEN description LIKE '%mazo%' THEN 'mazo'
            WHEN description LIKE '%amazon%' THEN 'amazon'
            ELSE 'other'
        END AS flag
    FROM transactions
) x
GROUP BY Month, flag

答案 1 :(得分:1)

您正在搜索包含mazo的字符串。如果您只想要Mazo,请更改:

SUM(IF(description LIKE '%mazo%',cashOut,0)) AS Mazo,

SUM(IF(description = 'mazo',cashOut,0)) AS Mazo,

编辑:在回复您的评论时,您可以使用正则表达式[[:<:]]搜索word boundaries

SUM(IF(description REGEXP '[[:<:]]mazo[[:>:]]',cashOut,0)) AS Mazo,

答案 2 :(得分:1)

SELECT
    MONTH(tDate) AS Month,
    SUM(IF(description LIKE '%amazon%',cashOut,0)) AS Amazon,
    SUM(IF(description LIKE '%mazo%' AND description NOT LIKE '%amazon%',cashOut,0)) AS Mazo,
    SUM(cashOut) AS Total
FROM `transactions` 
GROUP BY Month

答案 3 :(得分:0)

=与确切文字一起使用,而不是like,只需丢失IF即可。试试这个:

SELECT
    MONTH(tDate) AS Month,
    SUM((description = 'Amazon') * cashOut) AS Amazon,
    SUM((description = 'Mazo') * cashOut) AS Mazo,
    SUM(cashOut) AS Total
FROM `transactions`
GROUP BY Month