Data API 建構器(DAB)支援 SQL 家族資料庫的 GraphQL 聚合與分組,以及 Azure Synapse Analytics(專用 SQL 池)。 聚合功能讓你能在不寫自訂 API 程式碼的情況下,彙整數值欄位並分組結果。 Azure Cosmos DB for NoSQL、PostgreSQL 或 MySQL 不支援聚合功能和groupBy。
先決條件
- 支援資料庫:
- SQL Server 2016 或更新版本
- Azure SQL Database
- Azure SQL 受控執行個體
- Microsoft Fabric SQL
- Azure Synapse Analytics (僅限專用 SQL 池)
- 數據 API 產生器 CLI。 安裝 CLI
- 一個包含你實體的 DAB 設定檔,透過 GraphQL 公開。
- 一個 GraphQL 客戶端(例如 Banana Cake Pop 或 GraphQL Playground)來執行查詢。
支援的資料庫
| 資料庫 | 聚合支援 |
|---|---|
| SQL Server / Azure SQL / Microsoft Fabric SQL | ✅ 是 |
| Azure Synapse (Dedicated SQL pool) | ✅ 是 |
| Azure Synapse (Serverless SQL pool) | ❌ 否 |
| PostgreSQL | ❌ 否 |
| MySQL | ❌ 否 |
| Azure Cosmos DB for NoSQL | ❌ 否 |
聚合函數
DAB 支援以下聚合函式:
| 功能 | 適用對象 | Description |
|---|---|---|
sum |
僅允許數值欄位 | 所有數值的總和 |
average |
僅限數值欄位 | 所有值的平均值 |
min |
僅限數值欄位 | 最小值 |
max |
僅允許數值的字段 | 最大值 |
count |
任何領域 | 非空值的計數 |
Constraints
-
sumaverageminmax、且僅適用於數值資料型別(整數、十進位、浮點數等)。 -
count適用於任何資料型態,包括字串和日期。 - 如果資料表沒有數字欄位,DAB 不會為該實體產生聚合節點。 你仍然可以在非數值欄位使用
count。
可選修飾符
| 修飾語 | 目標 | Example |
|---|---|---|
distinct: true |
只計算唯一值 | 計算不同的客戶 |
having: { ... } |
聚合後的濾波器群組 | 顯示總和小於> 1000的群組 |
執行 DAB 執行環境
用你的設定檔啟動 DAB,這樣 GraphQL 端點就能使用。
dab start
查詢彙整結果
本節將完整示範資料表架構、GraphQL 查詢、產生的 SQL 與 JSON 回應。
資料表結構描述
CREATE TABLE books (
id INT PRIMARY KEY,
title NVARCHAR(200),
year INT,
pages INT
);
GraphQL 查詢
使用 GraphQL 來分組列並回傳數值欄位的彙總值。
{
books(
groupBy: { fields: ["year"] }
) {
items {
year
}
aggregates {
pages {
sum
average
min
max
}
}
}
}
-
groupBy.fields依指定欄位將資料列分組。 -
aggregates揭示了數值欄位的聚合函數(例如,pages)。 - GraphQL 架構僅對支援這些集合欄位開放;在客戶端使用結構內省來確認可用的聚合欄位和函式。
產生的 SQL
DAB 將 GraphQL 查詢轉換為 T-SQL:
SELECT
[year],
SUM([pages]) AS [sum],
AVG([pages]) AS [average],
MIN([pages]) AS [min],
MAX([pages]) AS [max]
FROM [dbo].[books]
GROUP BY [year]
FOR JSON PATH, INCLUDE_NULL_VALUES
JSON 回應
{
"data": {
"books": {
"items": [
{ "year": 2023 },
{ "year": 2024 }
],
"aggregates": {
"pages": [
{ "sum": 3200, "average": 320, "min": 120, "max": 450 },
{ "sum": 4500, "average": 300, "min": 140, "max": 510 }
]
}
}
}
}
items與aggregates陣列依索引對齊——第一個aggregates.pages元素對應於 中的items第一個群組。
不帶分組的彙總
當你省略 groupBy時,計算所有列的聚合值。
GraphQL 查詢
{
books {
aggregates {
pages {
sum
average
min
max
count
}
id {
count
}
}
}
}
產生的 SQL
SELECT
SUM([pages]) AS [sum],
AVG([pages]) AS [average],
MIN([pages]) AS [min],
MAX([pages]) AS [max],
COUNT([pages]) AS [count],
COUNT([id]) AS [count]
FROM [dbo].[books]
FOR JSON PATH, INCLUDE_NULL_VALUES
JSON 回應
{
"data": {
"books": {
"aggregates": {
"pages": {
"sum": 15420,
"average": 308,
"min": 120,
"max": 850,
"count": 50
},
"id": {
"count": 50
}
}
}
}
}
若沒有 groupBy,回應會回傳單一物件(非陣列),因為所有列合併為一個結果。
以一個或多個域分組
將資料列分組為一欄或多欄,並回傳每組的彙總結果。
資料表結構描述
CREATE TABLE sales (
id INT PRIMARY KEY,
year INT,
category NVARCHAR(50),
revenue DECIMAL(10,2),
quantity INT
);
GraphQL 查詢
{
sales(
groupBy: { fields: ["year", "category"] }
) {
items {
year
category
}
aggregates {
revenue {
sum
average
}
quantity {
sum
}
}
}
}
產生的 SQL
SELECT
[year],
[category],
SUM([revenue]) AS [sum],
AVG([revenue]) AS [average],
SUM([quantity]) AS [sum]
FROM [dbo].[sales]
GROUP BY [year], [category]
FOR JSON PATH, INCLUDE_NULL_VALUES
JSON 回應
{
"data": {
"sales": {
"items": [
{ "year": 2023, "category": "Books" },
{ "year": 2023, "category": "Electronics" },
{ "year": 2024, "category": "Books" }
],
"aggregates": {
"revenue": [
{ "sum": 45000.00, "average": 150.00 },
{ "sum": 120000.00, "average": 600.00 },
{ "sum": 52000.00, "average": 173.33 }
],
"quantity": [
{ "sum": 300 },
{ "sum": 200 },
{ "sum": 300 }
]
}
}
}
}
回應會回傳 items 和聚合值的陣列,並以相同的順序排列,讓你能將群組與其聚合值對齊。
必須篩選彙總結果
聚合後使用 having 來篩選群組。 這相當於 SQL 的 HAVING 子句。
資料表結構描述
CREATE TABLE products (
id INT PRIMARY KEY,
category NVARCHAR(50),
price DECIMAL(10,2)
);
GraphQL 查詢
{
products(
groupBy: { fields: ["category"] }
) {
items { category }
aggregates {
price {
sum(having: { gt: 10000 })
average
}
}
}
}
產生的 SQL
SELECT
[category],
SUM([price]) AS [sum],
AVG([price]) AS [average]
FROM [dbo].[products]
GROUP BY [category]
HAVING SUM([price]) > 10000
FOR JSON PATH, INCLUDE_NULL_VALUES
JSON 回應
僅回傳總和超過10000的類別:
{
"data": {
"products": {
"items": [
{ "category": "Electronics" },
{ "category": "Furniture" }
],
"aggregates": {
"price": [
{ "sum": 15000.00, "average": 300.00 },
{ "sum": 12000.00, "average": 400.00 }
]
}
}
}
}
擁有運算元
| Operator | SQL 等價物 | Example |
|---|---|---|
eq |
= |
having: { eq: 100 } |
neq |
<> |
having: { neq: 0 } |
gt |
> |
having: { gt: 1000 } |
gte |
>= |
having: { gte: 500 } |
lt |
< |
having: { lt: 100 } |
lte |
<= |
having: { lte: 50 } |
備註
每個 having 篩選器獨立應用於其聚合函數。 你無法在單一 GraphQL 查詢中建立像是「sum > 1000 或 count < 10」這種跨聚合條件。
聚合中的獨特性
計算唯一值使用 distinct: true。
資料表結構描述
CREATE TABLE orders (
id INT PRIMARY KEY,
customer_id INT,
product_id INT
);
GraphQL 查詢
{
orders(
groupBy: { fields: ["customer_id"] }
) {
items { customer_id }
aggregates {
product_id {
count(distinct: true)
count
}
}
}
}
產生的 SQL
SELECT
[customer_id],
COUNT(DISTINCT [product_id]) AS [count],
COUNT([product_id]) AS [count]
FROM [dbo].[orders]
GROUP BY [customer_id]
FOR JSON PATH, INCLUDE_NULL_VALUES
JSON 回應
{
"data": {
"orders": {
"items": [
{ "customer_id": 101 },
{ "customer_id": 102 }
],
"aggregates": {
"product_id": [
{ "count": 5 },
{ "count": 3 }
]
}
}
}
}
第一個 count (含 distinct: true)會為每位顧客返回獨一無二的產品。 第二個 count 會回傳總訂單。
備註
當在同一欄位請求多個聚合時,DAB 會依請求順序回傳。 使用別名(例如) uniqueProducts: count(distinct: true)來讓回應自我記錄。
將濾波器與聚合結合
在分組之前先應用 filter 於列,在聚合之後應用 having 於群組。 了解操作順序至關重要:
-
篩選 器(SQL
WHERE)會在分組前移除列 - Group by 會將資料列分成群組
- Aggregate 計算每組的總和/平均/最小/最大/數量
- 有這個 設定會移除不符合條件的群組
GraphQL 查詢
{
sales(
filter: { year: { gte: 2023 } }
groupBy: { fields: ["region"] }
) {
items { region }
aggregates {
revenue { sum average }
}
}
}
產生的 SQL
SELECT
[region],
SUM([revenue]) AS [sum],
AVG([revenue]) AS [average]
FROM [dbo].[sales]
WHERE [year] >= 2023
GROUP BY [region]
FOR JSON PATH, INCLUDE_NULL_VALUES
小提示
在彙總之前,使用 filter 排除列。 聚合後使用 having 來篩選群組。
使用別名與聚合
使用 GraphQL 別名建立有意義的欄位名稱。
{
products(
groupBy: { fields: ["category"] }
) {
items { category }
aggregates {
price {
totalRevenue: sum
avgPrice: average
cheapest: min
mostExpensive: max
productCount: count
}
}
}
}
模式檢視
利用內省(introspection)來查看實體可用的聚合。
{
__type(name: "BooksAggregates") {
fields {
name
type { name }
}
}
}
數值欄位會顯示 sum、average、min、max 和 count。 非數值欄位則 count暴露 。
技巧與限制
- 聚合和
groupBy僅應用於 SQL Server、Azure SQL、Microsoft Fabric SQL 與 Azure Synapse 專用的 SQL 池。 - 聚合體在數值欄位上運行;
count適用於任何領域。 沒有數值欄位的表格只會暴露count。 - 群組化適用於同一實體上的欄位(不包含跨實體 groupBy)。
- 大規模聚合的成本可能較高;在進行分組之前,請先為 GroupBy 欄位建立索引並篩選資料列。
- 在常用
groupBy欄位建立索引以提升查詢效能。
故障排除
錯誤:欄位不支援聚合
原因:在非數值欄位上使用 sum、 average、 minmax 、 。
解決方案:
- 使用 schema 內省來驗證欄位類型。
- 使用
count於非數值欄位。 - 如果使用自訂欄位名稱,請檢查欄位映射。
錯誤:找不到聚合節點
原因:該實體沒有數字欄位。
解決方案:
- 請確認資料表結構至少有一個數字欄位。
- 如果需要,可以在非數值欄位使用
count聚合。
慢速彙總查詢
原因:資料表大且沒有適當的索引。
解決方案:
- 在
groupBy欄位上建立索引。 - 在合併前用
filter來限制列數。 - 用
having來減少退回的群組數量。