简体   繁体   中英

SQL, calculating SUM of two columns A, B based on value(flag) in column C, performance

Lets say you have table Table1 with following columns: | A | B | C | D | | A | B | C | D | and you need to produce following result set via SELECT and GROUP BY D statement

| X1 | X2 | X3 | X4 | X5 | X6 |

where those columns are defined as:

X1 = sum(A) if C = 0 OR 12
X2 = sum(B) if C = 0 OR 12 
X3 = sum(A) if C = 2 
X4 = sum(B) if C = 2
X5 = sum(A) if C = 1
X6 = sum(B) if C = 1

Values for column C goes from 0, 1, 2, 3, ..., 12 .
One approach would be to use subquery for each calculation such as:

SELECT
    (
      SELECT COALESCE(SUM(A), 0.00)
      FROM Table1
      WHERE C = 0 OR C = 12
    ) AS 'X1',
    (
      SELECT COALESCE(SUM(B), 0.00)
      FROM Table1
      WHERE C = 0 OR C = 12
    ) AS 'X2',
    (
      SELECT COALESCE(SUM(A), 0.00)
      FROM Table1
      WHERE C = 2
    ) AS 'X3',
    (
      SELECT COALESCE(SUM(B), 0.00)
      FROM Table1
      WHERE C = 2
    ) AS 'X4',
    (
      SELECT  COALESCE(SUM(A), 0.00)
      FROM Table1
      WHERE C = 1
    ) AS 'X5',
    (
      SELECT COALESCE(SUM(B), 0.00)
      FROM Table1
      WHERE C = 1
    ) AS 'X6'
FROM Table 1
WHERE C IN (0, 1, 2, 12)
GROUP BY D

Performance wise, to me seems like a brute-force. Probably same thing could be converted using CASE instead subqueries , but i doubt it would affect performance in positive way? or it should? Any other/better approach(es) in mind? As an general question how number of subqueries affects performance?

Use conditional aggregation:

select d,
       sum(case when c in (0, 12) then a else 0 end) as x1,
       sum(case when c in (0, 12) then b else 0 end) as x2, 
       sum(case when c = 2 then a else 0 end) as x3,
       . . .
from t
group by d;

This should definitely be faster than subqueries.

Gordon beat me to the answer. This can be done with pretty standard SQL.

SQL Fiddle

MySQL 5.6 Schema Setup :

CREATE TABLE t1 (a int, b int, c int, d int) ; 

INSERT INTO t1 (a,b,c,d)
SELECT 1,1,0,10 UNION ALL
SELECT 1,1,0,10 UNION ALL
SELECT 1,1,0,20 UNION ALL
SELECT 1,1,0,20 UNION ALL
SELECT 1,1,1,10 UNION ALL
SELECT 1,1,1,20 UNION ALL
SELECT 1,1,2,10 UNION ALL
SELECT 1,1,2,30 UNION ALL
SELECT 1,1,3,10 UNION ALL
SELECT 1,1,5,10 UNION ALL
SELECT 1,1,12,10 UNION ALL
SELECT 1,1,5,10 UNION ALL
SELECT 1,1,5,10 UNION ALL
SELECT 1,1,5,20 UNION ALL
SELECT 1,1,5,20

Query 1 :

SELECT d
    , sum(CASE WHEN c IN (0,12) THEN a ELSE 0 END) AS x1 
    , sum(CASE WHEN c IN (0,12) THEN b ELSE 0 END) AS x2
    , sum(CASE WHEN c = 2 THEN a ELSE 0 END) AS x3
    , sum(CASE WHEN c = 2 THEN b ELSE 0 END) AS x4
    , sum(CASE WHEN c = 1 THEN a ELSE 0 END) AS x5
    , sum(CASE WHEN c = 1 THEN b ELSE 0 END) AS x6
FROM t1
WHERE c IN (0,1,2,12)
GROUP BY d

Results :

|  d | x1 | x2 | x3 | x4 | x5 | x6 |
|----|----|----|----|----|----|----|
| 10 |  3 |  3 |  1 |  1 |  1 |  1 |
| 20 |  2 |  2 |  0 |  0 |  1 |  1 |
| 30 |  0 |  0 |  1 |  1 |  0 |  0 |

If you have a lot of values in c that aren't in 0,1,2,12 , then you can use the WHERE to pare down the result set you'll be aggregating. Otherwise, you can probably remove it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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