원클릭으로
validation-author
Write validation/query lessons with SQL comparisons
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Write validation/query lessons with SQL comparisons
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Identify deprecated Cypher syntax in code files.
Create linear issues for the GRAC (GraphAcademy) team.
Periodically review course content for accuracy, relevance, and consistency. This includes checking for deprecated Cypher syntax.
Fact-check a single lesson against Neo4j documentation using the neo4j-docs MCP. Fixes inaccurate claims inline and appends a WHY report.
Review a single lesson for US English grammar, style, voice, and Neo4j terminology. Fixes issues inline and appends a WHY report.
Review a single lesson for pedagogical structure, lesson length, opening pattern, concept delivery, and scaffolding. Fixes issues inline and appends a WHY report.
| name | validation-author |
| description | Write validation/query lessons with SQL comparisons |
| allowed-tools | Read, Write, Edit, Glob, Grep |
Purpose: Write validation/query lessons that prove the value of what was built with SQL comparisons.
When to use: Workshop lesson requires proving the value of what learners just built.
Prerequisites:
This skill writes validation/query lessons that:
Do NOT write concept lessons, challenges, or practice lessons. This skill focuses ONLY on validation lessons.
Focus on graph databases and graph technologies.
Validation lesson approach:
When comparisons are helpful:
Keep it balanced:
Before writing anything, answer:
MUST READ:
- WORKSHOP-PLAN.md (for validation objectives)
- Previous challenge lesson (what was built)
- Source course lesson (for query examples)
- CONTENT_GUIDELINES.md (for SQL comparison patterns)
REFERENCE:
- modules/4-many-to-many/lessons/4-multi-hop-traversals/lesson.adoc
- SQL comparison examples throughout workshop
Introduction
├── References what was just built
└── States what will be validated
Query 1: Simple Business Question
├── Question in plain language
├── Cypher query with explanation
├── SQL comparison
└── Why graph is better for THIS query
Query 2: More Complex Question
├── Question in plain language
├── Cypher query with explanation
├── SQL comparison
└── Why graph is better for THIS query
Comparison Table
└── Metrics (Lines, JOINs, Performance, Readability)
Connection to Goal
└── How this pattern enables the final workshop goal
Summary
└── What was proven, forward reference
Start simple, build complexity:
[.slide.discrete]
== Introduction
You [what was just built in previous challenge]. Now you can answer business questions that would require complex JOINs in SQL.
In this lesson, you will query [what was built] and compare the Cypher queries to their SQL equivalents.
Example:
[.slide.discrete]
== Introduction
You created relationships between Order and Product nodes. Now you can traverse the complete Customer → Order → Product path with simple queries.
In this lesson, you will answer business questions using multi-hop traversals and compare them to the equivalent SQL queries.
[.slide]
== [Business Question as Header]
[Plain language business question]
[source,cypher]
.[Descriptive query title]
----
[Cypher query here]
----
[Explanation of what query does]
Click **Run** to see the results.
**SQL equivalent:**
[source,sql]
----
[SQL query here]
----
**Comparison:**
* [Specific advantage 1]
* [Specific advantage 2]
[.slide]
== Finding Customer Purchases
What products has a specific customer purchased?
[source,cypher]
.Products purchased by customer
----
MATCH (c:Customer {id: 'ALFKI'})
-[:PLACED]->(:Order)
-[:ORDERS]->(p:Product)
RETURN DISTINCT p.name AS product
ORDER BY product;
----
This query starts at a customer, traverses through their orders, and collects all products they've purchased.
Click **Run** to see all products purchased by customer ALFKI.
**SQL equivalent:**
[source,sql]
----
SELECT DISTINCT p.productName
FROM customers c
JOIN orders o ON c.customerId = o.customerId
JOIN order_details od ON o.orderId = od.orderId
JOIN products p ON od.productId = p.productId
WHERE c.customerId = 'ALFKI'
ORDER BY p.productName;
----
**Comparison:**
* **Cypher:** 2 relationship hops, reads like the question
* **SQL:** 3 JOIN operations scanning intermediate tables
* **Performance:** Graph traversal follows pointers in memory (cost scales with connections traversed); SQL JOIN repeatedly scans indexes and materializes result sets (cost scales with table sizes)
Side-by-side blocks:
[.slide]
== Query Comparison
**Cypher:**
[source,cypher]
----
MATCH (c:Customer)-[:PLACED]->(o:Order)
WHERE c.id = 'ALFKI'
RETURN count(o) AS orderCount;
----
**SQL:**
[source,sql]
----
SELECT COUNT(o.orderId) AS orderCount
FROM customers c
JOIN orders o ON c.customerId = o.customerId
WHERE c.customerId = 'ALFKI';
----
Two-column layout:
[.slide.col-2]
== Query Comparison
[.col]
====
**Cypher:**
[source,cypher]
----
MATCH (c:Customer)
-[:PLACED]->
(o:Order)
RETURN c.name, count(o)
----
====
[.col]
====
**SQL:**
[source,sql]
----
SELECT c.companyName,
COUNT(o.orderId)
FROM customers c
LEFT JOIN orders o
ON c.customerId = o.customerId
GROUP BY c.companyName
----
====
[.slide]
== Cypher vs SQL Comparison
[options="header"]
|===
| Metric | Cypher | SQL
| Lines of code | [N] | [M]
| JOIN operations | 0 | [N]
| Cost scales with | Connections traversed | Table sizes and number of JOINs
| Readability | Matches question structure | Multiple JOIN clauses
|===
**Key insight:** [Specific advantage for THIS query pattern]
Example:
[.slide]
== Multi-Hop Traversal Comparison
[options="header"]
|===
| Metric | Cypher | SQL
| Lines of code | 4 | 8
| JOIN operations | 0 | 3
| Tables accessed | 0 | 4 (customers, orders, order_details, products)
| Cost scales with | Connections traversed | Table sizes and JOIN count
| Readability | Path-based, visual | Multiple JOIN conditions
|===
**Key insight:** For connected data queries, graph traversal eliminates expensive JOIN operations that scan entire tables.
Performance explanation:
[.slide]
== Performance Advantage
**Relational approach:**
* Scans entire tables (or large index ranges) for JOIN conditions
* Creates intermediate result sets
* Cost grows with table sizes and number of JOINs
**Graph approach:**
* Follows direct relationship pointers in memory
* No repeated table scans or join materialization
* Cost grows with how many connections you traverse, not total graph size
For highly connected data, graph traversal stays predictable as data volume increases because it only touches the paths it follows.
Simplicity explanation:
[.slide]
== Simplicity Advantage
**Graph queries read like the questions you're asking:**
* "What products did this customer buy?" →
`(Customer)-[:PLACED]->(:Order)-[:ORDERS]->(Product)`
**SQL requires understanding schema implementation:**
* Which tables to JOIN
* Which foreign keys to match
* ORDER of JOIN operations
❌ Vague sales claims:
Graphs are powerful and provide amazing performance.
✅ Concrete technical facts:
Graph traversal follows pointers in memory; cost scales with connections traversed. SQL JOIN repeatedly scans indexes and materializes result sets; cost scales with table sizes and number of joins.
❌ Generic statements:
Cypher is easier to read and write.
✅ Specific comparison:
Cypher: 4 lines, 0 JOINs. SQL: 8 lines, 3 JOINs scanning 4 tables.
[.slide]
== Building Toward [Workshop Goal]
[Current capability statement]
[How this pattern extends for final goal]
[What comes next to complete the path]
Example:
[.slide]
== Building Toward Recommendations
You can now traverse Customer → Order → Product to find what each customer has purchased.
To build a recommendation query, you'll extend this pattern: find customers who bought similar products, then recommend products they haven't purchased yet.
This multi-hop traversal pattern is the foundation for collaborative filtering.
[.summary]
== Summary
In this lesson, you validated [what was built] by answering business questions:
* **[Query 1]** - [What it showed]
* **[Query 2]** - [What it showed]
* **[Query 3]** - [What it showed]
**Cypher vs SQL:** [N] lines vs [M] lines, [X] JOINs eliminated
In the next lesson, you will [what comes next].
Example:
[.summary]
== Summary
In this lesson, you validated the Customer → Order → Product path by answering business questions:
* **Customer purchases** - Found all products a customer bought
* **Popular products** - Identified most frequently ordered items
* **Order totals** - Calculated spending per customer
**Cypher vs SQL:** 4 lines vs 8 lines, 3 JOINs eliminated; graph cost scales with connections traversed, SQL with table sizes and joins
In the next lesson, you will learn how to find similar customers using bidirectional traversals.
// <1> not // (1)Every Cypher query:
Every SQL query:
Before completing:
Test each Cypher query:
Verify SQL equivalents:
Check metrics:
See these real files:
modules/4-many-to-many/lessons/4-multi-hop-traversals/lesson.adoc
modules/3-modeling-relationships/lessons/3-traversing-relationships/lesson.adoc
modules/5-final-review/lessons/1-recommendation-query/lesson.adoc
4-multi-hop-traversals/lesson.adoc:
Key patterns:
.TitleCypher:
MATCH (c:Customer {id: 'ALFKI'})-[:PLACED]->(o:Order)
RETURN c.name, o.id, o.date;
SQL:
SELECT c.companyName, o.orderId, o.orderDate
FROM customers c
JOIN orders o ON c.customerId = o.customerId
WHERE c.customerId = 'ALFKI';
Comparison: 1 line vs 4 lines, 1 JOIN
Cypher:
MATCH (c:Customer {id: 'ALFKI'})
-[:PLACED]->(:Order)
-[:ORDERS]->(p:Product)
RETURN DISTINCT p.name;
SQL:
SELECT DISTINCT p.productName
FROM customers c
JOIN orders o ON c.customerId = o.customerId
JOIN order_details od ON o.orderId = od.orderId
JOIN products p ON od.productId = p.productId
WHERE c.customerId = 'ALFKI';
Comparison: 4 lines vs 7 lines, 3 JOINs, 4 tables
Cypher:
MATCH (c1:Customer {id: 'ALFKI'})
-[:PLACED]->(:Order)
-[:ORDERS]->(p:Product)
<-[:ORDERS]-(:Order)
<-[:PLACED]-(c2:Customer)
WHERE c1 <> c2
RETURN c2.name, count(DISTINCT p) AS sharedProducts;
SQL:
SELECT c2.companyName, COUNT(DISTINCT p2.productId)
FROM customers c1
JOIN orders o1 ON c1.customerId = o1.customerId
JOIN order_details od1 ON o1.orderId = od1.orderId
JOIN products p1 ON od1.productId = p1.productId
JOIN order_details od2 ON p1.productId = od2.productId
JOIN orders o2 ON od2.orderId = o2.orderId
JOIN customers c2 ON o2.customerId = c2.customerId
WHERE c1.customerId = 'ALFKI' AND c1.customerId <> c2.customerId
GROUP BY c2.companyName;
Comparison: 7 lines vs 11 lines, 6 JOINs; each extra JOIN in SQL adds more index scans and materialization—cost grows quickly with depth
Before marking validation lesson complete, verify:
lesson.adoc exists:type: lesson, :order: X, :duration: 3-5