GraphQL을 사용하여 데이터 집계

Data API Builder는 SQL Server 제품군 및 Azure Synapse Analytics 전용 SQL 풀 엔터티에 대한 GraphQL 집계를 지원합니다. 컬렉션 쿼리의 groupBy 필드를 사용하여 , sum, avgminmax 값을 계산count합니다.

이 문서의 예제에서는 읽기 권한이 있는 SQL Server 및 GraphQL 엔터티를 사용합니다. 데이터 API 작성기에서는 각 시나리오에 표시된 문처럼 SQL을 생성합니다. 매개 변수 값은 런타임에 쿼리 매개 변수로 표시됩니다. sum, avg, minmax 함수는 숫자 필드에 적용됩니다. 함수는 count 모든 필드에서 작동합니다.

Important

집계는 Azure Cosmos DB for NoSQL, PostgreSQL 또는 MySQL에서는 사용할 수 없습니다.

집계는 기본적으로 사용하도록 설정됩니다. 끄려면 구성 파일에서 runtime.graphql 아래의 enable-aggregationfalse로 설정하세요. 집계 쿼리는 기본적으로 100개 그룹의 한 페이지를 반환합니다. 컬렉션 쿼리의 first 인수를 사용하여 최대값을 변경합니다(예: books(first: 500)). 를 사용하여 기본값 runtime.pagination.default-page-size을 설정합니다.

GraphQL 스키마 추가

집계를 사용하도록 설정하면 데이터 API 작성기에서 지원되는 각 GraphQL 컬렉션에 집계 필드와 생성된 형식을 추가합니다. 정확한 생성 타입 이름은 엔터티마다 다르며 GraphQL 인트로스펙션을 통해 확인할 수 있지만, 쿼리 구문은 모든 엔터티에서 일관됩니다.

다음 코드 조각은 전체 GraphQL 쿼리가 아닌 구문 형식을 보여 줍니다.

groupBy

컬렉션에 대해 그룹화된 행을 반환합니다. 집계 쿼리 대신 items 이 멤버를 선택합니다.

<collection> { groupBy { ... } }

groupBy(fields: [...])

그룹화할 엔터티 필드를 나열합니다. 모든 행을 하나의 그룹으로 집계하려면 생략 fields 합니다.

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

fields

집계 결과의 각 행에 대해 그룹화된 필드 값을 반환합니다.

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

aggregations

각 그룹에 대한 집계 함수 선택을 포함합니다.

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

sum, avg, minmax

숫자 필드를 집계합니다.

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

필드의 값을 계산합니다.

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

field

집계할 엔터티 필드를 식별합니다. 필드 이름은 문자열이 아닌 열거형 값입니다.

<function>(field: <field>)

having

데이터 API 작성기에서 집계 값을 계산한 후 그룹을 필터링합니다.

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

distinct

와 함께 count사용할 때 고유 값의 개수를 계산합니다.

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

데이터 API 작성기는 그룹 행 형식, 그룹화된 필드 형식, 집계 선택 유형, 필드 열거형 및 having 입력 형식을 포함하여 이러한 멤버 뒤에 엔터티별 GraphQL 형식을 생성합니다. 쿼리에서 생성된 형식의 이름을 지정할 필요가 없습니다.

Samples

다음 샘플에서는 일반적인 집계 패턴에 대한 SQL 테이블, GraphQL 쿼리, 결과 SQL 및 결과 출력을 보여 줍니다.

테이블의 모든 행 집계하기

전체 엔터티에 대해 하나의 요약 행을 원하는 경우 이 패턴을 사용합니다.

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 연도 pages
1 GraphQL 기본 사항 2023 120
2 고급 API 2023 450
3 데이터 패턴 2023 390
4 클라우드 API 2024 140
5 런타임 내부 구조 2024 510
6 쿼리 튜닝 2024 250

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 문

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;

결과 출력

{
  "data": {
    "books": {
      "groupBy": [
        {
          "aggregations": {
            "totalPages": 1860,
            "averagePages": 310,
            "shortestBook": 120,
            "longestBook": 510,
            "bookCount": 6
          }
        }
      ]
    }
  }
}
총 페이지 수 평균 페이지 수 shortestBook longestBook bookCount
1860 310 120 510 6

행을 한 필드씩 그룹화

필드 값당 하나의 집계 행을 반환하는 데 사용합니다 groupBy(fields: [...]) . 필드 이름은 문자열이 아닌 GraphQL 열거형 값입니다.

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 연도 pages
1 GraphQL 기본 사항 2023 120
2 고급 API 2023 450
3 데이터 패턴 2023 390
4 클라우드 API 2024 140
5 런타임 내부 구조 2024 510
6 쿼리 튜닝 2024 250

GraphQL 쿼리

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

결과 SQL 문

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;

결과 출력

{
  "data": {
    "books": {
      "groupBy": [
        {
          "fields": {
            "year": 2023
          },
          "aggregations": {
            "totalPages": 960,
            "averagePages": 320
          }
        },
        {
          "fields": {
            "year": 2024
          },
          "aggregations": {
            "totalPages": 900,
            "averagePages": 300
          }
        }
      ]
    }
  }
}
연도 totalPages 평균 페이지
2023 960 320
2024 900 300

보기에서 행 그룹화

집계는 뷰 기반 엔터티에도 또한 지원됩니다. 데이터 API 작성기에서 뷰를 엔터티로 노출할 수 있도록 보기에 대한 키 필드를 구성합니다.

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 부서 연령
1 공학 이십구
2 공학 41
3 Sales 34
4 Sales 52
5 Support 25
6 Support 38
7 공학 45

뷰를 id를 키 필드로 사용하도록 구성합니다:

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

GraphQL 쿼리

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

결과 SQL문

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;

결과 출력

{
  "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
          }
        }
      ]
    }
  }
}
부서 가장 어린 가장 오래된 직원 수
공학 이십구 45 3
Sales 34 52 2
Support 25 38 2

집계 전에 행 필터링하기

컬렉션 쿼리에 filter를 사용하여 Data API 빌더가 그룹화하고 집계하기 전에 원본 행을 제한하세요.

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 부서 연령
1 공학 이십구
2 공학 41
3 Sales 34
4 Sales 52
5 Support 25
6 Support 38
7 공학 45

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

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;

이 쿼리의 경우 다음과 같습니다 @param130.

결과 출력

{
  "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
          }
        }
      ]
    }
  }
}
부서 가장 어린 가장 오래된 직원 수
공학 41 45 2
Sales 34 52 2
Support 38 38 1

having를 사용하여 그룹 필터링

집계 함수에서 집계 후 그룹을 필터링하는 데 사용합니다 having . 이 패턴은 SQL HAVING 절에 매핑합니다.

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 카테고리 가격
1 전자 5000.00
2 전자 10000.00
3 가구 4000.00
4 가구 8000.00
5 100.00
6 200.00

GraphQL 쿼리

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

생성된 SQL

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;

이 쿼리의 경우 다음과 같습니다 @param110000.

결과 출력

{
  "data": {
    "products": {
      "groupBy": [
        {
          "fields": {
            "category": "Electronics"
          },
          "aggregations": {
            "totalValue": 15000,
            "averagePrice": 7500
          }
        },
        {
          "fields": {
            "category": "Furniture"
          },
          "aggregations": {
            "totalValue": 12000,
            "averagePrice": 6000
          }
        }
      ]
    }
  }
}
카테고리 총값 평균 가격
전자 15000 7,500
가구 12000 6000

고유값 개수

distinct: truecount와 함께 사용하여 각 그룹의 고유값 수를 계산합니다.

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

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

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;

결과 출력

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

일반적인 실수

  • 컬렉션 필드 내에서 groupBy을 선택합니다. 컬렉션 인수로 전달 groupBy 하지 마세요.
  • aggregations이 아니라 aggregates을 사용합니다.
  • avg이 아니라 average을 사용합니다.
  • 필드 열거형 값(예: fields: [year].)을 사용합니다. 필드 이름을 인용하지 마세요.
  • 동일한 컬렉션 쿼리에서 선택 itemsgroupBy 하지 마세요.
  • 필드별로 그룹화할 때 개체 내에서 fields 동일한 필드만 선택합니다.