Notă
Accesul la această pagină necesită autorizare. Puteți încerca să vă conectați sau să modificați directoarele.
Accesul la această pagină necesită autorizare. Puteți încerca să modificați directoarele.
Filtering narrows your results to the rows that matter. Aggregation summarizes those rows into counts, totals, and averages. This article shows you how to apply both techniques in GQL queries against graph in Microsoft Fabric.
The examples use the social network sample dataset. For an end-to-end explanation of query flow and statements, see GQL language guide.
Use this article for row and pattern filtering, grouped and ungrouped aggregation, aggregate-specific filters, and conditional routing. For constructing multihop patterns and selecting paths, see Write graph pattern queries. For ready-to-adapt business tasks, see Write common GQL queries.
Prerequisites
- A graph item built from the social network sample dataset, with the node types, edge types, and properties described in the social network schema example.
- Familiarity with basic
MATCHandRETURNqueries. See GQL language guide.
Filter rows with FILTER
Use FILTER to keep only the rows that meet a condition. Place FILTER after MATCH to narrow the matched results.
The following query returns all females with their name and birthday:
MATCH (p:Person)
FILTER p.gender = 'female'
RETURN p.firstName, p.lastName, p.birthday
Combine multiple conditions with AND and OR. For example, the following query returns the names of all females born before 1990:
MATCH (p:Person)
FILTER p.gender = 'female' AND p.birthday < 19900101
RETURN p.firstName, p.lastName
Tip
Use an inline WHERE clause when the condition defines which node or edge can
participate in the match. Use FILTER when the condition applies to the row
produced by an earlier statement. Predicate placement can change
shortest-path results; see Place predicates before or after path
selection.
Filter during pattern matching
Inline WHERE clauses inside a MATCH pattern restrict which nodes and edges qualify for the match. The query optimizer can apply equivalent predicates during scanning, so inline syntax isn't inherently faster than a separate FILTER. Choose the form that expresses the intended semantics.
For example, to find people born before 1994 along with the company where they work, limiting results to companies whose name starts with 'A':
MATCH (p:Person WHERE p.birthday < 19940101)-[:workAt]->(c:Company WHERE c.name STARTS WITH 'A')
RETURN p.firstName, p.lastName, c.name
Filter edge properties the same way. For example, to return only people who started working at a company in 2000 or later:
MATCH (p:Person)-[w:workAt WHERE w.workFrom >= 2000]->(c:Company)
RETURN p.firstName, p.lastName, c.name, w.workFrom
For more information about choosing between inline and post-match filtering, see Optimize GQL query performance.
Handle null values in filters
GQL uses three-valued logic: predicates evaluate to TRUE, FALSE, or UNKNOWN. When a property value is null, comparisons return UNKNOWN. FILTER treats UNKNOWN as not matching, so the row is excluded.
Use IS NULL and IS NOT NULL to test for null values explicitly:
-- Only include people whose browser is known
MATCH (p:Person)
FILTER p.browserUsed IS NOT NULL
RETURN p.firstName, p.browserUsed
Use coalesce() to substitute a default value when a property might be null:
MATCH (p:Person)
RETURN p.firstName, coalesce(p.browserUsed, 'Unknown browser') AS browser
Caution
NULL = NULL evaluates to UNKNOWN, not TRUE. Always use IS NULL to test for null values, not equality.
Aggregate results with RETURN
Use aggregate functions in RETURN to summarize your results. Graph supports
the following aggregate functions: COUNT, SUM, AVG, MIN, MAX,
COLLECT_LIST, COLLECT_ONE, and COLLECT_ELEMENTS.
For example, to count all people in the graph:
MATCH (p:Person)
RETURN count(*) AS totalPeople
To count distinct values such as how many distinct companies employ people:
MATCH (p:Person)-[:workAt]->(c:Company)
RETURN count(DISTINCT c) AS companyCount
Filter input for one aggregate
Add FILTER (WHERE predicate) after an aggregate to filter only that
aggregate's input. Other aggregates in the same RETURN still receive all
input rows.
MATCH (p:Person)
RETURN count(*) AS allPeople,
count(*) FILTER (WHERE p.birthday < 19900101) AS peopleBornBefore1990
Add LIMIT inside the aggregate filter to use at most that many qualifying
rows. The query applies the predicate before the aggregate-specific limit.
MATCH (p:Person)
RETURN count(*) FILTER (WHERE p.birthday < 19900101 LIMIT 100) AS sampleCount
Aggregate-specific FILTER and LIMIT don't remove rows from the rest of the
query. Use a FILTER statement or match-level WHERE clause when you want to
filter the row stream.
Collect values
Use COLLECT_LIST to return one list element for each input value, including
null values. Add DISTINCT to remove duplicates.
MATCH (p:Person)
RETURN collect_list(DISTINCT p.browserUsed) AS browsers
COLLECT_ONE returns one non-null input value. The selected value isn't
deterministic, so use it only when any value from the group is acceptable.
COLLECT_ELEMENTS accepts list-valued inputs and concatenates their elements
into one list:
MATCH (p:Person)
RETURN collect_elements([p.firstName, p.lastName]) AS names
Without grouping columns, an aggregate query with no input rows returns an
empty list from COLLECT_LIST and COLLECT_ELEMENTS and null from
COLLECT_ONE.
Group results with GROUP BY
Use GROUP BY in RETURN to group rows by shared values and compute aggregates within each group. This grouping is the GQL equivalent of SQL GROUP BY.
For example, to count employees per company:
MATCH (p:Person)-[:workAt]->(c:Company)
LET companyId = c.id, companyName = c.name
RETURN companyId, companyName, count(*) AS employeeCount
GROUP BY companyId, companyName
ORDER BY employeeCount DESC
Group by multiple columns and compute several aggregates at once. For example, break down the person count and birthday range by gender and browser, returning the 10 most common combinations:
MATCH (p:Person)
LET gender = p.gender
LET browser = p.browserUsed
RETURN gender,
browser,
count(*) AS personCount,
min(p.birthday) AS earliestBirthday,
max(p.birthday) AS latestBirthday
GROUP BY gender, browser
ORDER BY personCount DESC
LIMIT 10
Note
All non-aggregate expressions in RETURN must appear in GROUP BY. Expressions that aren't in GROUP BY must use an aggregate function.
Sort and limit aggregated results
Use ORDER BY and LIMIT together with GROUP BY to find top-N results.
For example, to find the top five cities by number of residents:
MATCH (p:Person)-[:isLocatedIn]->(city:City)
LET cityId = city.id, cityName = city.name
RETURN cityId, cityName, count(*) AS residentCount
GROUP BY cityId, cityName
ORDER BY residentCount DESC
LIMIT 5
Important
Place ORDER BY before LIMIT. LIMIT always applies to the already-sorted result set.
Route rows with conditional statements
Use a conditional statement to route each incoming row to the first matching branch. The input can come from any preceding query stage, not only an aggregation. For example, the following query categorizes companies after calculating their employee counts:
MATCH (p:Person)-[:workAt]->(c:Company)
LET companyId = c.id, companyName = c.name
RETURN companyId, companyName, count(*) AS employeeCount
GROUP BY companyId, companyName
NEXT
WHEN employeeCount >= 100u THEN
RETURN companyId, companyName, employeeCount, 'Large' AS category
WHEN employeeCount >= 10u THEN
RETURN companyId, companyName, employeeCount, 'Medium' AS category
ELSE
RETURN companyId, companyName, employeeCount, 'Small' AS category
Branches can run complete query statements and nested procedures, rather than
only returning expressions. The following example sends three input rows
through different branch shapes. One branch runs a MATCH, one combines two
aggregates with UNION ALL and then aggregates their results, and the fallback
branch returns a constant:
FOR selector IN [1, 2, 3]
RETURN selector
NEXT
WHEN selector = 1 THEN
MATCH (:Person)-[:knows]->(:Person)
RETURN count(*) AS total, 'Knows edges' AS category
WHEN selector = 2 THEN {
MATCH (:Person)-[:workAt]->(:Company)
RETURN count(*) AS partialCount
UNION ALL
MATCH (:Person)-[:studyAt]->(:University)
RETURN count(*) AS partialCount
NEXT
RETURN sum(partialCount) AS total, 'Affiliation edges' AS category
}
ELSE
RETURN 0u AS total, 'No selected metric' AS category
The query engine evaluates the predicates in order for each row. It runs only the first matching branch. If a predicate evaluates to UNKNOWN, evaluation continues with the next branch. Without an ELSE, rows that don't match a WHEN branch are omitted.
Conditional statements are different from CASE expressions. Graph supports simple CASE <expression> WHEN <value> expressions for equality-based value selection. Searched CASE WHEN <predicate> expressions aren't supported. For more information, see Conditional statements.