Agregat data dengan GraphQL

Pembuat API Data mendukung agregasi GraphQL untuk keluarga SQL Server dan entitas kumpulan SQL Khusus Azure Synapse Analytics. Gunakan kolom groupBy pada kueri koleksi untuk menghitung nilai sum, avg, min, max, dan count.

Contoh dalam artikel ini menggunakan entitas SQL Server dan GraphQL dengan izin baca. Penyusun API Data menghasilkan SQL seperti pernyataan yang ditunjukkan dalam setiap skenario. Nilai parameter muncul sebagai parameter kueri pada runtime. Fungsi sum, , avgmin, dan max berlaku untuk bidang numerik. Fungsi count ini berfungsi pada bidang apa pun.

Important

Agregasi tidak tersedia untuk Azure Cosmos DB untuk NoSQL, PostgreSQL, atau MySQL.

Agregasi diaktifkan secara default. Untuk menonaktifkannya, atur enable-aggregation ke false di bawah runtime.graphql dalam file konfigurasi Anda. Kueri agregasi mengembalikan satu halaman kelompok, dengan jumlah bawaan 100. first Gunakan argumen pada kueri koleksi untuk mengubah maksimum, misalnya books(first: 500). Atur default dengan runtime.pagination.default-page-size.

Penambahan skema GraphQL

Saat Anda mengaktifkan agregasi, penyusun API Data menambahkan bidang agregasi dan jenis yang dihasilkan ke setiap koleksi GraphQL yang didukung. Nama tipe yang dihasilkan secara tepat bergantung pada entitas dan dapat dilihat melalui introspeksi GraphQL, tetapi sintaks kuerinya tetap konsisten untuk semua entitas.

Cuplikan berikut menunjukkan format sintaksis, tidak menyelesaikan kueri GraphQL.

groupBy

Mengembalikan baris-baris yang dikelompokkan dalam koleksi. Pilih anggota ini alih-alih items dalam kueri agregasi.

<collection> { groupBy { ... } }

groupBy(fields: [...])

Menampilkan bidang entitas yang digunakan sebagai dasar pengelompokan. Hilangkan fields untuk mengagregasi semua baris ke dalam satu grup.

<collection> { groupBy(fields: [<field>, ...]) { ... } }

fields

Mengembalikan nilai bidang yang dikelompokkan untuk setiap baris dalam hasil agregasi.

groupBy(fields: [<field>]) { fields { <field> } }

aggregations

Berisi pilihan fungsi agregat untuk setiap grup.

groupBy { aggregations { <alias>: <function>(field: <field>) } }

sum, avg, min, dan max

Bidang numerik agregat.

aggregations { <alias>: sum(field: <numeric-field>) }
aggregations { <alias>: avg(field: <numeric-field>) }
aggregations { <alias>: min(field: <numeric-field>) }
aggregations { <alias>: max(field: <numeric-field>) }

count

Menghitung jumlah nilai untuk kolom.

aggregations { <alias>: count(field: <field>) }

field

Mengidentifikasi bidang entitas untuk diagregasi. Nama bidang adalah nilai enum, bukan string.

<function>(field: <field>)

having

Memfilter grup setelah penyusun Api Data menghitung nilai agregat.

aggregations { <alias>: <function>(field: <field>, having: { <operator>: <value> }) }

distinct

Menghitung nilai unik saat digunakan dengan count.

aggregations { <alias>: count(field: <field>, distinct: true) }

Data API builder membuat tipe GraphQL khusus entitas di balik anggota-anggota ini, termasuk tipe baris grup, tipe bidang yang dikelompokkan, tipe pemilihan agregat, enum bidang, dan tipe input having. Anda tidak perlu memberi nama tipe yang dihasilkan dalam kueri.

Samples

Sampel berikut menunjukkan tabel SQL, kueri GraphQL, SQL yang dihasilkan, dan output yang dihasilkan untuk pola agregasi umum.

Mengagregasi semua baris dalam tabel

Gunakan pola ini saat Anda menginginkan satu baris ringkasan untuk seluruh entitas.

Tabel SQL

CREATE TABLE dbo.Books (
    id INT NOT NULL PRIMARY KEY,
    title NVARCHAR(200) NOT NULL,
    [year] INT NOT NULL,
    pages INT NOT NULL
);

INSERT INTO dbo.Books (id, title, [year], pages) VALUES
    (1, N'GraphQL Basics', 2023, 120),
    (2, N'Advanced APIs', 2023, 450),
    (3, N'Data Patterns', 2023, 390),
    (4, N'Cloud APIs', 2024, 140),
    (5, N'Runtime Internals', 2024, 510),
    (6, N'Query Tuning', 2024, 250);
id title tahun halaman
1 Dasar-Dasar GraphQL 2023 120
2 API Tingkat Lanjut 2023 450
3 Pola Data 2023 390
4 API Cloud 2024 140
5 Mekanisme Internal Runtime 2024 510
6 Penyetelan Kueri 2024 250

Kueri GraphQL

{
  books {
    groupBy {
      aggregations {
        totalPages: sum(field: pages)
        averagePages: avg(field: pages)
        shortestBook: min(field: pages)
        longestBook: max(field: pages)
        bookCount: count(field: id)
      }
    }
  }
}

SQL yang dihasilkan

SELECT TOP 100
    SUM([table0].[pages]) AS [totalPages],
    AVG([table0].[pages]) AS [averagePages],
    MIN([table0].[pages]) AS [shortestBook],
    MAX([table0].[pages]) AS [longestBook],
    COUNT([table0].[id]) AS [bookCount]
FROM [dbo].[Books] AS [table0]
WHERE 1 = 1
FOR JSON PATH, INCLUDE_NULL_VALUES;

Output yang dihasilkan

{
  "data": {
    "books": {
      "groupBy": [
        {
          "aggregations": {
            "totalPages": 1860,
            "averagePages": 310,
            "shortestBook": 120,
            "longestBook": 510,
            "bookCount": 6
          }
        }
      ]
    }
  }
}
totalPages averagePages shortestBook buku terpanjang bookCount
1860 310 120 510 6

Mengelompokkan baris menurut satu bidang

Gunakan groupBy(fields: [...]) untuk mengembalikan satu baris agregat per nilai bidang. Nama bidang adalah nilai enum GraphQL, bukan string.

Tabel SQL

CREATE TABLE dbo.Books (
  id INT NOT NULL PRIMARY KEY,
  title NVARCHAR(200) NOT NULL,
  [year] INT NOT NULL,
  pages INT NOT NULL
);

INSERT INTO dbo.Books (id, title, [year], pages) VALUES
  (1, N'GraphQL Basics', 2023, 120),
  (2, N'Advanced APIs', 2023, 450),
  (3, N'Data Patterns', 2023, 390),
  (4, N'Cloud APIs', 2024, 140),
  (5, N'Runtime Internals', 2024, 510),
  (6, N'Query Tuning', 2024, 250);
id title tahun halaman
1 Dasar-Dasar GraphQL 2023 120
2 API Tingkat Lanjut 2023 450
3 Pola Data 2023 390
4 API Cloud 2024 140
5 Bagian Internal Runtime 2024 510
6 Pengoptimalan Kueri 2024 250

Kueri GraphQL

{
  books(orderBy: { year: ASC }) {
    groupBy(fields: [year]) {
      fields { year }
      aggregations {
        totalPages: sum(field: pages)
        averagePages: avg(field: pages)
      }
    }
  }
}

SQL yang dihasilkan

SELECT TOP 100
    [table0].[year] AS [year],
    SUM([table0].[pages]) AS [totalPages],
    AVG([table0].[pages]) AS [averagePages]
FROM [dbo].[Books] AS [table0]
WHERE 1 = 1
GROUP BY [table0].[year]
ORDER BY [table0].[year] ASC
FOR JSON PATH, INCLUDE_NULL_VALUES;

Output yang dihasilkan

{
  "data": {
    "books": {
      "groupBy": [
        {
          "fields": {
            "year": 2023
          },
          "aggregations": {
            "totalPages": 960,
            "averagePages": 320
          }
        },
        {
          "fields": {
            "year": 2024
          },
          "aggregations": {
            "totalPages": 900,
            "averagePages": 300
          }
        }
      ]
    }
  }
}
tahun totalPages averagePages
2023 960 320
2024 900 300

Mengelompokkan baris dari tampilan

Agregasi juga berfungsi untuk entitas yang didukung tampilan. Konfigurasikan bidang kunci untuk tampilan sehingga penyusun API Data dapat mengeksposnya sebagai entitas.

tampilan SQL

CREATE TABLE dbo.Employees (
  id INT NOT NULL PRIMARY KEY,
  name NVARCHAR(100) NOT NULL,
  department NVARCHAR(50) NOT NULL,
  title NVARCHAR(100) NOT NULL,
  age INT NOT NULL
);

INSERT INTO dbo.Employees (id, name, department, title, age) VALUES
  (1, N'Ada', N'Engineering', N'Developer', 29),
  (2, N'Ben', N'Engineering', N'Architect', 41),
  (3, N'Cora', N'Sales', N'Account manager', 34),
  (4, N'Diego', N'Sales', N'Sales lead', 52),
  (5, N'Ema', N'Support', N'Support engineer', 25),
  (6, N'Finn', N'Support', N'Support lead', 38),
  (7, N'Gia', N'Engineering', N'Engineering manager', 45);

CREATE VIEW dbo.EmployeeAgeReport
AS
SELECT id, department, age
FROM dbo.Employees;
id departemen usia
1 Teknik 29
2 Teknik 41
3 Sales 34
4 Sales 52
5 Support 25
6 Support 38
7 Teknik 45

Konfigurasikan tampilan dengan id sebagai bidang kunci:

dab add EmployeeAgeReport --source dbo.EmployeeAgeReport --source.type view --source.key-fields id --permissions "anonymous:read"

Kueri GraphQL

{
  employeeAgeReports(orderBy: { department: ASC }) {
    groupBy(fields: [department]) {
      fields { department }
      aggregations {
        youngest: min(field: age)
        oldest: max(field: age)
        employeeCount: count(field: id)
      }
    }
  }
}

SQL yang dihasilkan

SELECT TOP 100
  [table0].[department] AS [department],
  MIN([table0].[age]) AS [youngest],
  MAX([table0].[age]) AS [oldest],
  COUNT([table0].[id]) AS [employeeCount]
FROM [dbo].[EmployeeAgeReport] AS [table0]
WHERE 1 = 1
GROUP BY [table0].[department]
ORDER BY [table0].[department] ASC
FOR JSON PATH, INCLUDE_NULL_VALUES;

Output yang dihasilkan

{
  "data": {
    "employeeAgeReports": {
      "groupBy": [
        {
          "fields": {
            "department": "Engineering"
          },
          "aggregations": {
            "youngest": 29,
            "oldest": 45,
            "employeeCount": 3
          }
        },
        {
          "fields": {
            "department": "Sales"
          },
          "aggregations": {
            "youngest": 34,
            "oldest": 52,
            "employeeCount": 2
          }
        },
        {
          "fields": {
            "department": "Support"
          },
          "aggregations": {
            "youngest": 25,
            "oldest": 38,
            "employeeCount": 2
          }
        }
      ]
    }
  }
}
departemen termuda tertua employeeCount
Teknik 29 45 3
Sales 34 52 2
Support 25 38 2

Memfilter baris sebelum agregasi

Gunakan filter pada kueri koleksi untuk membatasi baris sumber sebelum Data API builder mengelompokkan dan mengagregasikannya.

tampilan SQL

CREATE TABLE dbo.Employees (
  id INT NOT NULL PRIMARY KEY,
  name NVARCHAR(100) NOT NULL,
  department NVARCHAR(50) NOT NULL,
  title NVARCHAR(100) NOT NULL,
  age INT NOT NULL
);

INSERT INTO dbo.Employees (id, name, department, title, age) VALUES
  (1, N'Ada', N'Engineering', N'Developer', 29),
  (2, N'Ben', N'Engineering', N'Architect', 41),
  (3, N'Cora', N'Sales', N'Account manager', 34),
  (4, N'Diego', N'Sales', N'Sales lead', 52),
  (5, N'Ema', N'Support', N'Support engineer', 25),
  (6, N'Finn', N'Support', N'Support lead', 38),
  (7, N'Gia', N'Engineering', N'Engineering manager', 45);

CREATE VIEW dbo.EmployeeAgeReport
AS
SELECT id, department, age
FROM dbo.Employees;
id departemen usia
1 Teknik 29
2 Teknik 41
3 Sales 34
4 Sales 52
5 Support 25
6 Support 38
7 Teknik 45

Kueri GraphQL

{
  employeeAgeReports(filter: { age: { gt: 30 } }, orderBy: { department: ASC }) {
    groupBy(fields: [department]) {
      fields { department }
      aggregations {
        youngest: min(field: age)
        oldest: max(field: age)
        employeeCount: count(field: id)
      }
    }
  }
}

SQL yang dihasilkan

SELECT TOP 100
  [table0].[department] AS [department],
  MIN([table0].[age]) AS [youngest],
  MAX([table0].[age]) AS [oldest],
  COUNT([table0].[id]) AS [employeeCount]
FROM [dbo].[EmployeeAgeReport] AS [table0]
WHERE [table0].[age] > @param1
GROUP BY [table0].[department]
ORDER BY [table0].[department] ASC
FOR JSON PATH, INCLUDE_NULL_VALUES;

Untuk kueri ini, @param1 adalah 30.

Output yang dihasilkan

{
  "data": {
    "employeeAgeReports": {
      "groupBy": [
        {
          "fields": {
            "department": "Engineering"
          },
          "aggregations": {
            "youngest": 41,
            "oldest": 45,
            "employeeCount": 2
          }
        },
        {
          "fields": {
            "department": "Sales"
          },
          "aggregations": {
            "youngest": 34,
            "oldest": 52,
            "employeeCount": 2
          }
        },
        {
          "fields": {
            "department": "Support"
          },
          "aggregations": {
            "youngest": 38,
            "oldest": 38,
            "employeeCount": 1
          }
        }
      ]
    }
  }
}
departemen termuda tertua employeeCount
Teknik 41 45 2
Sales 34 52 2
Support 38 38 1

Memfilter grup dengan menggunakan having

Gunakan having pada fungsi agregat untuk memfilter grup setelah agregasi. Pola ini sesuai dengan klausa SQL HAVING.

Tabel SQL

CREATE TABLE dbo.Products (
    id INT NOT NULL PRIMARY KEY,
    category NVARCHAR(50) NOT NULL,
    price DECIMAL(10,2) NOT NULL
);

INSERT INTO dbo.Products (id, category, price) VALUES
    (1, N'Electronics', 5000.00),
    (2, N'Electronics', 10000.00),
    (3, N'Furniture', 4000.00),
    (4, N'Furniture', 8000.00),
    (5, N'Books', 100.00),
    (6, N'Books', 200.00);
id kategori harga
1 Elektronik 5000.00
2 Elektronik 10.000,00
3 Perabot 4000.00
4 Perabot 8000.00
5 Buku 100.00
6 Buku 200.00

Kueri GraphQL

{
  products(orderBy: { category: ASC }) {
    groupBy(fields: [category]) {
      fields { category }
      aggregations {
        totalValue: sum(field: price, having: { gt: 10000 })
        averagePrice: avg(field: price)
      }
    }
  }
}

SQL yang dihasilkan

SELECT TOP 100
    [table0].[category] AS [category],
    SUM([table0].[price]) AS [totalValue],
    AVG([table0].[price]) AS [averagePrice]
FROM [dbo].[Products] AS [table0]
WHERE 1 = 1
GROUP BY [table0].[category]
HAVING SUM([table0].[price]) > @param1
ORDER BY [table0].[category] ASC
FOR JSON PATH, INCLUDE_NULL_VALUES;

Untuk kueri ini, @param1 adalah 10000.

Output yang dihasilkan

{
  "data": {
    "products": {
      "groupBy": [
        {
          "fields": {
            "category": "Electronics"
          },
          "aggregations": {
            "totalValue": 15000,
            "averagePrice": 7500
          }
        },
        {
          "fields": {
            "category": "Furniture"
          },
          "aggregations": {
            "totalValue": 12000,
            "averagePrice": 6000
          }
        }
      ]
    }
  }
}
kategori Nilai total harga rata-rata
Elektronik 15000 7500
Perabot 12000 6000

Hitung nilai unik

Gunakan distinct: true dengan count untuk menghitung nilai unik di setiap grup.

Tabel SQL

CREATE TABLE dbo.Orders (
    id INT NOT NULL PRIMARY KEY,
    customer_id INT NOT NULL,
    product_id INT NOT NULL
);

INSERT INTO dbo.Orders (id, customer_id, product_id) VALUES
    (1, 101, 1),
    (2, 101, 2),
    (3, 101, 2),
    (4, 101, 3),
    (5, 101, 4),
    (6, 101, 5),
    (7, 102, 1),
    (8, 102, 1),
    (9, 102, 2),
    (10, 102, 3);
id customer_id product_id
1 101 1
2 101 2
3 101 2
4 101 3
5 101 4
6 101 5
7 102 1
8 102 1
9 102 2
10 102 3

Kueri GraphQL

{
  orders(orderBy: { customer_id: ASC }) {
    groupBy(fields: [customer_id]) {
      fields { customer_id }
      aggregations {
        uniqueProducts: count(field: product_id, distinct: true)
        totalOrders: count(field: id)
      }
    }
  }
}

SQL yang dihasilkan

SELECT TOP 100
    [table0].[customer_id] AS [customer_id],
    COUNT(DISTINCT ([table0].[product_id])) AS [uniqueProducts],
    COUNT([table0].[id]) AS [totalOrders]
FROM [dbo].[Orders] AS [table0]
WHERE 1 = 1
GROUP BY [table0].[customer_id]
ORDER BY [table0].[customer_id] ASC
FOR JSON PATH, INCLUDE_NULL_VALUES;

Output yang dihasilkan

{
  "data": {
    "orders": {
      "groupBy": [
        {
          "fields": {
            "customer_id": 101
          },
          "aggregations": {
            "uniqueProducts": 5,
            "totalOrders": 6
          }
        },
        {
          "fields": {
            "customer_id": 102
          },
          "aggregations": {
            "uniqueProducts": 3,
            "totalOrders": 4
          }
        }
      ]
    }
  }
}
customer_id uniqueProducts totalOrders
101 5 6
102 3 4

Kesalahan umum

  • Pilih groupBy di dalam kolom koleksi. Jangan berikan groupBy sebagai argumen koleksi.
  • Gunakan aggregations, bukan aggregates.
  • Gunakan avg, bukan average.
  • Gunakan nilai enum kolom, seperti fields: [year]. Jangan kutip nama bidang.
  • Jangan pilih items dan groupBy dalam kueri koleksi yang sama.
  • Saat Anda mengelompokkan menurut bidang, pilih hanya bidang yang sama di fields dalam objek.