在mysql中使用COUNT 或者SUM函數計算記錄總數

count函數的做用

想要真正的理解count函數,咱們就必須明白count函數的做用。
做用一:統計某一列非空(not null)值得數量,即統計某列有值得結果數,使用count(col),其中col爲設置爲not null 的行
做用二:統計結果集的行數,此時不用管某列是否爲null值。即便用count(*).
明白了這點,咱們就應該知道MySQL的count(*)並非想象中的那樣,統計每一列的值,而是直接忽視掉全部列,直接統計行數,那麼它的效率確定是很高的。
可是有一點,當col指定了該字段爲NOT NULL時實際上,MySQL會自動將count(col)轉爲count(*),可是這樣也一樣耗費了些時間,若是col沒有指定爲NOT NULL的話,那麼效率就更低了,MySQL就必需要判斷每一行的值是否爲空。
因此綜上所述,最好優先使用select count(*)
當統計某一列等於多少的值得時候可使用下面兩種方法。
#統計出表中id爲23的值的數量的兩種方法
SELECT SUM(IF(id = 23,1,0)) FROM table 
SELECT COUNT(id = 23 OR NULL) FROM table //爲了讓id不爲23的時候,結果爲null,而count(null)=0html

解釋:mysql

查了下資料,count('任意內容')都會統計出全部記錄數,由於count只有在碰見null時不計數,即count(null)=0,sql

所以前者單引號內無論輸入什麼值都會統計出全部記錄數,因此count(id='23')單引號裏你填什麼年份都是1000條記錄,由於他們都not null!數據庫

而爲了讓查找id=23的這個條件生效,就必須加上or null,告訴count,id=23爲計數條件且不統計記錄爲null的值。編程

Count(NULL)是 不統計數, 至於加上or NULL , 很像其餘編程裏的or運算符,第一個表達式是true就是不執行or後面的表達式,第一個表達式是false 執行or後面的表達式 。當id不爲23的時候,id= 23 or NULL 的結果是NULL,Count就不會統計上這條記錄數。函數

又如:測試

SELECT ID FROM EPRJ_LIST WHERE EPRJ_INFO_ID = 78821 AND (NUM >10 OR NULL)

該SQL語句也是查詢NUM >10並且NUM不爲NULL的語句(純粹是爲了測試,能夠不加or null條件的),由於WHERE條件中若是直接寫成:WHERE 條件1 AND NULL 或者WHERE NULL(即以NULL做爲一個單獨的查詢條件),那麼返回的結果爲空集ui

而count(id> 23 or null)能夠這麼理解:SELECT COUNT(*) FROM ...WHERE (id> 23 or null)spa

 

mysql 中sum (if())與case

先來一個簡單的sum.net

select sum(qty) as total_qty from inventory_product group by product_id

這樣就會統計出全部product的qty.

可是很不幸,咱們的系統裏面竟然有qty爲負值。而我只想統計那些正值的qty,加上if function就能夠了。 SQL爲:

select sum(if(qty > 0, qty, 0)) as total_qty   from inventory_product group by product_id

意思是若是qty > 0, 將qty的值累加到total_qty, 不然將0累加到total_qty.

如下是sum(if())的例子,:

select
  sum( if( qty > 0, qty, 0)) as total_qty,//用來計算qty >0的全部記錄的字段qty值的彙總(從0累加,每次累加qty)
   sum( if( qty < 0, 1, 0 )) as negative_qty_count//計算qty < 0的記錄條數(從0累加,每次累加1)
from inventory_product group by product_id

 

上面主要介紹sum (if())的定義,如下是關於數據庫行列轉換的一些方法整理,也是拷貝其餘網友的博客的,作了一些刪減。

現整理解法以下:

數據樣本:

create table tx( 
 id int primary key, 
 c1 char(2), 
 c2 char(2), 
 c3 int 
);

insert into tx values 
(1 ,'A1','B1',9), 
(2 ,'A2','B1',7), 
(3 ,'A3','B1',4), 
(4 ,'A4','B1',2), 
(5 ,'A1','B2',2), 
(6 ,'A2','B2',9), 
(7 ,'A3','B2',8), 
(8 ,'A4','B2',5), 
(9 ,'A1','B3',1), 
(10 ,'A2','B3',8), 
(11 ,'A3','B3',8), 
(12 ,'A4','B3',6), 
(13 ,'A1','B4',8), 
(14 ,'A2','B4',2), 
(15 ,'A3','B4',6), 
(16 ,'A4','B4',9), 
(17 ,'A1','B4',3), 
(18 ,'A2','B4',5), 
(19 ,'A3','B4',2), 
(20 ,'A4','B4',5);

mysql> select * from tx;
+----+------+------+------+
| id | c1   | c2   | c3   |
+----+------+------+------+
|  1 | A1   | B1   |    9 |
|  2 | A2   | B1   |    7 |
|  3 | A3   | B1   |    4 |
|  4 | A4   | B1   |    2 |
|  5 | A1   | B2   |    2 |
|  6 | A2   | B2   |    9 |
|  7 | A3   | B2   |    8 |
|  8 | A4   | B2   |    5 |
|  9 | A1   | B3   |    1 |
| 10 | A2   | B3   |    8 |
| 11 | A3   | B3   |    8 |
| 12 | A4   | B3   |    6 |
| 13 | A1   | B4   |    8 |
| 14 | A2   | B4   |    2 |
| 15 | A3   | B4   |    6 |
| 16 | A4   | B4   |    9 |
| 17 | A1   | B4   |    3 |
| 18 | A2   | B4   |    5 |
| 19 | A3   | B4   |    2 |
| 20 | A4   | B4   |    5 |
+----+------+------+------+
20 rows in set (0.00 sec)

mysql>

指望結果

+------+-----+-----+-----+-----+------+
|C1    |B1   |B2   |B3   |B4   |Total |
+------+-----+-----+-----+-----+------+
|A1    |9    |2    |1    |11   |23    |
|A2    |7    |9    |8    |7    |31    |
|A3    |4    |8    |8    |8    |28    |
|A4    |2    |5    |6    |14   |27    |
|Total |22   |24   |23   |40   |109   |
+------+-----+-----+-----+-----+------+

1. 利用SUM(IF()) 生成列 + WITH ROLLUP 生成彙總行,並利用 IFNULL將彙總行標題顯示爲 Total

mysql> SELECT
    ->     IFNULL(c1,'total') AS total,
    ->     SUM(IF(c2='B1',c3,0)) AS B1,
    ->     SUM(IF(c2='B2',c3,0)) AS B2,
    ->     SUM(IF(c2='B3',c3,0)) AS B3,
    ->     SUM(IF(c2='B4',c3,0)) AS B4,
    ->     SUM(IF(c2='total',c3,0)) AS total
    -> FROM (
    ->     SELECT c1,IFNULL(c2,'total') AS c2,SUM(c3) AS c3
    ->     FROM tx
    ->     GROUP BY c1,c2
    ->     WITH ROLLUP
    ->     HAVING c1 IS NOT NULL
    -> ) AS A
    -> GROUP BY c1
    -> WITH ROLLUP;
+-------+------+------+------+------+-------+
| total | B1   | B2   | B3   | B4   | total |
+-------+------+------+------+------+-------+
| A1    |    9 |    2 |    1 |   11 |    23 |
| A2    |    7 |    9 |    8 |    7 |    31 |
| A3    |    4 |    8 |    8 |    8 |    28 |
| A4    |    2 |    5 |    6 |   14 |    27 |
| total |   22 |   24 |   23 |   40 |   109 |
+-------+------+------+------+------+-------+
5 rows in set, 1 warning (0.00 sec)

2. 利用SUM(IF()) 生成列 + UNION 生成彙總行,並利用 IFNULL將彙總行標題顯示爲 Total
mysql> select c1,
    -> sum(if(c2='B1',C3,0)) AS B1,
    -> sum(if(c2='B2',C3,0)) AS B2,
    -> sum(if(c2='B3',C3,0)) AS B3,
    -> sum(if(c2='B4',C3,0)) AS B4,SUM(C3) AS TOTAL
    -> from tx
    -> group by C1
    -> UNION
    -> SELECT 'TOTAL',sum(if(c2='B1',C3,0)) AS B1,
    -> sum(if(c2='B2',C3,0)) AS B2,
    -> sum(if(c2='B3',C3,0)) AS B3,
    -> sum(if(c2='B4',C3,0)) AS B4,SUM(C3) FROM TX
    -> ;
+-------+------+------+------+------+-------+
| c1    | B1   | B2   | B3   | B4   | TOTAL |
+-------+------+------+------+------+-------+
| A1    |    9 |    2 |    1 |   11 |    23 |
| A2    |    7 |    9 |    8 |    7 |    31 |
| A3    |    4 |    8 |    8 |    8 |    28 |
| A4    |    2 |    5 |    6 |   14 |    27 |
| TOTAL |   22 |   24 |   23 |   40 |   109 |
+-------+------+------+------+------+-------+
5 rows in set (0.00 sec)

3.  利用SUM(IF()) 生成列,直接生成結果再也不利用子查詢
mysql> select ifnull(c1,'total'),
    -> sum(if(c2='B1',C3,0)) AS B1,
    -> sum(if(c2='B2',C3,0)) AS B2,
    -> sum(if(c2='B3',C3,0)) AS B3,
    -> sum(if(c2='B4',C3,0)) AS B4,SUM(C3) AS TOTAL
    -> from tx
    -> group by C1 with rollup ;
+--------------------+------+------+------+------+-------+
| ifnull(c1,'total') | B1   | B2   | B3   | B4   | TOTAL |
+--------------------+------+------+------+------+-------+
| A1                 |    9 |    2 |    1 |   11 |    23 |
| A2                 |    7 |    9 |    8 |    7 |    31 |
| A3                 |    4 |    8 |    8 |    8 |    28 |
| A4                 |    2 |    5 |    6 |   14 |    27 |
| total              |   22 |   24 |   23 |   40 |   109 |
+--------------------+------+------+------+------+-------+
5 rows in set (0.00 sec)

4. 動態,適用於列不肯定狀況,

mysql> SET @EE=''; 
mysql> SELECT @EE:=CONCAT(@EE,'SUM(IF(C2=\'',C2,'\'',',C3,0)) AS ',C2,',') FROM (SELECT DISTINCT C2 FROM TX) A;

mysql> SET @QQ=CONCAT('SELECT ifnull(c1,\'total\'),',LEFT(@EE,LENGTH(@EE)-1),' ,SUM(C3) AS TOTAL FROM TX GROUP BY C1 WITH ROLLUP');
Query OK, 0 rows affected (0.00 sec)

mysql> PREPARE stmt2 FROM @QQ;
Query OK, 0 rows affected (0.00 sec)
Statement prepared

mysql> EXECUTE stmt2;
+--------------------+------+------+------+------+-------+
| ifnull(c1,'total') | B1   | B2   | B3   | B4   | TOTAL |
+--------------------+------+------+------+------+-------+
| A1                 |    9 |    2 |    1 |   11 |    23 |
| A2                 |    7 |    9 |    8 |    7 |    31 |
| A3                 |    4 |    8 |    8 |    8 |    28 |
| A4                 |    2 |    5 |    6 |   14 |    27 |
| total              |   22 |   24 |   23 |   40 |   109 |
+--------------------+------+------+------+------+-------+
5 rows in set (0.00 sec)

5.使用case,

 

SELECT ifnull(c1,'total')`,
   MAX(
        CASE
        WHEN c2= 'B1' THEN C3
        END
    ) AS B1,
    MAX(
        CASE
        WHEN c2= 'B2' THEN C3
        END
    ) AS B2,
    MAX(
        CASE
        WHEN c2= 'B3' THEN C3
        END
    ) AS B3,
    MAX(
        CASE
        WHEN c2= 'B4' THEN C3
        END
    ) AS B4
FROM tx  GROUP BY c1

 

其實數據庫中也能夠用 CASE WHEN / DECODE 代替 IF

參考博客:

http://blog.chinaunix.net/uid-7692530-id-2567582.html

相關文章
相關標籤/搜索