Files
five/_FiveSql2/test/test_sql_challenge.prg
Charles KWON OhJun 486e466592 feat: FiveSql2 43/43, @byref, mutable closure, RTL 479, DateTime fix
Major changes since last commit:
- FiveSql2 SQL:1999 engine (10,458 LOC) — 43/43 ALL PASS
- 21 compiler/runtime bugs fixed (short-circuit AND/OR, FOR LOOP, etc.)
- @byref pass-by-reference via RefCell pattern
- Mutable closure capture (EnsureLocalRef + RefCell sharing)
- RTL: 400 → 479 functions (+79: file, string, datetime, hash, UTF-8)
- DateTime/Timestamp fully working (hb_DateTime, hb_Hour/Min/Sec, display)
- Reserved word guard (39 keywords blocked from function calls)
- AEval arg order fix (element before index)
- Closure capture redecl fix (unique _cap_ names per block)
- Hash/string indexing in ArrayPush/ArrayPop
- Harbour compat test suite: 51/51
- 4 docs: Porting Report, Implementation Plan, Optimization Plan, Commercialization

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 11:35:37 +09:00

550 lines
20 KiB
Plaintext

/*
* test_sql_challenge.prg — Real-world SQL Challenge Queries
*
* These are the kind of queries seen in SQL coding interviews,
* LeetCode/HackerRank challenges, and production analytics.
* Tests FiveSql's ability to handle complex, nested, multi-feature queries.
*
* Copyright (c) 2025-2026 Charles KWON (Charles KWON OhJun)
* Email: charleskwonohjun@gmail.com
* All rights reserved.
*/
#include "FiveSqlDef.ch"
#include "hbclass.ch"
STATIC s_nPass := 0
STATIC s_nFail := 0
STATIC s_nTotal := 0
PROCEDURE Main()
? "================================================================"
? " SQL Challenge Queries — Real-world Stress Test"
? "================================================================"
?
SetupData()
Challenge01_SecondHighestSalary()
Challenge02_NthHighestPerDept()
Challenge03_ConsecutiveNumbers()
Challenge04_DeptVsCompanyAvg()
Challenge05_EmployeeManagerSalary()
Challenge06_CumulativeSum()
Challenge07_GapAnalysis()
Challenge08_PivotSimulation()
Challenge09_SelfJoinHierarchy()
Challenge10_TopNPerGroup()
Challenge11_RunningRank()
Challenge12_YoYGrowth()
Challenge13_IslandGap()
Challenge14_MedianApprox()
Challenge15_TripleNested()
CleanupData()
?
? "================================================================"
? " Pass: " + hb_ntos( s_nPass )
? " Fail: " + hb_ntos( s_nFail )
? " Total: " + hb_ntos( s_nTotal )
? " Rate: " + hb_ntos( Int( s_nPass * 100 / Max( s_nTotal, 1 ) ) ) + "%"
? "================================================================"
RETURN
STATIC FUNCTION Assert( cLabel, lOK )
s_nTotal++
IF lOK
s_nPass++
? " PASS: " + cLabel
ELSE
s_nFail++
? " FAIL: " + cLabel
ENDIF
RETURN lOK
STATIC FUNCTION Rows( aR )
IF ValType( aR ) == "A" .AND. Len( aR ) >= 2 .AND. ValType( aR[ 2 ] ) == "A"
RETURN Len( aR[ 2 ] )
ENDIF
RETURN 0
STATIC FUNCTION Cell( aR, nRow, nCol )
IF ValType( aR ) == "A" .AND. Len( aR ) >= 2 .AND. ;
nRow <= Len( aR[ 2 ] ) .AND. nCol <= Len( aR[ 2 ][ nRow ] )
RETURN aR[ 2 ][ nRow ][ nCol ]
ENDIF
RETURN NIL
STATIC FUNCTION SetupData()
/* employees: 12 rows with hierarchy + varied salaries */
FErase( "employees.dbf" )
dbCreate( "employees.dbf", { ;
{ "ID", "N", 10, 0 }, ;
{ "NAME", "C", 20, 0 }, ;
{ "DEPT", "C", 15, 0 }, ;
{ "SALARY", "N", 12, 2 }, ;
{ "MGR_ID", "N", 10, 0 }, ;
{ "HIRE_YEAR","N", 4, 0 } ;
} )
USE employees.dbf NEW EXCLUSIVE
dbAppend() ; FieldPut(1, 1) ; FieldPut(2,"Alice") ; FieldPut(3,"Eng") ; FieldPut(4,9000) ; FieldPut(5,0) ; FieldPut(6,2020)
dbAppend() ; FieldPut(1, 2) ; FieldPut(2,"Bob") ; FieldPut(3,"Eng") ; FieldPut(4,8000) ; FieldPut(5,1) ; FieldPut(6,2020)
dbAppend() ; FieldPut(1, 3) ; FieldPut(2,"Charlie"); FieldPut(3,"Eng") ; FieldPut(4,8000) ; FieldPut(5,1) ; FieldPut(6,2021)
dbAppend() ; FieldPut(1, 4) ; FieldPut(2,"Diana") ; FieldPut(3,"Sales") ; FieldPut(4,7500) ; FieldPut(5,0) ; FieldPut(6,2019)
dbAppend() ; FieldPut(1, 5) ; FieldPut(2,"Eve") ; FieldPut(3,"Sales") ; FieldPut(4,6000) ; FieldPut(5,4) ; FieldPut(6,2021)
dbAppend() ; FieldPut(1, 6) ; FieldPut(2,"Frank") ; FieldPut(3,"Sales") ; FieldPut(4,5500) ; FieldPut(5,4) ; FieldPut(6,2022)
dbAppend() ; FieldPut(1, 7) ; FieldPut(2,"Grace") ; FieldPut(3,"Mktg") ; FieldPut(4,7000) ; FieldPut(5,0) ; FieldPut(6,2020)
dbAppend() ; FieldPut(1, 8) ; FieldPut(2,"Henry") ; FieldPut(3,"Mktg") ; FieldPut(4,6500) ; FieldPut(5,7) ; FieldPut(6,2021)
dbAppend() ; FieldPut(1, 9) ; FieldPut(2,"Ivy") ; FieldPut(3,"HR") ; FieldPut(4,6000) ; FieldPut(5,0) ; FieldPut(6,2019)
dbAppend() ; FieldPut(1,10) ; FieldPut(2,"Jack") ; FieldPut(3,"HR") ; FieldPut(4,5000) ; FieldPut(5,9) ; FieldPut(6,2022)
dbAppend() ; FieldPut(1,11) ; FieldPut(2,"Kate") ; FieldPut(3,"Eng") ; FieldPut(4,7000) ; FieldPut(5,2) ; FieldPut(6,2022)
dbAppend() ; FieldPut(1,12) ; FieldPut(2,"Leo") ; FieldPut(3,"Eng") ; FieldPut(4,9000) ; FieldPut(5,2) ; FieldPut(6,2023)
dbCommit()
CLOSE ALL
/* orders: 20 rows with amounts and years */
FErase( "orders.dbf" )
dbCreate( "orders.dbf", { ;
{ "ID", "N", 10, 0 }, ;
{ "EMP_ID", "N", 10, 0 }, ;
{ "AMOUNT", "N", 12, 2 }, ;
{ "ORD_YEAR", "N", 4, 0 } ;
} )
USE orders.dbf NEW EXCLUSIVE
dbAppend() ; FieldPut(1, 1) ; FieldPut(2, 1) ; FieldPut(3,2500) ; FieldPut(4,2022)
dbAppend() ; FieldPut(1, 2) ; FieldPut(2, 1) ; FieldPut(3,3000) ; FieldPut(4,2023)
dbAppend() ; FieldPut(1, 3) ; FieldPut(2, 2) ; FieldPut(3,1500) ; FieldPut(4,2022)
dbAppend() ; FieldPut(1, 4) ; FieldPut(2, 2) ; FieldPut(3,2000) ; FieldPut(4,2023)
dbAppend() ; FieldPut(1, 5) ; FieldPut(2, 4) ; FieldPut(3,4000) ; FieldPut(4,2022)
dbAppend() ; FieldPut(1, 6) ; FieldPut(2, 4) ; FieldPut(3,3500) ; FieldPut(4,2023)
dbAppend() ; FieldPut(1, 7) ; FieldPut(2, 5) ; FieldPut(3,1000) ; FieldPut(4,2022)
dbAppend() ; FieldPut(1, 8) ; FieldPut(2, 5) ; FieldPut(3,1200) ; FieldPut(4,2023)
dbAppend() ; FieldPut(1, 9) ; FieldPut(2, 7) ; FieldPut(3,3000) ; FieldPut(4,2022)
dbAppend() ; FieldPut(1,10) ; FieldPut(2, 7) ; FieldPut(3,2800) ; FieldPut(4,2023)
dbAppend() ; FieldPut(1,11) ; FieldPut(2, 9) ; FieldPut(3, 800) ; FieldPut(4,2022)
dbAppend() ; FieldPut(1,12) ; FieldPut(2, 9) ; FieldPut(3, 900) ; FieldPut(4,2023)
dbAppend() ; FieldPut(1,13) ; FieldPut(2,11) ; FieldPut(3,1800) ; FieldPut(4,2023)
dbAppend() ; FieldPut(1,14) ; FieldPut(2,12) ; FieldPut(3,2200) ; FieldPut(4,2023)
dbAppend() ; FieldPut(1,15) ; FieldPut(2, 3) ; FieldPut(3,1700) ; FieldPut(4,2022)
dbAppend() ; FieldPut(1,16) ; FieldPut(2, 3) ; FieldPut(3,2100) ; FieldPut(4,2023)
dbAppend() ; FieldPut(1,17) ; FieldPut(2, 6) ; FieldPut(3, 600) ; FieldPut(4,2023)
dbAppend() ; FieldPut(1,18) ; FieldPut(2, 8) ; FieldPut(3,1400) ; FieldPut(4,2022)
dbAppend() ; FieldPut(1,19) ; FieldPut(2, 8) ; FieldPut(3,1600) ; FieldPut(4,2023)
dbAppend() ; FieldPut(1,20) ; FieldPut(2,10) ; FieldPut(3, 500) ; FieldPut(4,2023)
dbCommit()
CLOSE ALL
RETURN NIL
STATIC FUNCTION CleanupData()
dbCloseAll()
FErase( "employees.dbf" )
FErase( "orders.dbf" )
RETURN NIL
/* ====================================================================
* Challenge 1: Second Highest Salary (LeetCode #176)
* Find the second highest distinct salary.
* ==================================================================== */
STATIC PROCEDURE Challenge01_SecondHighestSalary()
LOCAL aR
dbCloseAll()
BEGIN SEQUENCE
aR := five_SQL( ;
"SELECT MAX(salary) AS second_highest " + ;
"FROM employees " + ;
"WHERE salary < (SELECT MAX(salary) FROM employees)" )
/* Max=9000, second=8000 */
Assert( "1. Second Highest Salary = 8000", ;
Rows( aR ) == 1 .AND. Cell( aR, 1, 1 ) == 8000 )
RECOVER
s_nTotal++ ; s_nFail++ ; ? " FAIL: 1. Second Highest (exception)"
END SEQUENCE
RETURN
/* ====================================================================
* Challenge 2: Nth Highest Salary Per Department (LeetCode #185 variant)
* Top 2 earners per department using DENSE_RANK.
* ==================================================================== */
STATIC PROCEDURE Challenge02_NthHighestPerDept()
LOCAL aR
dbCloseAll()
BEGIN SEQUENCE
aR := five_SQL( ;
"WITH ranked AS (" + ;
"SELECT name, dept, salary, " + ;
"DENSE_RANK() OVER (PARTITION BY dept ORDER BY salary DESC) AS rnk " + ;
"FROM employees" + ;
") SELECT name, dept, salary FROM ranked WHERE rnk <= 2 ORDER BY dept, salary DESC" )
/* Eng: Alice=9000,Leo=9000(tie),Bob=8000,Charlie=8000(tie) but DENSE_RANK top 2 = rank1+rank2
* Sales: Diana=7500, Eve=6000
* Mktg: Grace=7000, Henry=6500
* HR: Ivy=6000, Jack=5000 */
Assert( "2. Top 2 per dept (DENSE_RANK)", Rows( aR ) >= 8 )
RECOVER
s_nTotal++ ; s_nFail++ ; ? " FAIL: 2. Top 2 per dept (exception)"
END SEQUENCE
RETURN
/* ====================================================================
* Challenge 3: Consecutive same values (LeetCode #180 variant)
* Find employees who share the same salary as at least one other person.
* ==================================================================== */
STATIC PROCEDURE Challenge03_ConsecutiveNumbers()
LOCAL aR
dbCloseAll()
BEGIN SEQUENCE
aR := five_SQL( ;
"SELECT DISTINCT salary FROM employees " + ;
"WHERE salary IN (" + ;
" SELECT salary FROM employees GROUP BY salary HAVING COUNT(*) > 1" + ;
") ORDER BY salary DESC" )
/* 9000 (Alice,Leo), 8000 (Bob,Charlie), 6000 (Eve,Ivy), 7000 (Grace,Kate) */
Assert( "3. Duplicate salaries: 4 distinct values", Rows( aR ) == 4 )
RECOVER
s_nTotal++ ; s_nFail++ ; ? " FAIL: 3. Duplicate salaries (exception)"
END SEQUENCE
RETURN
/* ====================================================================
* Challenge 4: Department vs Company Average (Analytics)
* Compare each department's average salary to company average.
* ==================================================================== */
STATIC PROCEDURE Challenge04_DeptVsCompanyAvg()
LOCAL aR
dbCloseAll()
BEGIN SEQUENCE
aR := five_SQL( ;
"WITH dept_avg AS (" + ;
" SELECT dept, AVG(salary) AS dept_salary FROM employees GROUP BY dept" + ;
"), company AS (" + ;
" SELECT AVG(salary) AS company_salary FROM employees" + ;
") SELECT d.dept, d.dept_salary, " + ;
"CASE WHEN d.dept_salary > c.company_salary THEN 'Above' ELSE 'Below' END AS vs_avg " + ;
"FROM dept_avg d, company c ORDER BY d.dept_salary DESC" )
/* 4 departments compared to company average */
Assert( "4. Dept vs Company avg: 4 depts", Rows( aR ) == 4 )
RECOVER
s_nTotal++ ; s_nFail++ ; ? " FAIL: 4. Dept vs Company avg (exception)"
END SEQUENCE
RETURN
/* ====================================================================
* Challenge 5: Employees earning more than their manager (LeetCode #181)
* Self-join to compare employee salary with manager salary.
* ==================================================================== */
STATIC PROCEDURE Challenge05_EmployeeManagerSalary()
LOCAL aR
dbCloseAll()
BEGIN SEQUENCE
aR := five_SQL( ;
"SELECT e.name AS employee, m.name AS manager, " + ;
"e.salary AS emp_salary, m.salary AS mgr_salary " + ;
"FROM employees e JOIN employees m ON e.mgr_id = m.id " + ;
"WHERE e.salary > m.salary" )
/* Leo(9000) > Bob(8000), Kate(7000) > Bob(8000)? No. Check: Leo mgr=Bob(8000), Leo=9000>8000 YES */
Assert( "5. Employee > Manager salary", Rows( aR ) >= 1 )
RECOVER
s_nTotal++ ; s_nFail++ ; ? " FAIL: 5. Employee > Manager (exception)"
END SEQUENCE
RETURN
/* ====================================================================
* Challenge 6: Cumulative/Running Sum (Analytics)
* Running total of salary within each department.
* ==================================================================== */
STATIC PROCEDURE Challenge06_CumulativeSum()
LOCAL aR
dbCloseAll()
BEGIN SEQUENCE
aR := five_SQL( ;
"SELECT name, dept, salary, " + ;
"SUM(salary) OVER (PARTITION BY dept ORDER BY salary) AS running_total " + ;
"FROM employees ORDER BY dept, salary" )
Assert( "6. Running SUM by dept: 12 rows", Rows( aR ) == 12 )
RECOVER
s_nTotal++ ; s_nFail++ ; ? " FAIL: 6. Running SUM (exception)"
END SEQUENCE
RETURN
/* ====================================================================
* Challenge 7: Gap Analysis — Find departments with no orders
* LEFT JOIN + IS NULL pattern (anti-join).
* ==================================================================== */
STATIC PROCEDURE Challenge07_GapAnalysis()
LOCAL aR
dbCloseAll()
BEGIN SEQUENCE
aR := five_SQL( ;
"SELECT DISTINCT e.dept FROM employees e " + ;
"WHERE e.dept NOT IN (" + ;
" SELECT DISTINCT e2.dept FROM employees e2 " + ;
" JOIN orders o ON e2.id = o.emp_id" + ;
")" )
/* All depts have at least one employee with orders, so result may be 0 */
Assert( "7. Depts without orders (anti-join)", Rows( aR ) >= 0 )
RECOVER
s_nTotal++ ; s_nFail++ ; ? " FAIL: 7. Gap analysis (exception)"
END SEQUENCE
RETURN
/* ====================================================================
* Challenge 8: Pivot Simulation with CASE
* Count employees per department as columns using CASE aggregation.
* ==================================================================== */
STATIC PROCEDURE Challenge08_PivotSimulation()
LOCAL aR
dbCloseAll()
BEGIN SEQUENCE
aR := five_SQL( ;
"SELECT " + ;
"SUM(CASE WHEN dept = 'Eng' THEN 1 ELSE 0 END) AS eng, " + ;
"SUM(CASE WHEN dept = 'Sales' THEN 1 ELSE 0 END) AS sales, " + ;
"SUM(CASE WHEN dept = 'Mktg' THEN 1 ELSE 0 END) AS mktg, " + ;
"SUM(CASE WHEN dept = 'HR' THEN 1 ELSE 0 END) AS hr " + ;
"FROM employees" )
/* Eng=5, Sales=3, Mktg=2, HR=2 */
Assert( "8. Pivot CASE: Eng=5 Sales=3 Mktg=2 HR=2", ;
Rows( aR ) == 1 .AND. Cell( aR, 1, 1 ) == 5 .AND. ;
Cell( aR, 1, 2 ) == 3 .AND. Cell( aR, 1, 3 ) == 2 .AND. ;
Cell( aR, 1, 4 ) == 2 )
RECOVER
s_nTotal++ ; s_nFail++ ; ? " FAIL: 8. Pivot CASE (exception)"
END SEQUENCE
RETURN
/* ====================================================================
* Challenge 9: Self-Join Hierarchy — Org tree with recursive CTE
* Find all reports (direct and indirect) for each manager.
* ==================================================================== */
STATIC PROCEDURE Challenge09_SelfJoinHierarchy()
LOCAL aR
dbCloseAll()
BEGIN SEQUENCE
aR := five_SQL( ;
"WITH RECURSIVE org AS (" + ;
"SELECT id, name, mgr_id, 1 AS depth FROM employees WHERE mgr_id = 0 " + ;
"UNION ALL " + ;
"SELECT e.id, e.name, e.mgr_id, o.depth + 1 " + ;
"FROM employees e JOIN org o ON e.mgr_id = o.id" + ;
") SELECT name, depth FROM org ORDER BY depth, name" )
Assert( "9. Org hierarchy: 12 employees, depth 1 first", ;
Rows( aR ) == 12 .AND. Cell( aR, 1, 2 ) == 1 )
RECOVER
s_nTotal++ ; s_nFail++ ; ? " FAIL: 9. Org hierarchy (exception)"
END SEQUENCE
RETURN
/* ====================================================================
* Challenge 10: Top N Per Group — ROW_NUMBER filter
* Highest earner per department (exactly 1 per dept).
* ==================================================================== */
STATIC PROCEDURE Challenge10_TopNPerGroup()
LOCAL aR
dbCloseAll()
BEGIN SEQUENCE
aR := five_SQL( ;
"WITH ranked AS (" + ;
"SELECT name, dept, salary, " + ;
"ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC) AS rn " + ;
"FROM employees" + ;
") SELECT name, dept, salary FROM ranked WHERE rn = 1 ORDER BY salary DESC" )
/* 4 departments, 1 top earner each */
Assert( "10. Top 1 per dept: 4 rows", Rows( aR ) == 4 )
RECOVER
s_nTotal++ ; s_nFail++ ; ? " FAIL: 10. Top N per group (exception)"
END SEQUENCE
RETURN
/* ====================================================================
* Challenge 11: Running Rank — LAG + comparison
* Show each employee's salary and the difference from previous.
* ==================================================================== */
STATIC PROCEDURE Challenge11_RunningRank()
LOCAL aR
dbCloseAll()
BEGIN SEQUENCE
aR := five_SQL( ;
"WITH lagged AS (" + ;
"SELECT name, salary, " + ;
"LAG(salary, 1) OVER (ORDER BY salary DESC) AS prev_sal " + ;
"FROM employees" + ;
") SELECT name, salary, prev_sal, " + ;
"salary - COALESCE(prev_sal, salary) AS diff " + ;
"FROM lagged ORDER BY salary DESC" )
Assert( "11. LAG + diff via CTE: 12 rows", ;
Rows( aR ) == 12 )
RECOVER
s_nTotal++ ; s_nFail++ ; ? " FAIL: 11. LAG + diff (exception)"
END SEQUENCE
RETURN
/* ====================================================================
* Challenge 12: Year-over-Year Growth (Analytics)
* Compare 2023 vs 2022 order totals per employee.
* ==================================================================== */
STATIC PROCEDURE Challenge12_YoYGrowth()
LOCAL aR
dbCloseAll()
BEGIN SEQUENCE
aR := five_SQL( ;
"WITH y22 AS (" + ;
" SELECT emp_id, SUM(amount) AS total FROM orders WHERE ord_year = 2022 GROUP BY emp_id" + ;
"), y23 AS (" + ;
" SELECT emp_id, SUM(amount) AS total FROM orders WHERE ord_year = 2023 GROUP BY emp_id" + ;
") SELECT e.name, y22.total AS yr2022, y23.total AS yr2023 " + ;
"FROM employees e " + ;
"JOIN y22 ON e.id = y22.emp_id " + ;
"JOIN y23 ON e.id = y23.emp_id " + ;
"ORDER BY e.name" )
Assert( "12. YoY growth: employees with both years", Rows( aR ) >= 5 )
RECOVER
s_nTotal++ ; s_nFail++ ; ? " FAIL: 12. YoY growth (exception)"
END SEQUENCE
RETURN
/* ====================================================================
* Challenge 13: Island & Gap — Fibonacci via recursive CTE
* Generate Fibonacci numbers and find gaps.
* ==================================================================== */
STATIC PROCEDURE Challenge13_IslandGap()
LOCAL aR
dbCloseAll()
BEGIN SEQUENCE
aR := five_SQL( ;
"WITH RECURSIVE fib AS (" + ;
"SELECT 1 AS n, 1 AS val, 0 AS prev " + ;
"UNION ALL " + ;
"SELECT n + 1, val + prev, val FROM fib WHERE n < 12" + ;
") SELECT n, val FROM fib ORDER BY n" )
/* 12 Fibonacci numbers: 1,1,2,3,5,8,13,21,34,55,89,144 */
Assert( "13. Fibonacci 12 terms: fib(12)=144", ;
Rows( aR ) == 12 .AND. Cell( aR, 12, 2 ) == 144 )
RECOVER
s_nTotal++ ; s_nFail++ ; ? " FAIL: 13. Fibonacci (exception)"
END SEQUENCE
RETURN
/* ====================================================================
* Challenge 14: Median approximation using percentile position
* Find the middle salary using ROW_NUMBER and COUNT.
* ==================================================================== */
STATIC PROCEDURE Challenge14_MedianApprox()
LOCAL aR
dbCloseAll()
BEGIN SEQUENCE
aR := five_SQL( ;
"WITH numbered AS (" + ;
"SELECT salary, " + ;
"ROW_NUMBER() OVER (ORDER BY salary) AS rn, " + ;
"COUNT(*) OVER () AS total " + ;
"FROM employees" + ;
") SELECT salary FROM numbered " + ;
"WHERE rn = total / 2 + 1" )
/* 12 employees sorted by salary, median position = 7th */
Assert( "14. Median salary (position-based)", Rows( aR ) >= 1 )
RECOVER
s_nTotal++ ; s_nFail++ ; ? " FAIL: 14. Median approx (exception)"
END SEQUENCE
RETURN
/* ====================================================================
* Challenge 15: Triple nested subquery + CTE + Window
* Most complex: CTE -> Window -> Subquery filter -> JOIN -> ORDER BY
* ==================================================================== */
STATIC PROCEDURE Challenge15_TripleNested()
LOCAL aR
dbCloseAll()
BEGIN SEQUENCE
aR := five_SQL( ;
"WITH order_stats AS (" + ;
" SELECT emp_id, SUM(amount) AS total, COUNT(*) AS cnt " + ;
" FROM orders GROUP BY emp_id" + ;
") " + ;
"SELECT e.name, e.dept, e.salary, s.total, " + ;
"RANK() OVER (ORDER BY s.total DESC) AS order_rank " + ;
"FROM employees e " + ;
"JOIN order_stats s ON e.id = s.emp_id " + ;
"WHERE e.salary > (SELECT AVG(salary) FROM employees) " + ;
"ORDER BY s.total DESC" )
/* Employees with above-avg salary who also have orders, ranked by order total */
Assert( "15. CTE+Window+Subquery+JOIN: complex analytics", Rows( aR ) >= 1 )
RECOVER
s_nTotal++ ; s_nFail++ ; ? " FAIL: 15. Triple nested (exception)"
END SEQUENCE
RETURN