Udostępnij przez


Agregowanie danych za pomocą języka GraphQL w narzędziu Data API Builder

Kreator API danych (DAB) obsługuje agregację i grupowanie GraphQL dla baz danych rodziny SQL oraz usługi Azure Synapse Analytics (dedykowana pula SQL). Agregacje umożliwiają podsumowanie pól liczbowych i wyników grupowania bez pisania niestandardowego kodu interfejsu API. Agregacja oraz groupBy nie są dostępne w Azure Cosmos DB dla NoSQL, PostgreSQL ani MySQL.

Wymagania wstępne

  • Obsługiwana baza danych:
    • SQL Server 2016 lub nowszy
    • Azure SQL Database
    • Azure SQL Managed Instance
    • Microsoft Fabric SQL
    • Azure Synapse Analytics (tylko dedykowana pula SQL)
  • Kreator interfejsu wiersza polecenia do API danych. Zainstaluj CLI
  • Plik konfiguracji DAB z jednostką uwidocznioną przez GraphQL.
  • Klient GraphQL (na przykład Banana Cake Pop lub GraphQL Playground) do uruchamiania zapytań.

Obsługiwane bazy danych

Baza danych Obsługa agregacji
SQL Server / Azure SQL / Microsoft Fabric SQL ✅ Tak
Azure Synapse (dedykowana pula SQL) ✅ Tak
Azure Synapse (bezserwerowa pula SQL) ❌ Nie
PostgreSQL ❌ Nie
MySQL ❌ Nie
Azure Cosmos DB for NoSQL ❌ Nie

Funkcje agregujące

DAB obsługuje następujące funkcje agregujące:

Funkcja Odnosi się do Description
sum Tylko pola liczbowe Suma wszystkich wartości
average Tylko pola liczbowe Średnia wszystkich wartości
min Tylko pola liczbowe Wartość minimalna
max Tylko pola liczbowe Wartość maksymalna
count Dowolne pole Liczba wartości innych niż null

Constraints

  • sum, , averagemini max działają tylko na typach danych liczbowych (int, dziesiętnych, zmiennoprzecinkowych itp.).
  • count działa na dowolnym typie danych, takie jak ciągi znaków i daty.
  • Jeśli tabela nie ma kolumn liczbowych, daB nie generuje węzłów agregacji dla tej jednostki. Nadal można używać count w polach nieliczbowych.

Modyfikatory opcjonalne

Modyfikator Przeznaczenie Example
distinct: true Zlicz tylko unikatowe wartości Zlicz unikatowych klientów
having: { ... } Filtrowanie grup po agregacji Pokaż grupy z sumą > 1000

Uruchom środowisko uruchomieniowe DAB

Uruchom DAB za pomocą pliku konfiguracji, aby punkt końcowy GraphQL był dostępny.

dab start

Zagregowane wyniki zapytania

W tej sekcji przedstawiono kompletny przykład przedstawiający schemat tabeli, zapytanie GraphQL, wygenerowaną odpowiedź SQL i JSON.

Schemat tabeli

CREATE TABLE books (
    id INT PRIMARY KEY,
    title NVARCHAR(200),
    year INT,
    pages INT
);

Zapytanie GraphQL

Użyj języka GraphQL, aby zgrupować wiersze i zwrócić wartości agregacji dla pól liczbowych.

{
  books(
    groupBy: { fields: ["year"] }
  ) {
    items {
      year
    }
    aggregates {
      pages {
        sum
        average
        min
        max
      }
    }
  }
}
  • groupBy.fields grupuje wiersze według określonych kolumn.
  • aggregates Uwidacznia funkcje agregujące dla pól liczbowych (na przykład pages).
  • Schemat GraphQL uwidacznia tylko agregacje dla pól, które je obsługują; Użyj introspekcji schematu w kliencie, aby potwierdzić dostępne zagregowane pola i funkcje.

Wygenerowany język SQL

DAB przetwarza zapytanie GraphQL na 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

Odpowiedź w formacie 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 }
        ]
      }
    }
  }
}

Tablice items i aggregates są wyrównane według indeksu — pierwszy element tablicy aggregates.pages odpowiada pierwszej grupie w tablicy items.

Agregowanie bez grupowania

Oblicz agregacje we wszystkich wierszach, gdy pominięto element groupBy.

Zapytanie GraphQL

{
  books {
    aggregates {
      pages {
        sum
        average
        min
        max
        count
      }
      id {
        count
      }
    }
  }
}

Wygenerowany język 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

Odpowiedź w formacie JSON

{
  "data": {
    "books": {
      "aggregates": {
        "pages": {
          "sum": 15420,
          "average": 308,
          "min": 120,
          "max": 850,
          "count": 50
        },
        "id": {
          "count": 50
        }
      }
    }
  }
}

Bez groupByfunkcji odpowiedź zwraca pojedynczy obiekt (a nie tablicę), ponieważ wszystkie wiersze są zwinięte w jeden wynik.

Grupuj według co najmniej jednego pola

Grupuj wiersze według co najmniej jednej kolumny i zwracaj agregacje dla każdej grupy.

Schemat tabeli

CREATE TABLE sales (
    id INT PRIMARY KEY,
    year INT,
    category NVARCHAR(50),
    revenue DECIMAL(10,2),
    quantity INT
);

Zapytanie GraphQL

{
  sales(
    groupBy: { fields: ["year", "category"] }
  ) {
    items {
      year
      category
    }
    aggregates {
      revenue {
        sum
        average
      }
      quantity {
        sum
      }
    }
  }
}

Wygenerowany język 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

Odpowiedź w formacie 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 }
        ]
      }
    }
  }
}

Odpowiedź zwraca tablice dla items i agregacji w tej samej kolejności, aby można było dopasować grupy do ich zagregowanych wartości.

KONIECZNOŚĆ filtrowania zagregowanych wyników

Służy having do filtrowania grup po agregacji. Jest to odpowiednik klauzuli HAVING SQL.

Schemat tabeli

CREATE TABLE products (
    id INT PRIMARY KEY,
    category NVARCHAR(50),
    price DECIMAL(10,2)
);

Zapytanie GraphQL

{
  products(
    groupBy: { fields: ["category"] }
  ) {
    items { category }
    aggregates {
      price {
        sum(having: { gt: 10000 })
        average
      }
    }
  }
}

Wygenerowany język 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

Odpowiedź w formacie JSON

Zwracane są tylko kategorie, w których suma przekracza 10000:

{
  "data": {
    "products": {
      "items": [
        { "category": "Electronics" },
        { "category": "Furniture" }
      ],
      "aggregates": {
        "price": [
          { "sum": 15000.00, "average": 300.00 },
          { "sum": 12000.00, "average": 400.00 }
        ]
      }
    }
  }
}

Operatory HAVING

Operator Odpowiednik 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 }

Uwaga / Notatka

Każdy having filtr jest stosowany niezależnie do swojej funkcji agregującej. Nie można utworzyć warunków agregacji krzyżowej, takich jak "suma > 1000 OR count < 10" w pojedynczym zapytaniu GraphQL.

DISTINCT w agregacjach

Zlicz unikatowe wartości za pomocą polecenia distinct: true.

Schemat tabeli

CREATE TABLE orders (
    id INT PRIMARY KEY,
    customer_id INT,
    product_id INT
);

Zapytanie GraphQL

{
  orders(
    groupBy: { fields: ["customer_id"] }
  ) {
    items { customer_id }
    aggregates {
      product_id {
        count(distinct: true)
        count
      }
    }
  }
}

Wygenerowany język 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

Odpowiedź w formacie JSON

{
  "data": {
    "orders": {
      "items": [
        { "customer_id": 101 },
        { "customer_id": 102 }
      ],
      "aggregates": {
        "product_id": [
          { "count": 5 },
          { "count": 3 }
        ]
      }
    }
  }
}

Pierwsza count (z distinct: true) zwraca unikatowe produkty dla każdego klienta. Drugi count zwraca liczbę całkowitych zamówień.

Uwaga / Notatka

Podczas żądania wielu agregacji w tym samym polu funkcja DAB zwraca je w żądanej kolejności. Użyj aliasów (na przykład uniqueProducts: count(distinct: true)), aby samodzielnie dokumentować odpowiedzi.

Łączenie filtrów z agregacją

Zastosuj filter do wierszy przed grupowaniem i having do grup po agregacji. Zrozumienie kolejności operacji ma kluczowe znaczenie:

  1. Filtr (SQL WHERE) usuwa wiersze przed grupowaniem
  2. Grupuj według zbiera pozostałe wiersze w grupach
  3. Agregacja oblicza sumę/średnio/minimalną/maksymalną/liczbę na grupę
  4. Having usuwa grupy, które nie są zgodne z warunkiem

Zapytanie GraphQL

{
  sales(
    filter: { year: { gte: 2023 } }
    groupBy: { fields: ["region"] }
  ) {
    items { region }
    aggregates {
      revenue { sum average }
    }
  }
}

Wygenerowany język 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

Wskazówka

Użyj polecenia filter , aby wykluczyć wiersze przed agregacją. Służy having do filtrowania grup po agregacji.

Używanie aliasów z agregacjami

Tworzenie zrozumiałych nazw pól przy użyciu aliasów GraphQL.

{
  products(
    groupBy: { fields: ["category"] }
  ) {
    items { category }
    aggregates {
      price {
        totalRevenue: sum
        avgPrice: average
        cheapest: min
        mostExpensive: max
        productCount: count
      }
    }
  }
}

Introspekcja schematu

Użyj introspekcji, aby zobaczyć, które agregacje są dostępne dla jednostki.

{
  __type(name: "BooksAggregates") {
    fields {
      name
      type { name }
    }
  }
}

Pola liczbowe wystawiają sum, average, min, max i count. Pola nieliczbowe uwidaczniają wartość count.

Porady i ograniczenia

  • Agregacja i groupBy dotyczą tylko SQL Server, Azure SQL, Microsoft Fabric SQL i dedykowanej puli SQL w usłudze Azure Synapse.
  • Agregacje są uruchamiane w polach liczbowych; count działa w dowolnym polu. Tabele bez kolumn liczbowych uwidaczniają tylko wartość count.
  • Grupowanie dotyczy pól w tej samej encji (bez grupowania według pól w różnych encjach).
  • Duże agregacje mogą być kosztowne; zaindeksuj kolumny grupowania i filtruj wiersze przed grupowaniem, gdy jest to możliwe.
  • Tworzenie indeksów dla często używanych groupBy kolumn w celu zwiększenia wydajności zapytań.

Rozwiązywanie problemów

Błąd: pole nie obsługuje agregacji

Przyczyna: używanie sum, average, min lub max na polu nieliczbowym.

Rozwiązanie:

  • Użyj introspekcji schematu, aby zweryfikować typy pól.
  • Użyj count dla pól nieliczbowych.
  • Sprawdź mapowania pól, jeśli używasz niestandardowych nazw pól.

Błąd: Nie znaleziono węzłów agregacji

Przyczyna: Jednostka nie ma kolumn liczbowych.

Rozwiązanie:

  • Sprawdź, czy schemat tabeli ma co najmniej jedną kolumnę liczbową.
  • W razie potrzeby stosuj agregacje count na polach nieliczbowych.

Powolne zapytania agregacji

Przyczyna: Duże tabele bez odpowiednich indeksów.

Rozwiązanie:

  • Tworzenie indeksów w groupBy kolumnach.
  • Użyj polecenia filter , aby ograniczyć wiersze przed agregacją.
  • Użyj polecenia having , aby zmniejszyć liczbę zwracanych grup.

Następny krok