Thirty-one free Open Dental queries

Read-only SQL for Reports > User Query. Free, no signup. Each one below is listed with the assumption it makes, which is usually the reason a report comes back wrong.

All thirty-one on GitHubPaste into Reports > User Query and run. Nothing writes.

Every one is executed before it ships

Open Dental publishes its full database schema. A structure-only copy of it, 430 tables, no data, is rebuilt from that documentation and every query is run against it on every change, so a column your version does not have cannot quietly get through. The harness is verify.sh in the repository, and it takes a version number, so you can check these against yours.

Look at Open Dental's own library first

Open Dental publishes a free Query Examples library of over a thousand queries. It is bigger than this page and costs nothing, and several queries below have an official equivalent in it, including the discount plan list, procedure codes with a default provider, patients with remaining benefits, and time clock hours. If one of theirs answers your question, use it.

What is different here is narrow and worth exactly what it is worth. These are run against the 26.2 schema by CI before they ship, and each one names the assumption that makes the number wrong. The official library sorts by age and says on its own page that older queries may no longer run and that changes may be needed to get the result you want.

The queries

Unscheduled treatment, in dollars

Answers: How much work have we diagnosed that nobody ever booked?

The trap: Deleted procedures carry ProcStatus 6 and are still in the table. Forget to exclude them and the number comes back inflated by work that was cancelled, sometimes badly.

New patients scheduled this month

Answers: How many genuinely new patients are on the books for this month?

The trap: Counting new patients by when they were seen answers a different question than counting by when they are booked. Marketing wants the second one.

New patients who left with nothing booked

Answers: Who came in, had treatment, and walked out without a next visit?

The trap: A patient can have a future appointment that is neither Scheduled nor ASAP. Check the status values you count as "on the books" or you will chase people who are already booked.

An appointment report with broken appointments actually excluded

Answers: What was on the schedule between these dates, for this provider?

The trap: AptStatus 5 is Broken. It is still a row in the appointment table, and most hand-written appointment reports silently include it.

Daily production goal against what is scheduled

Answers: Are we on pace today, against a figure we set ourselves?

The trap: Open Dental's built-in goal is hourly per provider. Most practices think in a number per day for the whole office, which is a different calculation.

Production by dentist, with hygiene rolled in

Answers: What did each dentist produce, including hygiene billed under their licence?

The trap: This is the associate-compensation number, and it is wrong unless hygiene production attributed to a provider rolls back onto the dentist it was billed under.

Payment plans as of a date

Answers: Principal, charged, paid and due, as of a date I choose, not today.

The trap: Aging a payment plan to an arbitrary past date is not the same as filtering by date. The charges that existed then are the ones that count.

Why future payment-plan charges are missing

Answers: The GUI shows a schedule my query does not return. Where is it?

The trap: On a dynamic plan those future charges are not data. Open Dental computes them for display and materialises a row when the charge falls due, which is also why the API's getExpected returns nothing.

Recall due, nothing booked

Answers: Who is overdue for hygiene and has no future appointment?

The trap: Recall rows carry a disabled flag and a sentinel date of 0001-01-01. Both have to go, or the list fills with people who were never on recall.

Insurance claims sent and still unpaid

Answers: Where is our money stuck, and how old is it?

The trap: Aged from the claim procedure date rather than the send date, because that is the date the carrier works from.

Accounts receivable aging by patient

Answers: Who owes us what, in 0-30 / 31-60 / 61-90 / 90+?

The trap: The Bal_0_30 columns on the patient table are not live. Open Dental writes them during the aging run. If aging last ran on the 1st, that is the date your report is really as of, whatever today is.

Collections by day and provider

Answers: What did we actually get paid, and who earned it?

The trap: Read the splits, not the payments. One payment can cover several patients and providers, and unearned prepayment will inflate a day unless you keep it in its own column.

Broken appointments, repeat offenders

Answers: Who keeps breaking appointments, and what did it cost us in chair time?

The trap: Chair time lives in the Pattern string, one character per five minutes, not in a duration column.

Case acceptance by provider

Answers: Of what each provider diagnosed, how much got done?

The trap: Measure it in dollars. One crown is not one sealant, so a count-based acceptance rate flatters whoever diagnoses a lot of small work.

Active patients not seen in 18 months

Answers: Who fell off entirely?

The trap: This is not the recall report. The recall report can only find people who had a recall row to go overdue in the first place; plenty of lapsed patients never had one.

New patients, counted correctly

Answers: How many genuinely new patients did we see, without the count quietly dropping some?

The trap: Open Dental's own library query #1203 has this wrong. With GROUP BY PatNum, a bare ProcDate column is not the group's minimum, it is whichever row was stored first, so a patient whose rows landed out of date order fails the test and vanishes. Reported on the forum in 2024, never fixed. Reproduced in the file header.

A call list for one carrier and a code range

Answers: Who on this insurance has planned work in these codes, and when can we reach them?

The trap: Priority is a foreign key into the definition table, so sorting by it sorts by creation order rather than the sequence the treatment plan shows. GROUP_CONCAT also truncates at 1024 characters by default, which silently cuts the end off a large treatment plan with no error.

Is the in-house discount plan actually making money

Answers: Production, plan writeoffs, adjustments and payments for everyone on the plan, over a date range.

The trap: Joining procedures, adjustments and payments in one FROM clause multiplies them together. A patient with four procedures, two adjustments and three payments becomes twenty-four rows and every total is inflated. Each total here is its own subquery grouped by patient.

Who is on a discount plan

Answers: Which patients are on an in-house plan, and under which fee schedule?

The trap: Open Dental moved discount plans off the patient record and into their own subscription table with effective and termination dates. Both still exist. Read only one and you miss every patient on the other side of the change.

Active patients whose first visit predates a date

Answers: How many of our patients have been with us since before X?

The trap: DateFirstVisit is an editable field, and on a converted database it is often blank or the conversion date for the entire chart. Check it against the earliest completed procedure before trusting it.

Procedure codes with a default provider

Answers: Which codes automatically assign to a provider, and to whom?

The trap: Nothing in the interface lists these overrides. One code still pointed at a provider who left keeps assigning their production, and the only symptom is a number that looks slightly off.

How much of each month's production got collected

Answers: We produced well in March, so where is the money?

The trap: Production and collections reported side by side for the same month compares March's work against March's money, most of which is for earlier work. paysplit carries the procedure date as well as the payment date, which is what lets the two line up.

A fee schedule as a table

Answers: How does this PPO schedule compare to ours, before we sign?

The trap: A code with no fee row is left out rather than shown as zero. Open Dental treats no fee set and a fee of zero as different things, and flattening them changes the comparison.

Hours worked by employee and day

Answers: What does the time clock actually say each person worked?

The trap: TimeDisplayed is the adjusted punch the timecard shows and the one payroll runs from; TimeEntered is the raw punch. Use the raw one only if you are auditing rather than paying. Rows still clocked in have no clock-out and must be excluded, not counted as zero.

Every patient on one insurance carrier

Answers: A carrier changed its fee schedule or went out of network. Who do we have to call?

The trap: Open Dental stores "never terminated" as the sentinel date 0001-01-01, not as NULL. A plain date comparison silently drops every patient whose coverage is still active.

Treatment diagnosed and completed the same day

Answers: How much work do we close in the chair rather than reschedule?

The trap: Different from case acceptance. This counts only what never had to be re-sold, so it needs DateTP and ProcDate compared, not a status filter.

What each carrier writes off

Answers: We hit the production goal, so why is the bank balance short?

The trap: Production counts the full fee. The PPO writeoff is the gap between that and what the contract allows, and it appears in no production report at all.

Payments split by type

Answers: How much came in as cash, card, cheque or insurance?

The trap: payment.PayType is a foreign key into the definition table, not a fixed enum, so the types are whatever the practice set up. Without the join you get a column of integers.

The audit trail as an exportable table

Answers: Who changed what, across a date range rather than one chart at a time?

The trap: securitylog is enormous in an established practice. Keep the window narrow. PermType is a version-specific numeric code, so read LogText, which is the line Open Dental wrote itself.

Unused insurance benefits before the plan year closes

Answers: Who still has annual maximum left to spend before it resets?

The trap: Open Dental stores the annual maximum as a benefit row, and I could not verify from the public documentation which numeric BenefitType means Limitations, so this query does not hard-code it. It derives the maximum from your own data and prints the BenefitType it used, with a one-line query in the header to pin the value for your database.

If the number you want is not here

Ask for it Say what you want in plain English and include your Open Dental version. Real questions get written and added here, free. That is how most of the thirty-oneabove came about.

That link wants a GitHub account, which is a silly thing to ask of a dental practice. If you would rather not, email ishubham2101@gmail.com with the number you cannot get out of Open Dental. Same thing, no signup, and I am genuinely more interested in which numbers people have given up on than in selling anybody anything.

Open Dental will also write you a custom query, and you should know how that works before paying anybody: you must be on their support plan for the whole process, they quote a cost per request and write nothing until you approve it, and their own page says a deadline less than a month out is extremely unlikely to be met even with expediting. They also will not modify a query they did not write, which cuts both ways and applies to anything you buy from me.

If you are on support and a month is fine, theirs is the better deal. If you need it this week, I write these to order: $150 a query, tested, inside 48 hours. Delivered as a .sql file you run yourself, so no patient data leaves your office and there is nothing to sign. If it does not answer the question you asked, I fix it or refund you.