The lookup-table insert relied on INSERT OR IGNORE and the unique index
to dedupe against existing rows, but SQLite unique indexes treat NULLs
as distinct - extracting a second table into the same lookup table
re-inserted every NULL-containing value, growing orphan rows on each
extract. The insert now also has an IS-based NOT EXISTS guard, matching
how the foreign keys themselves are resolved.
Refs https://github.com/simonw/sqlite-utils/issues/769#issuecomment-4900034150
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- table.extract() and the sqlite-utils extract command now skip rows
where every extracted column is null: the new foreign key column is
left null and no all-null record is added to the lookup table. Rows
with at least one non-null extracted column are extracted as before.
- The extracts= option to insert() and friends keeps None values as
null instead of creating a lookup record for them - previously each
insert batch added a duplicate null row to the lookup table.
- table.lookup() compares values using IS rather than = so lookup
values containing None match existing rows correctly, instead of
inserting a duplicate row on every call.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Closes#577
This should solve all sorts of problems seen by users of platforms that throw errors on writable_schema.
Also added `add_foreign_keys=` and `foreign_keys=` parameters to `table.transform()`.
Takes my test down from ten minutes to four seconds!
* Removed unnecessary update() optimization
* Added column_order= to .transform() and .transform_sql()
* Tests for reusing lookup table in extract()
Closes#172