groue / GRDB.swift

A toolkit for SQLite databases, with a focus on application development

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Query too complex for me - some help required

ahartman opened this issue · comments

I tried a new query based on examples from you:

func getPatientTimeline() -> [PatientTimelineInfo] {
        var patientTimelineInfo = [PatientTimelineInfo]()
        do {
            patientTimelineInfo = try db.read { db in
                let request = Patient
                    .select(
                        Column("id"),
                        Column("patientName")
                    )
                    .order(Column("patientName"))
                    .annotated(with:
                        Patient.visits.min(Column("visitCreated")),
                        Patient.visits.max(Column("visitDate")))
                return try PatientTimelineInfo
                    .fetchAll(db, request)
            }
        } catch {
            fatalError("Unresolved error \(error)")
        }
        return patientTimelineInfo
    }

However this applies to more visits than required, I need to filter the visits for which I calculate the minimum and maximum Dates as in another query below:

func getPatientForCSV(dates: PeriodStartEnd) -> [PatientInfo] {
        var patientInfo = [PatientInfo]()
        do {
            patientInfo = try db.read { db in
                let filteredVisits = Patient.visits
                    .filter(Column("visitDate") >= dates.start)
                    .filter(Column("visitDate") <= dates.end)
                    .filter(["Marieke", "Marieke nieuwe"].contains(Column("visitCalendar")))
                return try Patient
                    .including(all: filteredVisits)
                    .having(filteredVisits.isEmpty == false)
                    .asRequest(of: PatientInfo.self)
                    .fetchAll(db)
            }
        } catch {
            fatalError("Unresolved error \(error)")
        }
        return patientInfo
    }

How can I get the effect of the line - .filter(["Marieke", "Marieke nieuwe"].contains(Column("visitCalendar"))) - in query 2 applied to query 1?

Still happy with GRDB.
Kind regards, André Hartman, Belgique

Environment

**GRDB flavor(s): GRDB
**GRDB version: master
**Installation method: package
**Xcode version: 15.2
**Swift version: 5
**Platform(s) running GRDB: Mac Catalyst
**macOS version running Xcode: Sonoma 14.3.1

Hi @ahartman,

I'm far away from any computer, so I'm not able to verify the validity of my answer.

Did you try to replace Patient.visits, in query 1, with the local variable filteredVisits defined as below?

let filteredVisits = Patient.visits
    .filter(["Marieke", "Marieke nieuwe"].contains(Column("visitCalendar")))

This is the same technique as in query 2: you replace the association of all visits with its filtered version.

Dear Gwendal,
I found the solution - finally - myself.
As I filter the patient visits for their Calendar, I may end up with patients without any visits in the result set.
They, of course do not have a filteredVisits.min(Column("visitCreated")) nor a filteredVisits.max(Column("visitDate")); the result is the GRDB error.
I needed to add the line ".having(filteredVisits.isEmpty == false)" and all was well.

I was reminded again that SQL is a subtle science.

Regards, André Hartman

I'm back from vacations, and you have solved your issue, @ahartman 👍🙂

The Assertion failed: unexpected NULL value error is interesting, because it is the sign of an actual GRDB bug (yeah, a real one). I won't bother you with asking for a way to reproduce the error, but if you have some spare time to put on this, this would be appreciated.

Until then, or until your next question, happy GRDB!

I do not think this is a GRDB issue; my error was to query a potential NULL result into a non-optional value.

It is a GRDB bug, because assertions like this are never supposed to be triggered.

This is a repeatable error, so it is easy to reproduce for you.

When I have the code and data that reproduces (something that compiles and runs on data that triggers the bug), yes I guess it starts to be easy ;-) Right now there are too many uninformed guesses to do.