2017年10月31日 星期二

SQL GROUP BY MAX() 取所有欄位

假設有一個資料表如下
| Id | Message | GroupId | Date |
|-------------------------------|
| 1  | Hello   | 1       | 1:00 |
| 2  | Hello   | 1       | 1:01 |
| 3  | Hey     | 2       | 2:00 |
| 4  | Dude    | 3       | 3:00 |
| 5  | Dude    | 3       | 3:01 |
但我想撈取的結果如下
| Id | Message | GroupId | Date |
|-------------------------------|
| 1  | Hello   | 1       | 1:00 |
| 3  | Hey     | 2       | 2:00 |
| 4  | Dude    | 3       | 3:00 |
也就是想要Message不重複,然後Date取最小值得的,一般會這樣下SQL
SELECT Message,MIN(Date) FROM GROUP BY Message

來取得這樣的結果,但是我想取到所有的欄位該如何下SQL呢

方法一: 使用EF LINQ
var result = data.GroupBy(item => item.GroupId)
                 .Select(grouping => grouping.FirstOrDefault())
                 .OrderByDescending(item => item.Date)
                 .ToList();

或
var result = data.GroupBy(item => item.GroupId)
                 .SelectMany(grouping => grouping.Take(1))
                 .OrderByDescending(item => item.Date)
                 .ToList();

若想使用Order by
var result = data.GroupBy(item => item.GroupId)
                 .SelectMany(grouping => grouping.OrderBy(item => item.Date).Take(1))
                 .OrderByDescending(item => item.Date)
                 .ToList();
方法二: 使用SQL CTE
WITH CTE AS
(
    SELECT GroupId, MIN(Date) as MinDate
    FROM table
    GROUP BY GroupId
)
SELECT
    T.*
FROM table AS T
JOIN CTE AS C on C.GroupId = T.GroupId AND C.MinDate=T.Date

Entity Framework的SaveChanges有使用Transaction

在新公司常看到Batch Console跳出資料表被鎖定的例外錯誤
造成其他的程式無法讀取該資料表
經查詢發現某支Console常常做一些EF跑上千筆的更新
然後上網查了一下資料,原來EF 的SaveChanges有在使用Transaction
所以還是別一次跑上千筆的更新比較恰當
而且EF的RemoveRange在SQL上是一筆一筆exec去跑的,我也是醉了



圖片來源:https://dotblogs.com.tw/yc421206/2015/03/18/150757

一個成功的Git分支模型圖