F# Guide — Query Expressions: LINQ-Style Data Queries
In this tutorial, you will learn about F# Guide. We cover key concepts, practical examples, and best practices to help you master this topic.
F# query expressions provide a LINQ-like syntax for querying data sources using comprehension syntax with select, where, groupBy, join, and sorting operations.
What You'll Learn
- Query expression syntax
- Select, where, and sorting
- Grouping and aggregation
- Joining data sources
- Database queries with query expressions
Why It Matters
Query expressions bridge functional operations with database queries, enabling type-safe queries against SQL, entity frameworks, and other queryable sources. Durga Antivirus Pro uses queries for log analysis.
Real-World Use
Querying SQL databases, filtering large in-memory collections, generating reports, and data analysis.
flowchart LR
A["Query Expressions"] --> B["Syntax"]
B --> C["Operations"]
C --> D["Grouping"]
D --> E["Joins"]
A:::current --> B
style A fill:#2563eb,stroke:#2563eb,color:#fff
style B fill:#dbeafe,stroke:#2563eb,color:#1e40af
style C fill:#dbeafe,stroke:#2563eb,color:#1e40af
style D fill:#dbeafe,stroke:#2563eb,color:#1e40af
style E fill:#f1f5f9,stroke:#94a3b8,color:#64748b
Basic Query
open System.Linq
let data = [1; 2; 3; 4; 5; 6]
let query = query {
for x in data do
where (x > 3)
sortBy x
select x
}
let results = query |> Seq.toList
// [4; 5; 6]
Select
let numbers = [1..10]
let doubled = query {
for n in numbers do
select (n * 2)
}
// [2; 4; 6; 8; 10; 12; 14; 16; 18; 20]
let namedResults = query {
for n in numbers do
select {| Original = n; Squared = n * n |}
}
Filtering
let data = [1..20]
let filtered = query {
for x in data do
where (x % 2 = 0)
where (x > 10)
sortByDescending x
select x
}
// [20; 18; 16; 14; 12]
// Or combine conditions
let combined = query {
for x in data do
where (x > 5 && x < 15)
select x
}
Grouping
type Person = { Name: string; Age: int; Dept: string }
let people = [
{ Name = "Alice"; Age = 30; Dept = "Eng" }
{ Name = "Bob"; Age = 25; Dept = "Eng" }
{ Name = "Carol"; Age = 35; Dept = "Sales" }
]
let grouped = query {
for p in people do
groupBy p.Dept into g
select (g.Key, g |> Seq.length)
}
// [("Eng", 2); ("Sales", 1)]
let withAverage = query {
for p in people do
groupBy p.Dept into g
select (g.Key, g |> Seq.averageBy (fun p -> float p.Age))
}
Joins
type Dept = { Id: int; Name: string }
type Employee = { Id: int; Name: string; DeptId: int }
let depts = [{Id=1; Name="Eng"}; {Id=2; Name="Sales"}]
let emps = [{Id=1; Name="Alice"; DeptId=1}; {Id=2; Name="Bob"; DeptId=2}]
let joined = query {
for e in emps do
join d in depts on (e.DeptId = d.Id)
select (e.Name, d.Name)
}
// [("Alice", "Eng"); ("Bob", "Sales")]
// Left join
let leftJoin = query {
for e in emps do
leftOuterJoin d in depts on (e.DeptId = d.Id) into grouping
for d in grouping.DefaultIfEmpty() do
select (e.Name, d |> Option.map (fun d -> d.Name))
}
Aggregation
let sales = [100.0; 200.0; 150.0; 300.0; 50.0]
let aggregates = query {
for s in sales do
select (s)
count
}
// 5
let sum = query { for s in sales do sumBy s }
// 800.0
let avg = query { for s in sales do averageBy (float s) }
// 160.0
Distinct and Take
let items = [1; 1; 2; 3; 2; 4; 5]
let distinct = query {
for i in items do
distinct
select i
}
// [1; 2; 3; 4; 5]
let firstThree = query {
for i in items do
take 3
select i
}
// [1; 1; 2]
Common Mistakes
1. Forgetting to evaluate
Query expressions are lazy. Use Seq.toList or Seq.toArray to force evaluation.
2. Multiple from vs join
Use from for cross product, join for inner join with condition.
3. Using query on non-queryable data
Query expressions work on IEnumerable. Use query { } for in-memory queries, LINQ to SQL for databases.
4. Complex grouping
Use groupBy with into to continue the query after grouping.
5. Mixing query and collection functions
Query expressions are separate from List/Seq functions. Choose one approach consistently.
Practice Questions
1. What is a query expression? A syntax for querying data sources using comprehension syntax with operations like select, where, groupBy, and join.
2. How does groupBy work in queries?
Group elements by a key, then continue the query with into groupName. Access .Key for group key.
3. When should you use queries vs List functions? Use queries for SQL-like operations and databases. Use List/Seq functions for in-memory transformations.
Challenge: Write a query that joins orders with customers and groups by customer.
FAQ
{{< faq question="Are F# queries efficient?" >}} Yes. Queries are compiled to LINQ expressions that can be translated to SQL or executed efficiently on in-memory data. {{< /faq >}}
{{< faq question="Can I use queries with databases?" >}} Yes, using query expressions with Entity Framework or other LINQ providers. The query compiles to SQL. {{< /faq >}}
{{< faq question="What is the difference between query and Seq?" >}} Query expressions have SQL-like syntax and support operations like groupBy and join more naturally than Seq functions. {{< /faq >}}
{{< faq question="Can I page results?" >}
Yes, use skip n and take n for paging: query { for x in data do skip 10; take 10; select x }.
{{< /faq >}}
{{< faq question="Do queries support nested queries?" >} Yes. You can nest query expressions inside other queries for subquery functionality. {{< /faq >}}
Mini Project
Build a reporting query for employee data:
type Employee = { Name: string; Salary: decimal; Dept: string; Years: int }
let employees = [
{ Name = "Alice"; Salary = 80000m; Dept = "Eng"; Years = 5 }
{ Name = "Bob"; Salary = 60000m; Dept = "Eng"; Years = 2 }
{ Name = "Carol"; Salary = 90000m; Dept = "Sales"; Years = 8 }
]
let deptReport = query {
for e in employees do
groupBy e.Dept into g
select {| Dept = g.Key
Count = g |> Seq.length
AvgSalary = g |> Seq.averageBy (fun e -> e.Salary)
MaxYears = g |> Seq.maxBy (fun e -> e.Years) |}
}
What's Next
Now that you understand query expressions, explore type providers for data integration.
| Topic | Description | Link |
|---|---|---|
| F# Type Providers | Data type providers | {{< ref "22-type-providers" >}} |
| F# File I/O | File operations | {{< ref "23-file-io" >}} |
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro