iT邦幫忙

2022 iThome 鐵人賽

DAY 22
0
Software Development

SQL rookie 之天天魯一下系列 第 22

Day 22 - Active Record Query Interface: group method(2)

  • 分享至 

  • xImage
  •  

Hi, 大家好!

昨天跟著API dock 研究group這方法,但還是很多不熟悉的地方,今天就嘗試繼續研究、理解

我們先回顧昨天最後研究的地方:

irb(main):078:0> Todo.select(:completed).group(:completed).count
   (0.7ms)  SELECT COUNT("todos"."completed") AS count_completed, "todos"."completed" AS todos_completed FROM "todos" GROUP BY "todos"."completed"
{
    false => 110,
     true => 90
}

得知可以這麼將todos group,並算出各自的數量;然而今天在確認Rails Guide 時,看到其實連select(:completed) 都能省略:

irb(main):002:0> Todo.group(:completed).count
   (8.6ms)  SELECT COUNT(*) AS count_all, "todos"."completed" AS todos_completed FROM "todos" GROUP BY "todos"."completed"
{
    false => 110,
     true => 90
}

先讓我們觀察看看兩者的SQL statement 的差別:

# 有先select
SELECT COUNT("todos"."completed") AS count_completed, "todos"."completed" AS todos_completed FROM "todos" GROUP BY "todos"."completed"

# 直接group 後count
SELECT COUNT(*) AS count_all, "todos"."completed" AS todos_completed FROM "todos" GROUP BY "todos"."completed"

接著暫時得出以下小結:

  1. SQL GROUP BY 的statement 是一樣的(GROUP BY "todos"."completed"
  2. SELECT 的statement 各有兩部分,後半段也是一樣的("todos"."completed" AS todos_completed
  3. 所以差別主要是前面的SELECT COUNT("todos"."completed") AS count_completed vs. SELECT COUNT(*) AS count_all,但因為AS 只是別稱所以可以無視;所以重點是在COUNT()語法回傳的資料結構嗎?

應該不是?感覺重點是後面的group by

然而查看Rails Guide 和Rails API 又看不出端倪,只知道兩者雖然都是for Rails v7.0.4,不過不僅敘述有別,且Rails API 上的方法模仿起來的效果有限~~~

Rails Guide:
Rails Guide

vs.

Rails API
Rails API

但我想,也許Rails 的group概念跟SQL 的GROUP BY也許是有差異的吧?

Hmm...


不如我們接著稍微看看SQL 的GROUP BY 吧?XD

SQL 的GROUP BY 是將SELECT 的每列資料依據某欄位分組,得到的結果類似SQL 的Aggregate Function,如COUNT()、SUM()、MIN() 等

我們以todos 資料表來做練習:

首先,該資料表是長這樣子:
https://ithelp.ithome.com.tw/upload/images/20221006/20150959WxbRRNzHay.png

當我們利用COUNT(*)會得到:

SELECT COUNT(*) FROM todos

https://ithelp.ithome.com.tw/upload/images/20221006/20150959orn0JSTXZO.png

不管我們用什麼欄位替換COUNT(*)都是得到同樣的結果;然而,當我們搭配GROUP BY 的時候,就會有令人意想不到的驚喜!?
https://ithelp.ithome.com.tw/upload/images/20221007/201509593HuatqJsGs.png

SELECT COUNT(completed) FROM todos GROUP BY completed

https://ithelp.ithome.com.tw/upload/images/20221007/20150959WhHIquRejg.png

SELECT COUNT(id) FROM todos GROUP BY completed

SELECT COUNT(id) FROM todos GROUP BY id

https://ithelp.ithome.com.tw/upload/images/20221007/201509594fXMpO59pQ.png

SELECT COUNT(completed) FROM todos GROUP BY "userId"

https://ithelp.ithome.com.tw/upload/images/20221007/20150959Oul8Wg2HiF.png

我覺得PostgrSQL Tutorials 這句話很有力地解釋了上面的狀態:

It’s possible to use other clauses of the SELECT statement with the GROUP BY clause.

PostgreSQL evaluates the GROUP BY clause after the FROM and WHERE clauses and before the HAVING SELECT, DISTINCT, ORDER BY and LIMIT clauses.

GROUP BY clause 在Select 前先被資料庫處理了,因此若是在句子內看到GROUP BY,要先從
FROM/WHERE -> GROUP BY -> SELECT, DISTINCT, ORDER BY 等statement

這大概也能說明為何前面無論SELECT 了什麼,還是以GROUP BY 欄位的獨特值來分組,因此才會得到這結果吧!?

但究竟我們要怎麼利用GROUP BY、理解對等的語句而不遇到這錯誤呢:

SELECT * FROM todos GROUP BY completed

https://ithelp.ithome.com.tw/upload/images/20221007/201509593xqAW5X8wb.png

就讓我們再繼續研究下去吧!


但、今天就先到這吧,謝謝大家 XD


上一篇
Day 21 - Active Record Query Interface: group method(1)
下一篇
Day 23 - SQL where clause with case when
系列文
SQL rookie 之天天魯一下30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言