Remember that casting can do weird things, so whatever you try, make sure it's doing what you want. sqlite> create table t1 (a text unique); sqlite> create table t2 (b integer); sqlite> insert into t1 values ('1'), ('1.0'), ('1xyz'); sqlite> insert into t2 values (1); sqlite> select * from t2 left outer join t1 on a = b; QUERY PLAN |--SCAN TABLE t2 `--SCAN TABLE t1 b|a 1|1 1|1.0 sqlite> select * from t2 left outer join t1 on a = cast(b as text); QUERY PLAN |--SCAN TABLE t2 `--SEARCH TABLE t1 USING COVERING INDEX sqlite_autoindex_t1_1 (a=?) b|a 1|1 sqlite> select * from t2 left outer join t1 on cast(a as int) = b; QUERY PLAN |--SCAN TABLE t2 `--SCAN TABLE t1 b|a 1|1 1|1.0 1|1xyz