Concepts / Parsing CSV Files in Python

Parsing CSV Files in Python

The INSERT OR IGNORE and SELECT pattern solves the foreign key dependency problem by inserting a record and immediately retrieving its ID for use in subsequent insertions.

  • Programming

From Flat Rows to Linked Records

A CSV file presents data as rows of values, but a relational database may organize those values across several linked tables. During a load operation, one value from a CSV row may identify a record in a parent table, while another record must store that parent row's database ID as a foreign key. The central technique is to insert the parent value or ignore it when it already exists, immediately select its ID, and reuse that ID in the next insertion.

The pattern is not simply an insertion pattern. It is an insert, retrieve, and reuse pattern that connects a natural value from the input to an actual database row ID.

The Insert-Retrieve-Reuse Sequence

Suppose a CSV row contains a value that belongs in a parent table. First, INSERT OR IGNORE attempts to add that value. If the value is new, a row is inserted. If the value is already present, the duplicate is ignored rather than creating another copy. Next, SELECT retrieves the ID of the row that now represents the value. That ID is the value needed by a later child-table insertion.

valuerow existsreturnsindex [0]foreign keyCSV valueparent valueINSERT OR IGNOREadd or skip duplicateSELECTfind the rowReturned tuplerow data containing IDForeign key IDcur.fetchone()[0]Child insertionreuse the ID
What happens when a parent value is inserted, an existing duplicate is ignored, and its foreign key ID is retrieved?

Parent Tables Before Child Tables

Foreign key dependencies determine the load order. A parent table must be populated before a child table that references it. The reason is operational: the child insertion needs an ID that belongs to an existing parent row. Loading the child first reverses the dependency and leaves its foreign key without the required parent row.

retrieve IDforeign keydependencyParent tableinsert firstParent IDretrieve after SELECTChild tablestores foreign keyLater related tableinsert after dependencies
Which table must be populated first, and how do foreign key dependencies determine the order of subsequent insertions?

Before writing the load steps, identify which tables are parents and which are children. Then arrange the insertions so every referenced parent row is handled before the child row that needs its ID.

Tracing One CSV Row

A row moving through related tables

A CSV row contains a value for a parent table and related information for a child table. Describe the load sequence without creating a duplicate parent record.

Read the parent value: Treat the value from the CSV row as the value to look up or establish in the parent table.

Insert or ignore: Use INSERT OR IGNORE. A new parent value is inserted; a value already present is skipped, so duplicate values are handled gracefully.

Retrieve the parent ID: Use SELECT immediately after the insert-or-ignore step. The returned tuple contains the row information, and cur.fetchone()[0] extracts the actual ID.

Insert the child record: Place the retrieved parent ID into the child record's foreign key field, together with the other data from the CSV row.

The CSV row is represented across related tables, and the child record points to an actual parent row through the retrieved foreign key ID.

extractINSERT OR IGNORESELECTforeign keyCSV rowmultiple valuesParent valuenatural input valueParent recordinserted or retainedParent IDretrieved identifierChild recordstores foreign key
How does data from one CSV row move through the parent and child tables during the load operation?

Turning Values into Foreign Keys

The CSV usually gives the loader a natural value, while the related table needs a database ID. The SELECT step performs the bridge between them. It finds the row associated with the natural value, and indexing the first item of the fetched tuple produces the ID that can be reused in a later insertion.

identifyextract first itemreuseNatural valuefrom CSVParent rowfound by SELECTIDcur.fetchone()[0]Child foreign keyreused ID
How does a natural value from the CSV become a database ID, and where is that ID reused?

The ID is the handoff between table operations: SELECT obtains it from the parent row, and the next insertion uses it as the child row's foreign key.

Mapping Fields to Records

A single CSV row can contribute to more than one relational record. The value that identifies a parent belongs in the parent-table operation. Other values can be used when the child record is inserted. The retrieved parent ID is not another independent CSV value; it is produced during the load and placed into the child's foreign key field.

map parent valueinsert then selectadd foreign keyCSV fieldsvalues from one rowParent fieldsparent valueRetrieved IDfrom SELECTChild fieldsCSV values plus foreign key
How are fields in one CSV row mapped to columns and records across multiple related tables?

Mistakes That Break the Load

  • Inserting a child record before its parent record

    The child table depends on a parent row through a foreign key.

    Fix: Insert or locate the parent row first, retrieve its ID, and then insert the child record.

  • Treating a duplicate parent value as a reason to stop the load

    Duplicate values can be handled by skipping the duplicate and using the existing row.

    Fix: Use INSERT OR IGNORE, then SELECT the existing row's ID.

  • Using the fetched tuple instead of its ID

    The SELECT result is returned as a tuple, while the later foreign key operation needs the actual ID value.

    Fix: Index the first item with cur.fetchone()[0].

  • Retrieving the ID without reusing it

    The retrieved ID is the connection between the parent row and the child row.

    Fix: Pass the retrieved ID into the child record's foreign key field.

Practice the Dependency Trace

MEDIUM

A CSV row supplies a value for a parent record and additional values for a child record. Write the four conceptual steps needed to load that row using the INSERT OR IGNORE and SELECT pattern. Include the point at which cur.fetchone()[0] is used and identify where the resulting ID goes.

Hints
  • Start with the table that does not depend on another table's foreign key.
  • The duplicate case should not create a second parent record.
  • The SELECT result is a tuple, so identify the operation that extracts its first item.
  • The extracted ID is reused in the child record.
  1. To solve the practice trace, name the operations in this order: insert or ignore the parent value, select the corresponding row, extract the ID with cur.fetchone()[0], and insert the child record using that ID as its foreign key.

Reliable Relational Loads

  • INSERT OR IGNORE handles duplicate parent values by skipping the duplicate instead of creating another row.
  • SELECT immediately retrieves the ID of the parent row that will be referenced later.
  • Use cur.fetchone()[0] to extract the actual ID from the tuple returned by SELECT.
  • Insert parent tables before child tables because child rows depend on parent foreign key targets.
  • The retrieved parent ID carries a CSV row's relationship into the child-table insertion.

Key Takeaways

  • The INSERT OR IGNORE and SELECT pattern connects CSV values to relational database IDs.
  • INSERT OR IGNORE permits duplicate values to be skipped while preserving the existing row.
  • The ID retrieved with cur.fetchone()[0] is reused as a foreign key in a later insertion.
  • Foreign key dependencies require parent tables to be populated before child tables.
  • Tracing each CSV row through parent insertion, ID retrieval, and child insertion prevents broken relationships and data loss.