03_Projects_Query

PDF-Dokumente

DateinameAktion
PDFUebung_Taxi.pdfÖffnen

Lernmaterialien

Alles löschen

MATCH (n) DETACH DELETE n;

Projekt 01 – Bibliothek

1) Titel

Bibliothek: Member – Book

2) Kurzbeschreibung

Mitglieder suchen nach Büchern und leihen Bücher aus. So kann man Such- und Ausleihverhalten vergleichen.

3) Nodes & Relations

  • Nodes: :Member(memberId, name, email), :Book(bookId, title, genre, year)

  • Relations:

    • (:Member)-[:SEARCHED_FOR {at, query}]->(:Book)

    • (:Member)-[:BORROWED {at, dueDate}]->(:Book)

4) Befüllen (Cypher)

CREATE CONSTRAINT p01_member_id_unique IF NOT EXISTS
FOR (m:Member) REQUIRE m.memberId IS UNIQUE;

CREATE CONSTRAINT p01_book_id_unique IF NOT EXISTS
FOR (b:Book) REQUIRE b.bookId IS UNIQUE;

MERGE (m1:Member {memberId:"M001"}) SET m1.name="Anna", m1.email="anna@example.com";
MERGE (m2:Member {memberId:"M002"}) SET m2.name="Ben",  m2.email="ben@example.com";

MERGE (b1:Book {bookId:"B100"}) SET b1.title="1984", b1.genre="Fiction", b1.year=1949;
MERGE (b2:Book {bookId:"B200"}) SET b2.title="Dune", b2.genre="SciFi", b2.year=1965;
MERGE (b3:Book {bookId:"B300"}) SET b3.title="Sapiens", b3.genre="Nonfiction", b3.year=2011;

MATCH (m1:Member {memberId:"M001"}), (b2:Book {bookId:"B200"})
MERGE (m1)-[:SEARCHED_FOR {at: datetime("2026-01-10T10:15:00"), query:"best scifi"}]->(b2);

MATCH (m1:Member {memberId:"M001"}), (b2:Book {bookId:"B200"})
MERGE (m1)-[:BORROWED {at: datetime("2026-01-10T10:45:00"), dueDate: date("2026-01-24")}]->(b2);

MATCH (m2:Member {memberId:"M002"}), (b3:Book {bookId:"B300"})
MERGE (m2)-[:SEARCHED_FOR {at: datetime("2026-01-11T09:05:00"), query:"history bestseller"}]->(b3);

5) Abfragen (ohne Lösung)

  • Liste alle Mitglieder, die mindestens ein Buch ausgeliehen haben.

  • Zeige die Top-Bücher nach Anzahl SEARCHED_FOR.

  • Zeige Bücher, die gesucht aber nie ausgeliehen wurden.

  • Zeige Mitglieder, die alle Bücher ausgeliehen haben.

  • “Market Basket”: Mitglieder, die Buch X ausgeliehen haben, liehen auch welches Buch?


Projekt 02 – Streaming

1) Titel

Streaming: User – Movie

2) Kurzbeschreibung

Nutzer suchen Filme und schauen sie. Beziehungen speichern Suchanfrage, Fortschritt und Bewertung.

3) Nodes & Relations

  • Nodes: :User(userId, name, email), :Movie(movieId, title, genre, year)

  • Relations:

    • (:User)-[:SEARCHED_FOR {at, query}]->(:Movie)

    • (:User)-[:WATCHED {at, progressPct, rating}]->(:Movie)

4) Befüllen (Cypher)

CREATE CONSTRAINT p02_user_id_unique IF NOT EXISTS
FOR (u:User) REQUIRE u.userId IS UNIQUE;

CREATE CONSTRAINT p02_movie_id_unique IF NOT EXISTS
FOR (m:Movie) REQUIRE m.movieId IS UNIQUE;

MERGE (u1:User {userId:"U001"}) SET u1.name="Clara", u1.email="clara@example.com";
MERGE (u2:User {userId:"U002"}) SET u2.name="David", u2.email="david@example.com";

MERGE (m1:Movie {movieId:"MV100"}) SET m1.title="Inception", m1.genre="SciFi", m1.year=2010;
MERGE (m2:Movie {movieId:"MV200"}) SET m2.title="Interstellar", m2.genre="SciFi", m2.year=2014;
MERGE (m3:Movie {movieId:"MV300"}) SET m3.title="La La Land", m3.genre="Drama", m3.year=2016;

MATCH (u1:User {userId:"U001"}), (m2:Movie {movieId:"MV200"})
MERGE (u1)-[:SEARCHED_FOR {at: datetime("2026-01-12T18:15:00"), query:"space movie"}]->(m2);

MATCH (u1:User {userId:"U001"}), (m2:Movie {movieId:"MV200"})
MERGE (u1)-[:WATCHED {at: datetime("2026-01-12T20:00:00"), progressPct: 100, rating: 5}]->(m2);

MATCH (u2:User {userId:"U002"}), (m3:Movie {movieId:"MV300"})
MERGE (u2)-[:SEARCHED_FOR {at: datetime("2026-01-13T21:05:00"), query:"musical romance"}]->(m3);

5) Abfragen (ohne Lösung)

  • Top-User nach Anzahl WATCHED.

  • Filme, die gesucht aber nicht geschaut wurden.

  • Durchschnittliche Bewertung pro Film.

  • User, die alle Filme geschaut haben.

  • Empfehlungen: “Wer Film A geschaut hat, schaute auch …”.


Projekt 03 – Flugportal

1) Titel

Reisen: Traveler – Flight

2) Kurzbeschreibung

Reisende suchen Flüge und buchen einen Flug. Buchungsdaten (Preis, Sitzplatz) liegen auf der Beziehung.

3) Nodes & Relations

  • Nodes: :Traveler(travelerId, name, email), :Flight(flightId, route, departure, airline)

  • Relations:

    • (:Traveler)-[:SEARCHED_FOR {at, query}]->(:Flight)

    • (:Traveler)-[:BOOKED {at, bookingId, seat, price, currency}]->(:Flight)

4) Befüllen (Cypher)

CREATE CONSTRAINT p03_traveler_id_unique IF NOT EXISTS
FOR (t:Traveler) REQUIRE t.travelerId IS UNIQUE;

CREATE CONSTRAINT p03_flight_id_unique IF NOT EXISTS
FOR (f:Flight) REQUIRE f.flightId IS UNIQUE;

MERGE (t1:Traveler {travelerId:"T001"}) SET t1.name="Eva", t1.email="eva@example.com";
MERGE (t2:Traveler {travelerId:"T002"}) SET t2.name="Felix", t2.email="felix@example.com";

MERGE (f1:Flight {flightId:"F100"}) SET f1.route="VIE→CDG", f1.departure=date("2026-02-01"), f1.airline="AirX";
MERGE (f2:Flight {flightId:"F200"}) SET f2.route="VIE→LHR", f2.departure=date("2026-02-05"), f2.airline="SkyJet";
MERGE (f3:Flight {flightId:"F300"}) SET f3.route="VIE→FRA", f3.departure=date("2026-02-10"), f3.airline="EuroFly";

MATCH (t1:Traveler {travelerId:"T001"}), (f2:Flight {flightId:"F200"})
MERGE (t1)-[:SEARCHED_FOR {at: datetime("2026-01-14T08:10:00"), query:"cheap london flight"}]->(f2);

MATCH (t1:Traveler {travelerId:"T001"}), (f2:Flight {flightId:"F200"})
MERGE (t1)-[:BOOKED {at: datetime("2026-01-14T08:20:00"), bookingId:"BKG-9001", seat:"12A", price:129.0, currency:"EUR"}]->(f2);

MATCH (t2:Traveler {travelerId:"T002"}), (f1:Flight {flightId:"F100"})
MERGE (t2)-[:SEARCHED_FOR {at: datetime("2026-01-14T09:05:00"), query:"paris weekend"}]->(f1);

5) Abfragen (ohne Lösung)

  • Reisende, die mindestens einen Flug gebucht haben.

  • Top-Routen nach Anzahl Buchungen.

  • Flüge gesucht aber nicht gebucht.

  • Reisende, die alle Flüge gebucht haben.

  • Durchschnittspreis pro Airline (aus BOOKED-Properties).


Projekt 04 – Jobportal

1) Titel

Jobs: Candidate – JobPosting

2) Kurzbeschreibung

Kandidaten suchen Stellenanzeigen und bewerben sich. Bewerbungseigenschaften werden als Relationship-Properties gespeichert.

3) Nodes & Relations

  • Nodes: :Candidate(candidateId, name, email), :JobPosting(jobId, title, city, level)

  • Relations:

    • (:Candidate)-[:SEARCHED_FOR {at, query}]->(:JobPosting)

    • (:Candidate)-[:APPLIED_TO {at, applicationId, cvVersion}]->(:JobPosting)

4) Befüllen (Cypher)

CREATE CONSTRAINT p04_candidate_id_unique IF NOT EXISTS
FOR (c:Candidate) REQUIRE c.candidateId IS UNIQUE;

CREATE CONSTRAINT p04_job_id_unique IF NOT EXISTS
FOR (j:JobPosting) REQUIRE j.jobId IS UNIQUE;

MERGE (c1:Candidate {candidateId:"CAND1"}) SET c1.name="Gina", c1.email="gina@example.com";
MERGE (c2:Candidate {candidateId:"CAND2"}) SET c2.name="Hannes", c2.email="hannes@example.com";

MERGE (j1:JobPosting {jobId:"J100"}) SET j1.title="Junior DBA", j1.city="Vienna", j1.level="Junior";
MERGE (j2:JobPosting {jobId:"J200"}) SET j2.title="Backend Dev", j2.city="Graz", j2.level="Mid";
MERGE (j3:JobPosting {jobId:"J300"}) SET j3.title="Data Analyst", j3.city="Linz", j3.level="Junior";

MATCH (c1:Candidate {candidateId:"CAND1"}), (j1:JobPosting {jobId:"J100"})
MERGE (c1)-[:SEARCHED_FOR {at: datetime("2026-01-15T10:15:00"), query:"oracle junior"}]->(j1);

MATCH (c1:Candidate {candidateId:"CAND1"}), (j1:JobPosting {jobId:"J100"})
MERGE (c1)-[:APPLIED_TO {at: datetime("2026-01-15T10:40:00"), applicationId:"APP-7001", cvVersion:"v2"}]->(j1);

MATCH (c2:Candidate {candidateId:"CAND2"}), (j2:JobPosting {jobId:"J200"})
MERGE (c2)-[:SEARCHED_FOR {at: datetime("2026-01-15T11:05:00"), query:"java graz"}]->(j2);

5) Abfragen (ohne Lösung)

  • Kandidaten, die sich beworben haben.

  • Top-Jobs nach Anzahl Bewerbungen.

  • Jobs gesucht aber ohne Bewerbung.

  • Kandidaten, die alle JobPostings beworben haben.

  • Kandidaten, die in einer bestimmten Stadt gesucht haben.


Projekt 05 – Immobilienportal

1) Titel

Immobilien: Client – Listing

2) Kurzbeschreibung

Kunden suchen Immobilien und vereinbaren Besichtigungen. So lassen sich Nachfrage und Besichtigungen vergleichen.

3) Nodes & Relations

  • Nodes: :Client(clientId, name, email), :Listing(listingId, type, city, price)

  • Relations:

    • (:Client)-[:SEARCHED_FOR {at, query}]->(:Listing)

    • (:Client)-[:SCHEDULED_VIEWING {at, viewingAt}]->(:Listing)

4) Befüllen (Cypher)

CREATE CONSTRAINT p05_client_id_unique IF NOT EXISTS
FOR (c:Client) REQUIRE c.clientId IS UNIQUE;

CREATE CONSTRAINT p05_listing_id_unique IF NOT EXISTS
FOR (l:Listing) REQUIRE l.listingId IS UNIQUE;

MERGE (c1:Client {clientId:"CL001"}) SET c1.name="Iris", c1.email="iris@example.com";
MERGE (c2:Client {clientId:"CL002"}) SET c2.name="Jonas", c2.email="jonas@example.com";

MERGE (l1:Listing {listingId:"L100"}) SET l1.type="Apartment", l1.city="Vienna", l1.price=450000;
MERGE (l2:Listing {listingId:"L200"}) SET l2.type="House", l2.city="Graz", l2.price=520000;
MERGE (l3:Listing {listingId:"L300"}) SET l3.type="Studio", l3.city="Vienna", l3.price=250000;

MATCH (c1:Client {clientId:"CL001"}), (l3:Listing {listingId:"L300"})
MERGE (c1)-[:SEARCHED_FOR {at: datetime("2026-01-16T12:10:00"), query:"vienna studio cheap"}]->(l3);

MATCH (c1:Client {clientId:"CL001"}), (l3:Listing {listingId:"L300"})
MERGE (c1)-[:SCHEDULED_VIEWING {at: datetime("2026-01-16T12:30:00"), viewingAt: datetime("2026-01-18T15:00:00")}]->(l3);

MATCH (c2:Client {clientId:"CL002"}), (l2:Listing {listingId:"L200"})
MERGE (c2)-[:SEARCHED_FOR {at: datetime("2026-01-16T09:05:00"), query:"house graz garden"}]->(l2);

5) Abfragen (ohne Lösung)

  • Kunden mit mindestens einer Besichtigung.

  • Top-Listings nach Besichtigungen.

  • Listings gesucht aber ohne Besichtigung.

  • Kunden, die alle Listings besichtigt haben.

  • Durchschnittspreis der Listings, die besichtigt wurden.


Projekt 06 – Restaurant-Reservierung

1) Titel

Gastronomie: Guest – Restaurant

2) Kurzbeschreibung

Gäste suchen Restaurants und reservieren Tische. Reservierungsdaten (Zeit, Gruppengröße) liegen auf der Beziehung.

3) Nodes & Relations

  • Nodes: :Guest(guestId, name, email), :Restaurant(restaurantId, name, city, cuisine)

  • Relations:

    • (:Guest)-[:SEARCHED_FOR {at, query}]->(:Restaurant)

    • (:Guest)-[:RESERVED {at, reservationAt, partySize, reservationId}]->(:Restaurant)

4) Befüllen (Cypher)

CREATE CONSTRAINT p06_guest_id_unique IF NOT EXISTS
FOR (g:Guest) REQUIRE g.guestId IS UNIQUE;

CREATE CONSTRAINT p06_restaurant_id_unique IF NOT EXISTS
FOR (r:Restaurant) REQUIRE r.restaurantId IS UNIQUE;

MERGE (g1:Guest {guestId:"G001"}) SET g1.name="Kathi", g1.email="kathi@example.com";
MERGE (g2:Guest {guestId:"G002"}) SET g2.name="Lukas", g2.email="lukas@example.com";

MERGE (r1:Restaurant {restaurantId:"R100"}) SET r1.name="Trattoria Uno", r1.city="Vienna", r1.cuisine="Italian";
MERGE (r2:Restaurant {restaurantId:"R200"}) SET r2.name="Sushi Zen", r2.city="Vienna", r2.cuisine="Japanese";
MERGE (r3:Restaurant {restaurantId:"R300"}) SET r3.name="Steak House", r3.city="Graz", r3.cuisine="Steak";

MATCH (g1:Guest {guestId:"G001"}), (r2:Restaurant {restaurantId:"R200"})
MERGE (g1)-[:SEARCHED_FOR {at: datetime("2026-01-17T18:15:00"), query:"best sushi vienna"}]->(r2);

MATCH (g1:Guest {guestId:"G001"}), (r2:Restaurant {restaurantId:"R200"})
MERGE (g1)-[:RESERVED {at: datetime("2026-01-17T18:25:00"), reservationAt: datetime("2026-01-19T19:00:00"), partySize:2, reservationId:"RES-8101"}]->(r2);

MATCH (g2:Guest {guestId:"G002"}), (r3:Restaurant {restaurantId:"R300"})
MERGE (g2)-[:SEARCHED_FOR {at: datetime("2026-01-17T20:05:00"), query:"steak graz"}]->(r3);

5) Abfragen (ohne Lösung)

  • Top-Gäste nach Anzahl Reservierungen.

  • Restaurants gesucht aber nicht reserviert.

  • Reservierungen in einer bestimmten Stadt.

  • Gäste, die alle Restaurants reserviert haben.

  • Durchschnittliche PartySize pro Restaurant.


Projekt 07 – Musikshop

1) Titel

Musik: Listener – Album

2) Kurzbeschreibung

Hörer suchen Alben und kaufen sie. Auf der Kaufbeziehung stehen Bestellung und Preis zum Kaufzeitpunkt.

3) Nodes & Relations

  • Nodes: :Listener(listenerId, name, email), :Album(albumId, title, genre, price)

  • Relations:

    • (:Listener)-[:SEARCHED_FOR {at, query}]->(:Album)

    • (:Listener)-[:PURCHASED {at, orderId, priceAtPurchase, currency}]->(:Album)

4) Befüllen (Cypher)

CREATE CONSTRAINT p07_listener_id_unique IF NOT EXISTS
FOR (l:Listener) REQUIRE l.listenerId IS UNIQUE;

CREATE CONSTRAINT p07_album_id_unique IF NOT EXISTS
FOR (a:Album) REQUIRE a.albumId IS UNIQUE;

MERGE (l1:Listener {listenerId:"LI01"}) SET l1.name="Mara", l1.email="mara@example.com";
MERGE (l2:Listener {listenerId:"LI02"}) SET l2.name="Nico", l2.email="nico@example.com";

MERGE (a1:Album {albumId:"A100"}) SET a1.title="Chill Beats", a1.genre="LoFi", a1.price=9.99;
MERGE (a2:Album {albumId:"A200"}) SET a2.title="Rock Legends", a2.genre="Rock", a2.price=12.99;
MERGE (a3:Album {albumId:"A300"}) SET a3.title="Classical Moods", a3.genre="Classical", a3.price=7.99;

MATCH (l1:Listener {listenerId:"LI01"}), (a1:Album {albumId:"A100"})
MERGE (l1)-[:SEARCHED_FOR {at: datetime("2026-01-18T09:15:00"), query:"lofi study"}]->(a1);

MATCH (l1:Listener {listenerId:"LI01"}), (a1:Album {albumId:"A100"})
MERGE (l1)-[:PURCHASED {at: datetime("2026-01-18T09:25:00"), orderId:"O-5001", priceAtPurchase:9.99, currency:"EUR"}]->(a1);

MATCH (l2:Listener {listenerId:"LI02"}), (a2:Album {albumId:"A200"})
MERGE (l2)-[:SEARCHED_FOR {at: datetime("2026-01-18T10:05:00"), query:"best rock compilation"}]->(a2);

5) Abfragen (ohne Lösung)

  • Top-Listener nach Anzahl Käufe.

  • Alben gesucht aber nicht gekauft.

  • Umsatz (Summe priceAtPurchase) pro Genre.

  • Listener, die alle Alben gekauft haben.

  • “Wer Album A gekauft hat, kaufte auch …”.


Projekt 08 – Arzttermin

1) Titel

Gesundheit: Patient – Doctor

2) Kurzbeschreibung

Patienten suchen Ärzte und buchen Termine. Terminzeit und Grund liegen auf der BOOKED-Beziehung.

3) Nodes & Relations

  • Nodes: :Patient(patientId, name, email), :Doctor(doctorId, name, specialty, city)

  • Relations:

    • (:Patient)-[:SEARCHED_FOR {at, query}]->(:Doctor)

    • (:Patient)-[:BOOKED {at, appointmentAt, reason}]->(:Doctor)

4) Befüllen (Cypher)

CREATE CONSTRAINT p08_patient_id_unique IF NOT EXISTS
FOR (p:Patient) REQUIRE p.patientId IS UNIQUE;

CREATE CONSTRAINT p08_doctor_id_unique IF NOT EXISTS
FOR (d:Doctor) REQUIRE d.doctorId IS UNIQUE;

MERGE (p1:Patient {patientId:"PA01"}) SET p1.name="Olivia", p1.email="olivia@example.com";
MERGE (p2:Patient {patientId:"PA02"}) SET p2.name="Paul",   p2.email="paul@example.com";

MERGE (d1:Doctor {doctorId:"DR10"}) SET d1.name="Dr. Weber", d1.specialty="Dermatology", d1.city="Vienna";
MERGE (d2:Doctor {doctorId:"DR20"}) SET d2.name="Dr. Huber", d2.specialty="Dentistry",   d2.city="Vienna";
MERGE (d3:Doctor {doctorId:"DR30"}) SET d3.name="Dr. Moser", d3.specialty="Cardiology",  d3.city="Graz";

MATCH (p1:Patient {patientId:"PA01"}), (d2:Doctor {doctorId:"DR20"})
MERGE (p1)-[:SEARCHED_FOR {at: datetime("2026-01-19T11:15:00"), query:"dentist vienna"}]->(d2);

MATCH (p1:Patient {patientId:"PA01"}), (d2:Doctor {doctorId:"DR20"})
MERGE (p1)-[:BOOKED {at: datetime("2026-01-19T11:35:00"), appointmentAt: datetime("2026-01-22T14:00:00"), reason:"checkup"}]->(d2);

MATCH (p2:Patient {patientId:"PA02"}), (d1:Doctor {doctorId:"DR10"})
MERGE (p2)-[:SEARCHED_FOR {at: datetime("2026-01-19T09:05:00"), query:"skin doctor"}]->(d1);

5) Abfragen (ohne Lösung)

  • Patienten mit mindestens einem Termin.

  • Top-Ärzte nach Anzahl BOOKED.

  • Ärzte gesucht aber nicht gebucht.

  • Patienten, die alle Ärzte gebucht haben.

  • Termine in einer bestimmten Stadt / Fachgebiet.


Projekt 09 – Hochschule

1) Titel

Uni: Student – Course

2) Kurzbeschreibung

Studierende suchen Kurse und schreiben sich ein. Einschreibung speichert Semester und Zeitpunkt.

3) Nodes & Relations

  • Nodes: :Student(studentId, name, email), :Course(courseId, title, ects, level)

  • Relations:

    • (:Student)-[:SEARCHED_FOR {at, query}]->(:Course)

    • (:Student)-[:ENROLLED {at, semester}]->(:Course)

4) Befüllen (Cypher)

CREATE CONSTRAINT p09_student_id_unique IF NOT EXISTS
FOR (s:Student) REQUIRE s.studentId IS UNIQUE;

CREATE CONSTRAINT p09_course_id_unique IF NOT EXISTS
FOR (c:Course) REQUIRE c.courseId IS UNIQUE;

MERGE (s1:Student {studentId:"S001"}) SET s1.name="Quinn", s1.email="quinn@example.com";
MERGE (s2:Student {studentId:"S002"}) SET s2.name="Rita",  s2.email="rita@example.com";

MERGE (c1:Course {courseId:"DB101"}) SET c1.title="Databases", c1.ects=6, c1.level="Beginner";
MERGE (c2:Course {courseId:"DB202"}) SET c2.title="Advanced SQL", c2.ects=5, c2.level="Intermediate";
MERGE (c3:Course {courseId:"GR301"}) SET c3.title="Graph Databases", c3.ects=5, c3.level="Advanced";

MATCH (s1:Student {studentId:"S001"}), (c3:Course {courseId:"GR301"})
MERGE (s1)-[:SEARCHED_FOR {at: datetime("2026-01-20T10:15:00"), query:"neo4j course"}]->(c3);

MATCH (s1:Student {studentId:"S001"}), (c3:Course {courseId:"GR301"})
MERGE (s1)-[:ENROLLED {at: datetime("2026-01-20T10:45:00"), semester:"2026S"}]->(c3);

MATCH (s2:Student {studentId:"S002"}), (c1:Course {courseId:"DB101"})
MERGE (s2)-[:SEARCHED_FOR {at: datetime("2026-01-20T09:05:00"), query:"database basics"}]->(c1);

5) Abfragen (ohne Lösung)

  • Top-Studierende nach Anzahl ENROLLED.

  • Kurse gesucht aber nicht belegt.

  • Studierende, die alle Kurse belegt haben.

  • Kurse nach Level sortiert mit Anzahl Einschreibungen.

  • “Wer Kurs A belegt, belegt auch …”.


Projekt 10 – Events/Tickets

1) Titel

Events: Attendee – Event

2) Kurzbeschreibung

Besucher suchen Events und kaufen Tickets. Ticketdaten stehen auf BOUGHT_TICKET.

3) Nodes & Relations

  • Nodes: :Attendee(attendeeId, name, email), :Event(eventId, title, city, date)

  • Relations:

    • (:Attendee)-[:SEARCHED_FOR {at, query}]->(:Event)

    • (:Attendee)-[:BOUGHT_TICKET {at, ticketId, priceAtPurchase, currency}]->(:Event)

4) Befüllen (Cypher)

CREATE CONSTRAINT p10_attendee_id_unique IF NOT EXISTS
FOR (a:Attendee) REQUIRE a.attendeeId IS UNIQUE;

CREATE CONSTRAINT p10_event_id_unique IF NOT EXISTS
FOR (e:Event) REQUIRE e.eventId IS UNIQUE;

MERGE (a1:Attendee {attendeeId:"AT01"}) SET a1.name="Sara", a1.email="sara@example.com";
MERGE (a2:Attendee {attendeeId:"AT02"}) SET a2.name="Tom",  a2.email="tom@example.com";

MERGE (e1:Event {eventId:"E100"}) SET e1.title="Jazz Night", e1.city="Vienna", e1.date=date("2026-02-10");
MERGE (e2:Event {eventId:"E200"}) SET e2.title="Tech Meetup", e2.city="Graz", e2.date=date("2026-02-12");
MERGE (e3:Event {eventId:"E300"}) SET e3.title="Art Expo", e3.city="Vienna", e3.date=date("2026-02-15");

MATCH (a1:Attendee {attendeeId:"AT01"}), (e1:Event {eventId:"E100"})
MERGE (a1)-[:SEARCHED_FOR {at: datetime("2026-01-21T12:15:00"), query:"jazz vienna"}]->(e1);

MATCH (a1:Attendee {attendeeId:"AT01"}), (e1:Event {eventId:"E100"})
MERGE (a1)-[:BOUGHT_TICKET {at: datetime("2026-01-21T12:20:00"), ticketId:"TCK-1001", priceAtPurchase:25.0, currency:"EUR"}]->(e1);

MATCH (a2:Attendee {attendeeId:"AT02"}), (e2:Event {eventId:"E200"})
MERGE (a2)-[:SEARCHED_FOR {at: datetime("2026-01-21T13:05:00"), query:"tech meetup graz"}]->(e2);

5) Abfragen (ohne Lösung)

  • Top-Events nach Ticketkäufen.

  • Besucher, die Tickets gekauft haben.

  • Events gesucht aber ohne Ticketkauf.

  • Besucher, die alle Events besucht/gekauft haben.

  • Umsatz pro Stadt.


Projekt 11 – Autovermietung

1) Titel

Car Rental: Renter – Car

2) Kurzbeschreibung

Kunden suchen Autos und mieten sie. Mietzeitraum und Preis sind Properties.

3) Nodes & Relations

  • Nodes: :Renter(renterId, name, email), :Car(carId, model, class, dailyRate)

  • Relations:

    • (:Renter)-[:SEARCHED_FOR {at, query}]->(:Car)

    • (:Renter)-[:RENTED {at, bookingId, from, to, price, currency}]->(:Car)

4) Befüllen (Cypher)

CREATE CONSTRAINT p11_renter_id_unique IF NOT EXISTS
FOR (r:Renter) REQUIRE r.renterId IS UNIQUE;

CREATE CONSTRAINT p11_car_id_unique IF NOT EXISTS
FOR (c:Car) REQUIRE c.carId IS UNIQUE;

MERGE (r1:Renter {renterId:"RE01"}) SET r1.name="Ute", r1.email="ute@example.com";
MERGE (r2:Renter {renterId:"RE02"}) SET r2.name="Viktor", r2.email="viktor@example.com";

MERGE (c1:Car {carId:"CAR1"}) SET c1.model="VW Golf", c1.class="Compact", c1.dailyRate=45.0;
MERGE (c2:Car {carId:"CAR2"}) SET c2.model="BMW 3",   c2.class="Sedan",   c2.dailyRate=79.0;
MERGE (c3:Car {carId:"CAR3"}) SET c3.model="Skoda Fabia", c3.class="Compact", c3.dailyRate=39.0;

MATCH (r1:Renter {renterId:"RE01"}), (c3:Car {carId:"CAR3"})
MERGE (r1)-[:SEARCHED_FOR {at: datetime("2026-01-22T09:15:00"), query:"cheap compact car"}]->(c3);

MATCH (r1:Renter {renterId:"RE01"}), (c3:Car {carId:"CAR3"})
MERGE (r1)-[:RENTED {at: datetime("2026-01-22T09:30:00"), bookingId:"RENT-3001", from: date("2026-02-01"), to: date("2026-02-03"), price:78.0, currency:"EUR"}]->(c3);

MATCH (r2:Renter {renterId:"RE02"}), (c2:Car {carId:"CAR2"})
MERGE (r2)-[:SEARCHED_FOR {at: datetime("2026-01-22T10:05:00"), query:"sedan weekend"}]->(c2);

5) Abfragen (ohne Lösung)

  • Top-Kunden nach Anzahl RENTED.

  • Autos gesucht aber nicht gemietet.

  • Umsatz (Summe price) pro Fahrzeugklasse.

  • Kunden, die alle Autos gemietet haben.

  • Mietdauer (to-from) im Durchschnitt pro Auto.


Projekt 12 – Hotel

1) Titel

Hotel: Guest – Room

2) Kurzbeschreibung

Gäste suchen Zimmer und buchen sie. Buchung speichert Zeitraum und Preis.

3) Nodes & Relations

  • Nodes: :HotelGuest(guestId, name, email), :Room(roomId, type, city, nightRate)

  • Relations:

    • (:HotelGuest)-[:SEARCHED_FOR {at, query}]->(:Room)

    • (:HotelGuest)-[:BOOKED {at, reservationId, checkIn, checkOut, price, currency}]->(:Room)

4) Befüllen (Cypher)

CREATE CONSTRAINT p12_guest_id_unique IF NOT EXISTS
FOR (g:HotelGuest) REQUIRE g.guestId IS UNIQUE;

CREATE CONSTRAINT p12_room_id_unique IF NOT EXISTS
FOR (r:Room) REQUIRE r.roomId IS UNIQUE;

MERGE (g1:HotelGuest {guestId:"HG01"}) SET g1.name="Wanda", g1.email="wanda@example.com";
MERGE (g2:HotelGuest {guestId:"HG02"}) SET g2.name="Xaver", g2.email="xaver@example.com";

MERGE (r1:Room {roomId:"RM10"}) SET r1.type="Single", r1.city="Vienna", r1.nightRate=89.0;
MERGE (r2:Room {roomId:"RM20"}) SET r2.type="Double", r2.city="Vienna", r2.nightRate=129.0;
MERGE (r3:Room {roomId:"RM30"}) SET r3.type="Suite",  r3.city="Graz",   r3.nightRate=199.0;

MATCH (g1:HotelGuest {guestId:"HG01"}), (r2:Room {roomId:"RM20"})
MERGE (g1)-[:SEARCHED_FOR {at: datetime("2026-01-23T11:15:00"), query:"double room vienna"}]->(r2);

MATCH (g1:HotelGuest {guestId:"HG01"}), (r2:Room {roomId:"RM20"})
MERGE (g1)-[:BOOKED {at: datetime("2026-01-23T11:40:00"), reservationId:"H-9001", checkIn: date("2026-02-10"), checkOut: date("2026-02-12"), price:258.0, currency:"EUR"}]->(r2);

MATCH (g2:HotelGuest {guestId:"HG02"}), (r3:Room {roomId:"RM30"})
MERGE (g2)-[:SEARCHED_FOR {at: datetime("2026-01-23T09:05:00"), query:"suite graz"}]->(r3);

5) Abfragen (ohne Lösung)

  • Top-Gäste nach Anzahl BOOKED.

  • Zimmer gesucht aber nicht gebucht.

  • Umsatz pro Stadt.

  • Gäste, die alle Zimmer gebucht haben.

  • Durchschnittliche Aufenthaltsdauer (checkOut-checkIn).


Projekt 13 – Versicherung

1) Titel

Versicherung: InsCustomer – Policy

2) Kurzbeschreibung

Kunden suchen Policen und schließen Verträge ab. Vertragsdaten liegen auf PURCHASED.

3) Nodes & Relations

  • Nodes: :InsCustomer(customerId, name, email), :Policy(policyId, type, provider, monthlyPremium)

  • Relations:

    • (:InsCustomer)-[:SEARCHED_FOR {at, query}]->(:Policy)

    • (:InsCustomer)-[:PURCHASED {at, contractId, startDate, premium, currency}]->(:Policy)

4) Befüllen (Cypher)

CREATE CONSTRAINT p13_customer_id_unique IF NOT EXISTS
FOR (c:InsCustomer) REQUIRE c.customerId IS UNIQUE;

CREATE CONSTRAINT p13_policy_id_unique IF NOT EXISTS
FOR (p:Policy) REQUIRE p.policyId IS UNIQUE;

MERGE (c1:InsCustomer {customerId:"IC01"}) SET c1.name="Yara", c1.email="yara@example.com";
MERGE (c2:InsCustomer {customerId:"IC02"}) SET c2.name="Zeno", c2.email="zeno@example.com";

MERGE (p1:Policy {policyId:"PO10"}) SET p1.type="Car", p1.provider="SafeCo", p1.monthlyPremium=45.0;
MERGE (p2:Policy {policyId:"PO20"}) SET p2.type="Home", p2.provider="HomeSure", p2.monthlyPremium=29.0;
MERGE (p3:Policy {policyId:"PO30"}) SET p3.type="Travel", p3.provider="TripCare", p3.monthlyPremium=9.0;

MATCH (c1:InsCustomer {customerId:"IC01"}), (p1:Policy {policyId:"PO10"})
MERGE (c1)-[:SEARCHED_FOR {at: datetime("2026-01-24T10:15:00"), query:"car insurance cheap"}]->(p1);

MATCH (c1:InsCustomer {customerId:"IC01"}), (p1:Policy {policyId:"PO10"})
MERGE (c1)-[:PURCHASED {at: datetime("2026-01-24T10:45:00"), contractId:"CN-1001", startDate: date("2026-02-01"), premium:45.0, currency:"EUR"}]->(p1);

MATCH (c2:InsCustomer {customerId:"IC02"}), (p3:Policy {policyId:"PO30"})
MERGE (c2)-[:SEARCHED_FOR {at: datetime("2026-01-24T09:05:00"), query:"travel insurance"}]->(p3);

5) Abfragen (ohne Lösung)

  • Kunden mit mindestens einem Vertrag.

  • Top-Provider nach Anzahl PURCHASED.

  • Policen gesucht aber nicht gekauft.

  • Kunden, die alle Policen gekauft haben.

  • Durchschnittliche premium pro Policy-Typ.


Projekt 14 – Banking

1) Titel

Bank: BankClient – BankProduct

2) Kurzbeschreibung

Kunden suchen nach Bankprodukten und eröffnen sie (Konto/Karte/Sparen).

3) Nodes & Relations

  • Nodes: :BankClient(clientId, name, email), :BankProduct(productId, name, type, feeMonthly)

  • Relations:

    • (:BankClient)-[:SEARCHED_FOR {at, query}]->(:BankProduct)

    • (:BankClient)-[:OPENED {at, accountRef, limit}]->(:BankProduct)

4) Befüllen (Cypher)

CREATE CONSTRAINT p14_client_id_unique IF NOT EXISTS
FOR (c:BankClient) REQUIRE c.clientId IS UNIQUE;

CREATE CONSTRAINT p14_product_id_unique IF NOT EXISTS
FOR (p:BankProduct) REQUIRE p.productId IS UNIQUE;

MERGE (c1:BankClient {clientId:"BC01"}) SET c1.name="Alina", c1.email="alina@example.com";
MERGE (c2:BankClient {clientId:"BC02"}) SET c2.name="Bruno", c2.email="bruno@example.com";

MERGE (p1:BankProduct {productId:"BP10"}) SET p1.name="Girokonto", p1.type="Account", p1.feeMonthly=0.0;
MERGE (p2:BankProduct {productId:"BP20"}) SET p2.name="Kreditkarte", p2.type="Card", p2.feeMonthly=3.0;
MERGE (p3:BankProduct {productId:"BP30"}) SET p3.name="Sparplan", p3.type="Savings", p3.feeMonthly=1.0;

MATCH (c1:BankClient {clientId:"BC01"}), (p2:BankProduct {productId:"BP20"})
MERGE (c1)-[:SEARCHED_FOR {at: datetime("2026-01-25T10:15:00"), query:"best credit card"}]->(p2);

MATCH (c1:BankClient {clientId:"BC01"}), (p2:BankProduct {productId:"BP20"})
MERGE (c1)-[:OPENED {at: datetime("2026-01-25T10:45:00"), accountRef:"CARD-7788", limit:1500}]->(p2);

MATCH (c2:BankClient {clientId:"BC02"}), (p1:BankProduct {productId:"BP10"})
MERGE (c2)-[:SEARCHED_FOR {at: datetime("2026-01-25T09:05:00"), query:"free account"}]->(p1);

5) Abfragen (ohne Lösung)

  • Top-Kunden nach Anzahl OPENED.

  • Produkte gesucht aber nicht eröffnet.

  • Verteilung der eröffneten Produkte nach Typ.

  • Kunden, die alle Produkte eröffnet haben.

  • Durchschnittliches Limit pro Kartenprodukt.


Projekt 15 – Mobilfunk

1) Titel

Telco: Subscriber – Plan

2) Kurzbeschreibung

Kunden suchen Tarife und schließen einen Vertrag ab. Laufzeit und Startdatum liegen auf SUBSCRIBED.

3) Nodes & Relations

  • Nodes: :Subscriber(subscriberId, name, email), :Plan(planId, name, dataGb, monthly)

  • Relations:

    • (:Subscriber)-[:SEARCHED_FOR {at, query}]->(:Plan)

    • (:Subscriber)-[:SUBSCRIBED {at, contractMonths, startDate}]->(:Plan)

4) Befüllen (Cypher)

CREATE CONSTRAINT p15_sub_id_unique IF NOT EXISTS
FOR (s:Subscriber) REQUIRE s.subscriberId IS UNIQUE;

CREATE CONSTRAINT p15_plan_id_unique IF NOT EXISTS
FOR (p:Plan) REQUIRE p.planId IS UNIQUE;

MERGE (s1:Subscriber {subscriberId:"SUB1"}) SET s1.name="Carla", s1.email="carla@example.com";
MERGE (s2:Subscriber {subscriberId:"SUB2"}) SET s2.name="Denis", s2.email="denis@example.com";

MERGE (p1:Plan {planId:"PL10"}) SET p1.name="Basic", p1.dataGb=10, p1.monthly=9.9;
MERGE (p2:Plan {planId:"PL20"}) SET p2.name="Plus",  p2.dataGb=50, p2.monthly=19.9;
MERGE (p3:Plan {planId:"PL30"}) SET p3.name="Max",   p3.dataGb=200, p3.monthly=39.9;

MATCH (s1:Subscriber {subscriberId:"SUB1"}), (p2:Plan {planId:"PL20"})
MERGE (s1)-[:SEARCHED_FOR {at: datetime("2026-01-26T10:15:00"), query:"50gb plan"}]->(p2);

MATCH (s1:Subscriber {subscriberId:"SUB1"}), (p2:Plan {planId:"PL20"})
MERGE (s1)-[:SUBSCRIBED {at: datetime("2026-01-26T10:45:00"), contractMonths:24, startDate: date("2026-02-01")}]->(p2);

MATCH (s2:Subscriber {subscriberId:"SUB2"}), (p1:Plan {planId:"PL10"})
MERGE (s2)-[:SEARCHED_FOR {at: datetime("2026-01-26T09:05:00"), query:"cheap plan"}]->(p1);

5) Abfragen (ohne Lösung)

  • Top-Tarife nach Anzahl SUBSCRIBED.

  • Tarife gesucht aber nicht abgeschlossen.

  • Durchschnittliche Vertragslaufzeit.

  • Subscriber, die alle Tarife abgeschlossen haben.

  • Tarife mit Datenvolumen über X und Anzahl Abschlüsse.


Projekt 16 – Fitnessstudio

1) Titel

Gym: GymMember – GymClass

2) Kurzbeschreibung

Mitglieder suchen Kurse und buchen Plätze. Buchung enthält Termin und Buchungs-ID.

3) Nodes & Relations

  • Nodes: :GymMember(memberId, name, email), :GymClass(classId, title, level, durationMin)

  • Relations:

    • (:GymMember)-[:SEARCHED_FOR {at, query}]->(:GymClass)

    • (:GymMember)-[:BOOKED {at, bookingId, classTime}]->(:GymClass)

4) Befüllen (Cypher)

CREATE CONSTRAINT p16_member_id_unique IF NOT EXISTS
FOR (m:GymMember) REQUIRE m.memberId IS UNIQUE;

CREATE CONSTRAINT p16_class_id_unique IF NOT EXISTS
FOR (c:GymClass) REQUIRE c.classId IS UNIQUE;

MERGE (m1:GymMember {memberId:"GM01"}) SET m1.name="Elena", m1.email="elena@example.com";
MERGE (m2:GymMember {memberId:"GM02"}) SET m2.name="Fritz", m2.email="fritz@example.com";

MERGE (c1:GymClass {classId:"CL10"}) SET c1.title="Yoga", c1.level="Beginner", c1.durationMin=60;
MERGE (c2:GymClass {classId:"CL20"}) SET c2.title="HIIT", c2.level="Advanced", c2.durationMin=45;
MERGE (c3:GymClass {classId:"CL30"}) SET c3.title="Pilates", c3.level="Intermediate", c3.durationMin=50;

MATCH (m1:GymMember {memberId:"GM01"}), (c1:GymClass {classId:"CL10"})
MERGE (m1)-[:SEARCHED_FOR {at: datetime("2026-01-27T10:15:00"), query:"yoga beginner"}]->(c1);

MATCH (m1:GymMember {memberId:"GM01"}), (c1:GymClass {classId:"CL10"})
MERGE (m1)-[:BOOKED {at: datetime("2026-01-27T10:45:00"), bookingId:"BK-1001", classTime: datetime("2026-01-28T18:00:00")}]->(c1);

MATCH (m2:GymMember {memberId:"GM02"}), (c2:GymClass {classId:"CL20"})
MERGE (m2)-[:SEARCHED_FOR {at: datetime("2026-01-27T09:05:00"), query:"hiit"}]->(c2);

5) Abfragen (ohne Lösung)

  • Top-Mitglieder nach Anzahl BOOKED.

  • Kurse gesucht aber nicht gebucht.

  • Kurse nach Level mit Buchungsanzahl.

  • Mitglieder, die alle Kurse gebucht haben.

  • Durchschnittliche Kursdauer der gebuchten Kurse.


Projekt 17 – Online Grocery

1) Titel

Grocery: Shopper – Item

2) Kurzbeschreibung

Kunden suchen Artikel und bestellen sie. Bestellbeziehung enthält Menge und Kaufpreis.

3) Nodes & Relations

  • Nodes: :Shopper(shopperId, name, email), :Item(itemId, name, category, price)

  • Relations:

    • (:Shopper)-[:SEARCHED_FOR {at, query}]->(:Item)

    • (:Shopper)-[:ORDERED {at, orderId, quantity, priceAtPurchase, currency}]->(:Item)

4) Befüllen (Cypher)

CREATE CONSTRAINT p17_shopper_id_unique IF NOT EXISTS
FOR (s:Shopper) REQUIRE s.shopperId IS UNIQUE;

CREATE CONSTRAINT p17_item_id_unique IF NOT EXISTS
FOR (i:Item) REQUIRE i.itemId IS UNIQUE;

MERGE (s1:Shopper {shopperId:"SH01"}) SET s1.name="Greta", s1.email="greta@example.com";
MERGE (s2:Shopper {shopperId:"SH02"}) SET s2.name="Henry", s2.email="henry@example.com";

MERGE (i1:Item {itemId:"I100"}) SET i1.name="Milk", i1.category="Groceries", i1.price=1.49;
MERGE (i2:Item {itemId:"I200"}) SET i2.name="Bread", i2.category="Groceries", i2.price=1.99;
MERGE (i3:Item {itemId:"I300"}) SET i3.name="Apples", i3.category="Groceries", i3.price=2.49;

MATCH (s1:Shopper {shopperId:"SH01"}), (i3:Item {itemId:"I300"})
MERGE (s1)-[:SEARCHED_FOR {at: datetime("2026-01-28T10:15:00"), query:"fresh apples"}]->(i3);

MATCH (s1:Shopper {shopperId:"SH01"}), (i3:Item {itemId:"I300"})
MERGE (s1)-[:ORDERED {at: datetime("2026-01-28T10:45:00"), orderId:"ORD-9001", quantity:2, priceAtPurchase:2.49, currency:"EUR"}]->(i3);

MATCH (s2:Shopper {shopperId:"SH02"}), (i1:Item {itemId:"I100"})
MERGE (s2)-[:SEARCHED_FOR {at: datetime("2026-01-28T09:05:00"), query:"milk"}]->(i1);

5) Abfragen (ohne Lösung)

  • Top-Shopper nach Anzahl ORDERED.

  • Artikel gesucht aber nie bestellt.

  • Umsatz pro Kategorie (Summe quantity*priceAtPurchase).

  • Shopper, die alle Items bestellt haben.

  • “Basket”: wer Item A bestellt, bestellt auch welches Item?


Projekt 18 – IT Support

1) Titel

Support: SupportUser – KnowledgeArticle

2) Kurzbeschreibung

User suchen Wissensartikel und verwenden sie zur Lösung. Nutzung speichert “helpful” und “resolvedAt”.

3) Nodes & Relations

  • Nodes: :SupportUser(userId, name, email), :KnowledgeArticle(articleId, title, topic, version)

  • Relations:

    • (:SupportUser)-[:SEARCHED_FOR {at, query}]->(:KnowledgeArticle)

    • (:SupportUser)-[:USED {at, helpful, resolvedAt}]->(:KnowledgeArticle)

4) Befüllen (Cypher)

CREATE CONSTRAINT p18_user_id_unique IF NOT EXISTS
FOR (u:SupportUser) REQUIRE u.userId IS UNIQUE;

CREATE CONSTRAINT p18_article_id_unique IF NOT EXISTS
FOR (a:KnowledgeArticle) REQUIRE a.articleId IS UNIQUE;

MERGE (u1:SupportUser {userId:"SU01"}) SET u1.name="Ivo", u1.email="ivo@example.com";
MERGE (u2:SupportUser {userId:"SU02"}) SET u2.name="Jana", u2.email="jana@example.com";

MERGE (a1:KnowledgeArticle {articleId:"KA10"}) SET a1.title="Reset Password", a1.topic="Account", a1.version=3;
MERGE (a2:KnowledgeArticle {articleId:"KA20"}) SET a2.title="VPN Setup", a2.topic="Network", a2.version=2;
MERGE (a3:KnowledgeArticle {articleId:"KA30"}) SET a3.title="Printer Fix", a3.topic="Hardware", a3.version=5;

MATCH (u1:SupportUser {userId:"SU01"}), (a2:KnowledgeArticle {articleId:"KA20"})
MERGE (u1)-[:SEARCHED_FOR {at: datetime("2026-01-29T10:15:00"), query:"vpn windows"}]->(a2);

MATCH (u1:SupportUser {userId:"SU01"}), (a2:KnowledgeArticle {articleId:"KA20"})
MERGE (u1)-[:USED {at: datetime("2026-01-29T10:45:00"), helpful:true, resolvedAt: datetime("2026-01-29T11:00:00")}]->(a2);

MATCH (u2:SupportUser {userId:"SU02"}), (a3:KnowledgeArticle {articleId:"KA30"})
MERGE (u2)-[:SEARCHED_FOR {at: datetime("2026-01-29T09:05:00"), query:"printer not working"}]->(a3);

5) Abfragen (ohne Lösung)

  • Top-Artikel nach Anzahl USED.

  • Artikel gesucht aber nie verwendet.

  • Erfolgsquote: Anteil helpful=true pro Artikel.

  • User, die alle Artikel verwendet haben.

  • Top-Topics nach Anzahl Suchanfragen.


Projekt 19 – Museum

1) Titel

Museum: Visitor – Exhibit

2) Kurzbeschreibung

Besucher suchen Ausstellungen und besuchen sie. Besuch speichert Dauer in Minuten.

3) Nodes & Relations

  • Nodes: :Visitor(visitorId, name, email), :Exhibit(exhibitId, name, type, floor)

  • Relations:

    • (:Visitor)-[:SEARCHED_FOR {at, query}]->(:Exhibit)

    • (:Visitor)-[:VISITED {at, durationMin}]->(:Exhibit)

4) Befüllen (Cypher)

CREATE CONSTRAINT p19_visitor_id_unique IF NOT EXISTS
FOR (v:Visitor) REQUIRE v.visitorId IS UNIQUE;

CREATE CONSTRAINT p19_exhibit_id_unique IF NOT EXISTS
FOR (e:Exhibit) REQUIRE e.exhibitId IS UNIQUE;

MERGE (v1:Visitor {visitorId:"V001"}) SET v1.name="Karl", v1.email="karl@example.com";
MERGE (v2:Visitor {visitorId:"V002"}) SET v2.name="Lena", v2.email="lena@example.com";

MERGE (e1:Exhibit {exhibitId:"EX10"}) SET e1.name="Dinosaurs", e1.type="History", e1.floor=1;
MERGE (e2:Exhibit {exhibitId:"EX20"}) SET e2.name="Impressionists", e2.type="Art", e2.floor=2;
MERGE (e3:Exhibit {exhibitId:"EX30"}) SET e3.name="Space", e3.type="Science", e3.floor=3;

MATCH (v1:Visitor {visitorId:"V001"}), (e3:Exhibit {exhibitId:"EX30"})
MERGE (v1)-[:SEARCHED_FOR {at: datetime("2026-01-30T10:15:00"), query:"space exhibit"}]->(e3);

MATCH (v1:Visitor {visitorId:"V001"}), (e3:Exhibit {exhibitId:"EX30"})
MERGE (v1)-[:VISITED {at: datetime("2026-01-30T10:45:00"), durationMin:35}]->(e3);

MATCH (v2:Visitor {visitorId:"V002"}), (e2:Exhibit {exhibitId:"EX20"})
MERGE (v2)-[:SEARCHED_FOR {at: datetime("2026-01-30T09:05:00"), query:"impressionism"}]->(e2);

5) Abfragen (ohne Lösung)

  • Top-Ausstellungen nach VISITED.

  • Ausstellungen gesucht aber nicht besucht.

  • Durchschnittliche Besuchsdauer pro Ausstellung.

  • Besucher, die alle Ausstellungen besucht haben.

  • Ausstellungen pro Stockwerk mit Besuchszahlen.


Projekt 20 – E-Learning

1) Titel

E-Learning: Learner – Tutorial

2) Kurzbeschreibung

Lernende suchen Tutorials und schließen sie ab. Abschluss enthält Score und Abschlusszeit.

3) Nodes & Relations

  • Nodes: :Learner(learnerId, name, email), :Tutorial(tutorialId, title, topic, level)

  • Relations:

    • (:Learner)-[:SEARCHED_FOR {at, query}]->(:Tutorial)

    • (:Learner)-[:COMPLETED {at, completedAt, score}]->(:Tutorial)

4) Befüllen (Cypher)

CREATE CONSTRAINT p20_learner_id_unique IF NOT EXISTS
FOR (l:Learner) REQUIRE l.learnerId IS UNIQUE;

CREATE CONSTRAINT p20_tutorial_id_unique IF NOT EXISTS
FOR (t:Tutorial) REQUIRE t.tutorialId IS UNIQUE;

MERGE (l1:Learner {learnerId:"LE01"}) SET l1.name="Milan", l1.email="milan@example.com";
MERGE (l2:Learner {learnerId:"LE02"}) SET l2.name="Nora",  l2.email="nora@example.com";

MERGE (t1:Tutorial {tutorialId:"TU10"}) SET t1.title="SQL Basics", t1.topic="Databases", t1.level="Beginner";
MERGE (t2:Tutorial {tutorialId:"TU20"}) SET t2.title="Neo4j Intro", t2.topic="Graphs", t2.level="Beginner";
MERGE (t3:Tutorial {tutorialId:"TU30"}) SET t3.title="Indexing", t3.topic="Databases", t3.level="Intermediate";

MATCH (l1:Learner {learnerId:"LE01"}), (t2:Tutorial {tutorialId:"TU20"})
MERGE (l1)-[:SEARCHED_FOR {at: datetime("2026-01-31T10:15:00"), query:"graph database tutorial"}]->(t2);

MATCH (l1:Learner {learnerId:"LE01"}), (t2:Tutorial {tutorialId:"TU20"})
MERGE (l1)-[:COMPLETED {at: datetime("2026-01-31T10:45:00"), completedAt: datetime("2026-01-31T12:00:00"), score:92}]->(t2);

MATCH (l2:Learner {learnerId:"LE02"}), (t1:Tutorial {tutorialId:"TU10"})
MERGE (l2)-[:SEARCHED_FOR {at: datetime("2026-01-31T09:05:00"), query:"learn sql"}]->(t1);

5) Abfragen (ohne Lösung)

  • Top-Learner nach Anzahl COMPLETED.

  • Tutorials gesucht aber nicht abgeschlossen.

  • Durchschnittlicher Score pro Tutorial.

  • Learner, die alle Tutorials abgeschlossen haben.

  • Top-Topics nach Anzahl Abschlüsse.