Aggregare i dati con GraphQL

Il Generatore API dati supporta l'aggregazione GraphQL per le entità della famiglia SQL Server e per le entità del pool SQL dedicato di Azure Synapse Analytics. Usare il campo groupBy in una query di raccolta per calcolare i valori sum, avg, min, max e count.

Gli esempi in questo articolo usano SQL Server e le entità GraphQL con autorizzazione di lettura. Data API Builder genera istruzioni SQL come quelle mostrate in ogni scenario. I valori dei parametri vengono visualizzati come parametri di query in fase di esecuzione. Le sumfunzioni , avgmin, e max si applicano ai campi numerici. La count funzione funziona su qualsiasi campo.

Importante

L'aggregazione non è disponibile per Azure Cosmos DB per NoSQL, PostgreSQL o MySQL.

L'aggregazione è abilitata per impostazione predefinita. Per disattivarlo, impostare enable-aggregation su false in runtime.graphql nel file di configurazione. Le query di aggregazione restituiscono una pagina di gruppi, 100 per impostazione predefinita. Usare l'argomento first nella query di raccolta per modificare il valore massimo, ad esempio books(first: 500). Impostare il valore predefinito con runtime.pagination.default-page-size.

Aggiunte dello schema GraphQL

Quando si abilita l'aggregazione, Generatore API dati aggiunge campi di aggregazione e tipi generati a ogni raccolta GraphQL supportata. I nomi esatti dei tipi generati sono specifici dell'entità e visibili tramite l'introspezione GraphQL, ma la sintassi della query è uniforme tra le entità.

I frammenti di codice seguenti mostrano i formati di sintassi e non le query GraphQL complete.

groupBy

Restituisce righe raggruppate per l'insieme. Selezionare questo membro anziché items in una query di aggregazione.

<collection> { groupBy { ... } }

groupBy(fields: [...])

Elenca i campi dell'entità per cui raggruppare. Omettere fields per aggregare tutte le righe in un unico gruppo.

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

fields

Restituisce i valori di campo raggruppati per ogni riga nel risultato dell'aggregazione.

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

aggregations

Contiene le selezioni di funzioni di aggregazione per ogni gruppo.

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

sum, avg, mine max

Aggregare i campi numerici.

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

Conta i valori per un campo.

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

field

Identifica il campo dell'entità da aggregare. I nomi dei campi sono valori di enumerazione, non stringhe.

<function>(field: <field>)

having

Filtra i gruppi dopo che Generatore API dati calcola il valore di aggregazione.

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

distinct

Conta valori univoci se usati con count.

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

Il generatore di API dati genera tipi GraphQL specifici dell'entità dietro questi membri, inclusi i tipi di riga di gruppo, i tipi di campo raggruppati, i tipi di selezione aggregati, le enumerazioni dei campi e having i tipi di input. Non è necessario denominare i tipi generati in una query.

Esempi

Gli esempi seguenti illustrano la tabella SQL, la query GraphQL, il codice SQL risultante e l'output risultante per i modelli di aggregazione comuni.

Aggregare tutte le righe in una tabella

Usare questo modello quando si desidera una riga di riepilogo per l'intera entità.

Tabella 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 Titolo anno Pagine
1 Nozioni di base su GraphQL 2023 120
2 API avanzate 2023 450
3 Modelli di dati 2023 390
4 API cloud 2024 140
5 Elementi interni del runtime 2024 510
6 Ottimizzazione delle query 2024 250

Query 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 risultante

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 risultante

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

Raggruppare le righe per un campo

Utilizzare groupBy(fields: [...]) per restituire una riga di aggregazione per ogni valore di campo. I nomi dei campi sono valori di enumerazione GraphQL, non stringhe.

Tabella 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 Titolo anno Pagine
1 Nozioni di base su GraphQL 2023 120
2 API avanzate 2023 450
3 Modelli di dati 2023 390
4 API cloud 2024 140
5 Struttura interna del runtime 2024 510
6 Ottimizzazione delle query 2024 250

Query GraphQL

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

SQL risultante

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 risultante

{
  "data": {
    "books": {
      "groupBy": [
        {
          "fields": {
            "year": 2023
          },
          "aggregations": {
            "totalPages": 960,
            "averagePages": 320
          }
        },
        {
          "fields": {
            "year": 2024
          },
          "aggregations": {
            "totalPages": 900,
            "averagePages": 300
          }
        }
      ]
    }
  }
}
anno pagine totali Pagine medie
2023 960 320
2024 900 300

Raggruppa righe in una visualizzazione

L'aggregazione funziona anche per le entità supportate dalla visualizzazione. Configurare un campo chiave per la visualizzazione in modo che il generatore di API dati possa esporlo come entità.

Visualizzazione 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 dipartimento età
1 Ingegneria 29
2 Ingegneria 41
3 Sales 34
4 Sales 52
5 Support 25
6 Support 38
7 Ingegneria 45

Configurare la visualizzazione con id come campo chiave:

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

Query GraphQL

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

SQL risultante

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 risultante

{
  "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
          }
        }
      ]
    }
  }
}
dipartimento più giovane più vecchio numero di dipendenti
Ingegneria 29 45 3
Sales 34 52 2
Support 25 38 2

Filtrare le righe prima dell'aggregazione

Usare filter nella query sulla raccolta per limitare le righe sorgente prima che Data API builder le raggruppi e le aggreghi.

Visualizzazione 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 dipartimento età
1 Ingegneria 29
2 Ingegneria 41
3 Sales 34
4 Sales 52
5 Support 25
6 Support 38
7 Ingegneria 45

Query 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 risultante

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;

Per questa query, @param1 è 30.

Output risultante

{
  "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
          }
        }
      ]
    }
  }
}
dipartimento più giovane più vecchio numero di dipendenti
Ingegneria 41 45 2
Sales 34 52 2
Support 38 38 1

Filtrare i gruppi usando having

Usare having in una funzione di aggregazione per filtrare i gruppi dopo l'aggregazione. Questo modello corrisponde a una clausola SQL HAVING.

Tabella 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 categoria Prezzo
1 Elettronica 5.000,00
2 Elettronica 10.000,00
3 Mobilio 4000.00
4 Mobilio 8000.00
5 Libri 100.00
6 Libri 200.00

Query GraphQL

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

SQL risultante

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;

Per questa query, @param1 è 10000.

Output risultante

{
  "data": {
    "products": {
      "groupBy": [
        {
          "fields": {
            "category": "Electronics"
          },
          "aggregations": {
            "totalValue": 15000,
            "averagePrice": 7500
          }
        },
        {
          "fields": {
            "category": "Furniture"
          },
          "aggregations": {
            "totalValue": 12000,
            "averagePrice": 6000
          }
        }
      ]
    }
  }
}
categoria valore totale prezzo medio
Elettronica 15000 7500
Mobilio 12000 6000

Conteggio dei valori distinti

Usare distinct: true con count per contare valori univoci in ogni gruppo.

Tabella 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

Query 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 risultante

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 risultante

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

Errori comuni

  • Selezionare groupBy all'interno del campo della raccolta. Non passare groupBy come argomento di raccolta.
  • Usare aggregations, non aggregates.
  • Usare avg, non average.
  • Usare valori enum del campo, ad esempio fields: [year]. Non racchiudere i nomi dei campi tra virgolette.
  • Non selezionare items e groupBy nella stessa query di raccolta.
  • Quando si raggruppano i campi, selezionare solo gli stessi campi all'interno dell'oggetto fields .