Most PDF data doesn't fit in one table. A shipping invoice has header fields and a list of tracking events, and flattening both into a single table means stuffing lists into cells — then someone downstream gets to reconstruct the relationships, badly, forever.
Many extraction tools hand you that flat file and wish you luck. PdfParse takes a different route. Extracted data lands in SQLite, with real tables, typed columns, and foreign keys — so the relationships survive the trip, and anyone with existing SQL knowledge can query the result instead of learning a vendor's rule language.
Still, a relational database locked inside a platform is a hosting plan with extra steps. SQLite is one portable file: open it anywhere, share it anywhere, no server required.
This guide converts shipping invoices into exactly that:
shipping_invoicesstores one row for each invoice.tracking_shipmentsstores the repeating tracking events.
Each tracking event links back to its invoice, so you can filter, group, and join the extracted data with SQL afterward.
What good output looks like
The parent table holds the invoice data:
The child table holds the tracking events:
PdfParse creates the stable record identifiers and the foreign-key link itself. The extraction model never invents these values.
1. Plan the database structure
Stuffing repeating tracking events into a single invoice cell is how data goes to die. Give them a child table.
The parent schema:
| Column | Type | Meaning |
|---|---|---|
invoice_number | text | Invoice number as printed |
tracking_number | text | Carrier tracking number |
carrier | text | Carrier name |
issue_date | date | Invoice issue date |
destination | text | Delivery destination |
total_amount | number | Final invoice amount |
status | text | Shipment status |
The child schema:
| Column | Type | Meaning |
|---|---|---|
checkpoint_sequence | number | Event order |
event_time | date | Event date or time |
event_status | text | Tracking status |
location | text | Event location |
notes | text | Event details |
Keep identifiers and codes as text — tracking numbers can contain letters and leading zeros, and numeric types eat both for breakfast.
2. Create a project
Sign in to PdfParse. Then:
- Select New Project.
- Enter a short project name.
- Enter an optional description.
- Keep the processing threshold at its default unless you have a tested reason to change it.
- Enable password protection only if your authorized documents need it and the option is available.
- Select Create Project.
The project keeps its schema, documents, extracted rows, queries, and exports in one place.
3. Create the parent and child tables
Select Create table in the project.
You can define the schema directly, or use a representative sample PDF when the schema builder offers a suggestion flow. Either way, review every field before you save.
Create shipping_invoices as the parent and tracking_shipments as its child table, with prompts that describe the printed values:
Don't write prompts that ask the model to create id values or foreign keys — PdfParse creates the relationship fields for you.
4. Upload and process the PDFs
Open Manage Files for the table. Then:
- Upload a small representative set.
- Wait until the files are ready.
- Select the files that you want to process.
- Select Process Selected.
- Wait for the extraction job to complete.
Start with two or three documents, and make one of them the awkward layout. Don't run the full archive until the sample checks out.
PdfParse picks the processing path from the project threshold and the request — there's no per-file OCR decision to make.
Use synthetic or redacted files for training and demonstrations.
5. Review the extracted rows
Open shipping_invoices and check the headline values first:
- invoice number
- tracking number
- issue date
- total amount
- status
Then open tracking_shipments and confirm:
- each printed tracking event created one child row
- the event order is correct
- each child row links to the correct invoice
- no page header became a child row
Select source-linked rows and compare them with the PDF where the table view provides the source document. Review dates, codes, decimal points, and negative values with extra care.
Resist the urge to do this check with SQL alone. SQL can find inconsistent data, but it can't prove OCR read the source correctly — eyes on the source first, queries second.
6. Query the database with SQL
Open Query in the project sidebar.
The query view accepts one read-only SELECT, WITH, or EXPLAIN statement at a time. Writes and administration statements are blocked, and results cap at 100 rows.
Find shipments that need attention:
Join invoices to their tracking events:
The exact generated relationship column is visible in your project schema — use that name in your query.
7. Export the SQLite database
Open Project Settings, find Data Export, and select Export SQLite Database.
PdfParse prepares the complete project database file. Wait for the ready state, then download it.
Open the file with any SQLite client, or poke it from a terminal:
Inspect the schema:
Run a read-only check:
Keep the original project around until the downloaded file checks out.
Validate the database
Before the file goes anywhere near another system, confirm:
- Every expected table exists.
- Every required column exists.
- Parent row counts match the processed documents.
- Child row counts match the repeating source records.
- Foreign-key links return the expected records.
- Date and number values use consistent types.
- Aggregate totals agree with the source documents.
Use PDF to SQLite to inspect the public query demo. Use CSV for flat spreadsheet data. Use JSON for API payloads and nested objects. Read the API documentation to automate document processing.