子查询与嵌套 #

一、子查询概述 #

1.1 子查询类型 #

text
子查询类型:
├── WHERE子查询 - 条件过滤
├── FROM子查询 - 数据源
├── SELECT子查询 - 投影计算
└── LET子查询 - 变量定义

1.2 子查询特点 #

text
子查询特点:
├── 可以嵌套多层
├── 支持关联子查询
├── 可返回单值或集合
└── 可在多个位置使用

二、WHERE子查询 #

2.1 IN子查询 #

sql
SELECT FROM Person WHERE employer IN (
    SELECT FROM Company WHERE industry = 'Technology'
)

2.2 NOT IN子查询 #

sql
SELECT FROM Person WHERE @rid NOT IN (
    SELECT customer FROM Order WHERE status = 'cancelled'
)

2.3 EXISTS子查询 #

sql
SELECT FROM Person p WHERE (
    SELECT COUNT(*) FROM Order WHERE customer = p.@rid
) > 0

2.4 比较子查询 #

sql
SELECT FROM Employee WHERE salary > (
    SELECT AVG(salary) FROM Employee
)

2.5 多条件子查询 #

sql
SELECT FROM Person WHERE 
    employer IN (SELECT FROM Company WHERE industry = 'Tech')
    AND @rid NOT IN (SELECT person FROM Blacklist)

三、FROM子查询 #

3.1 基本FROM子查询 #

sql
SELECT name, age FROM (
    SELECT FROM Person WHERE age > 30
)

3.2 带条件的FROM子查询 #

sql
SELECT name, city FROM (
    SELECT FROM Person WHERE status = 'active'
) WHERE age > 25

3.3 多层FROM子查询 #

sql
SELECT name, avgAge FROM (
    SELECT city, name, AVG(age) AS avgAge
    FROM (
        SELECT FROM Person WHERE status = 'active'
    )
    GROUP BY city
) WHERE avgAge > 30

3.4 聚合FROM子查询 #

sql
SELECT AVG(deptCount) AS avgDeptSize FROM (
    SELECT department, COUNT(*) AS deptCount
    FROM Employee
    GROUP BY department
)

四、SELECT子查询 #

4.1 单值子查询 #

sql
SELECT 
    name,
    (SELECT COUNT(*) FROM Order WHERE customer = @rid) AS orderCount
FROM Person

4.2 多字段子查询 #

sql
SELECT 
    name,
    (SELECT SUM(amount) FROM Order WHERE customer = @rid) AS totalSpent,
    (SELECT MAX(createdAt) FROM Order WHERE customer = @rid) AS lastOrderDate
FROM Person

4.3 关联子查询 #

sql
SELECT 
    p.name,
    (SELECT name FROM Company WHERE @rid = p.employer)[0] AS companyName
FROM Person p

4.4 条件子查询 #

sql
SELECT 
    name,
    IF(
        (SELECT COUNT(*) FROM Order WHERE customer = @rid) > 10,
        'VIP',
        'Regular'
    ) AS customerLevel
FROM Person

五、LET语句详解 #

5.1 基本LET #

sql
LET $activeUsers = SELECT FROM User WHERE status = 'active'
SELECT name, email FROM $activeUsers

5.2 多变量LET #

sql
LET $users = SELECT FROM User WHERE status = 'active'
LET $orders = SELECT FROM Order WHERE createdAt > sysdate() - 30
SELECT 
    u.name,
    COUNT(o) AS orderCount
FROM $users u
LET $userOrders = (SELECT FROM $orders WHERE userId = u.@rid)
WHERE $userOrders.size() > 0

5.3 LET与子查询 #

sql
LET $topCustomers = (
    SELECT customer, SUM(amount) AS totalSpent
    FROM Order
    GROUP BY customer
    ORDER BY totalSpent DESC
    LIMIT 10
)
SELECT 
    c.name AS customerName,
    t.totalSpent
FROM $topCustomers t
LET c = (SELECT FROM Customer WHERE @rid = t.customer)

5.4 LET循环引用 #

sql
LET $managers = SELECT FROM Employee WHERE level = 'manager'
SELECT 
    m.name AS managerName,
    $team.size() AS teamSize
FROM $managers m
LET $team = (SELECT FROM Employee WHERE manager = m.@rid)
WHERE $team.size() > 0

5.5 LET缓存优化 #

sql
LET $companies = SELECT FROM Company WHERE industry = 'Tech'
SELECT 
    p.name,
    $c.name AS companyName
FROM Person p
LET $c = (SELECT FROM $companies WHERE @rid = p.employer)
WHERE $c.size() > 0

六、嵌套表达式 #

6.1 嵌套CASE #

sql
SELECT 
    name,
    CASE 
        WHEN status = 'active' THEN 
            CASE 
                WHEN level = 'VIP' THEN 'Active VIP'
                ELSE 'Active Regular'
            END
        ELSE 'Inactive'
    END AS customerStatus
FROM Customer

6.2 嵌套函数 #

sql
SELECT 
    name,
    UPPER(TRIM(name)) AS cleanName,
    ROUND(AVG(salary), 2) AS avgSalary
FROM Employee

6.3 嵌套条件 #

sql
SELECT 
    name,
    IF(
        age > 18,
        IF(status = 'active', 'Adult Active', 'Adult Inactive'),
        'Minor'
    ) AS category
FROM Person

七、关联子查询 #

7.1 基本关联 #

sql
SELECT 
    p.name,
    (SELECT COUNT(*) FROM Order WHERE customer = p.@rid) AS orderCount
FROM Person p

7.2 多表关联 #

sql
SELECT 
    p.name,
    (SELECT name FROM Company WHERE @rid = p.employer)[0] AS company,
    (SELECT COUNT(*) FROM Order WHERE customer = p.@rid) AS orders
FROM Person p

7.3 条件关联 #

sql
SELECT 
    p.name,
    (SELECT SUM(amount) FROM Order 
     WHERE customer = p.@rid AND status = 'completed') AS totalSpent
FROM Person p
WHERE (SELECT COUNT(*) FROM Order WHERE customer = p.@rid) > 0

八、递归查询 #

8.1 图遍历递归 #

sql
SELECT 
    name,
    out('MANAGES').name AS directReports
FROM Employee
WHERE level = 'CEO'

8.2 路径递归 #

sql
TRAVERSE out('KNOWS') FROM #12:0 MAXDEPTH 3

8.3 层级查询 #

sql
SELECT 
    @rid,
    name,
    $path AS path,
    $depth AS depth
FROM (
    TRAVERSE out('REPORTS_TO') FROM #12:0
)

九、复杂查询示例 #

9.1 多层嵌套统计 #

sql
LET $deptStats = (
    SELECT 
        department,
        COUNT(*) AS empCount,
        AVG(salary) AS avgSalary
    FROM Employee
    GROUP BY department
)
SELECT 
    d.name AS departmentName,
    s.empCount,
    s.avgSalary,
    CASE 
        WHEN s.avgSalary > (SELECT AVG(avgSalary) FROM $deptStats) THEN 'Above Average'
        ELSE 'Below Average'
    END AS salaryLevel
FROM $deptStats s
LET d = (SELECT FROM Department WHERE @rid = s.department)

9.2 复杂业务查询 #

sql
LET $orders = SELECT FROM Order WHERE createdAt > sysdate() - 30
LET $customers = SELECT FROM Customer WHERE status = 'active'
SELECT 
    c.name AS customerName,
    COUNT(o) AS orderCount,
    SUM(o.totalAmount) AS totalSpent,
    AVG(o.totalAmount) AS avgOrderValue,
    MAX(o.createdAt) AS lastOrderDate
FROM $customers c
LET $customerOrders = (SELECT FROM $orders WHERE customer = c.@rid)
UNWIND $customerOrders AS o
GROUP BY c
HAVING COUNT(o) > 0
ORDER BY totalSpent DESC

9.3 层级聚合 #

sql
SELECT 
    region,
    SUM(deptTotal) AS regionTotal,
    AVG(deptAvg) AS regionAvg
FROM (
    SELECT 
        department,
        region,
        SUM(salary) AS deptTotal,
        AVG(salary) AS deptAvg
    FROM Employee
    GROUP BY department, region
)
GROUP BY region

十、性能优化 #

10.1 使用LET缓存 #

sql
LET $companies = SELECT FROM Company
SELECT p.name, $c.name 
FROM Person p
LET $c = (SELECT FROM $companies WHERE @rid = p.employer)

10.2 避免重复子查询 #

sql
LET $orderCount = (SELECT COUNT(*) FROM Order WHERE customer = @rid)
SELECT name, $orderCount AS orderCount
FROM Person
WHERE $orderCount > 0

10.3 限制子查询结果 #

sql
SELECT FROM Person WHERE employer IN (
    SELECT FROM Company WHERE industry = 'Tech' LIMIT 100
)

10.4 使用索引 #

sql
CREATE INDEX Order.customer LINK
SELECT FROM Order WHERE customer = (SELECT FROM Person WHERE name = 'Tom')

十一、实际应用示例 #

11.1 客户价值分析 #

sql
LET $customerStats = (
    SELECT 
        customer,
        COUNT(*) AS orderCount,
        SUM(totalAmount) AS totalSpent,
        AVG(totalAmount) AS avgOrderValue,
        MAX(createdAt) AS lastOrderDate
    FROM Order
    WHERE status = 'completed'
    GROUP BY customer
)
SELECT 
    c.name AS customerName,
    c.email,
    s.orderCount,
    s.totalSpent,
    s.avgOrderValue,
    DATEDIFF('day', s.lastOrderDate, sysdate()) AS daysSinceLastOrder,
    CASE 
        WHEN s.totalSpent > 10000 THEN 'VIP'
        WHEN s.totalSpent > 5000 THEN 'Gold'
        WHEN s.totalSpent > 1000 THEN 'Silver'
        ELSE 'Bronze'
    END AS customerLevel
FROM $customerStats s
LET c = (SELECT FROM Customer WHERE @rid = s.customer)
ORDER BY s.totalSpent DESC

11.2 员工绩效分析 #

sql
LET $employeeMetrics = (
    SELECT 
        e.@rid AS employeeId,
        e.name,
        e.department,
        COUNT(p) AS projectCount,
        AVG(p.score) AS avgScore,
        SUM(p.hours) AS totalHours
    FROM Employee e
    LET $projects = (SELECT FROM Project WHERE employeeId = e.@rid)
    UNWIND $projects AS p
    GROUP BY e
)
SELECT 
    m.name,
    m.department,
    m.projectCount,
    m.avgScore,
    m.totalHours,
    RANK() OVER (ORDER BY m.avgScore DESC) AS performanceRank
FROM $employeeMetrics m

11.3 产品推荐查询 #

sql
LET $userPurchases = (
    SELECT productId, COUNT(*) AS purchaseCount
    FROM OrderItem
    WHERE orderId IN (SELECT @rid FROM Order WHERE customer = #12:0)
    GROUP BY productId
)
LET $similarUsers = (
    SELECT customer, COUNT(*) AS commonProducts
    FROM OrderItem
    WHERE productId IN (SELECT productId FROM $userPurchases)
    AND customer != #12:0
    GROUP BY customer
    ORDER BY commonProducts DESC
    LIMIT 10
)
SELECT 
    p.name AS productName,
    COUNT(*) AS recommendationScore
FROM OrderItem oi
WHERE oi.orderId IN (SELECT @rid FROM Order WHERE customer IN (SELECT customer FROM $similarUsers))
AND oi.productId NOT IN (SELECT productId FROM $userPurchases)
LET p = (SELECT FROM Product WHERE @rid = oi.productId)
GROUP BY oi.productId
ORDER BY recommendationScore DESC
LIMIT 10

十二、总结 #

子查询与嵌套要点:

类型 说明 示例
WHERE子查询 条件过滤 WHERE … IN (SELECT …)
FROM子查询 数据源 FROM (SELECT …)
SELECT子查询 投影计算 (SELECT COUNT(*) …)
LET语句 变量定义 LET $var = …
关联子查询 引用外部 WHERE customer = p.@rid

下一步,让我们学习图数据库!

最后更新:2026-03-27