In my projects, I write queries with an eye on the schema, so I always know where the results come from. Also, I never use SELECT x.* , because any added column will ruin my day. Anyway, you could try to interpret the output of `EXPLAIN SELECT`, perhaps in combination with `PRAGMA table_info()`, but it isn't easy, especially with aliased `rowid`. Example: ```sql CREATE TABLE a ( id INTEGER PRIMARY KEY NOT NULL , name TEXT , b_id INTEGER REFERENCES b(id) ); CREATE TABLE b ( id INTEGER PRIMARY KEY NOT NULL , name TEXT ); INSERT INTO b VALUES (2,'two'); INSERT INTO b VALUES (3,'three'); INSERT INTO a VALUES (1,'one',2); .mode column .headers on SELECT * FROM pragma_table_info('a') UNION ALL SELECT * FROM pragma_table_info('b'); EXPLAIN SELECT a.*, b.* FROM a JOIN b ON a.b_id = b.id; SELECT a.*, b.* FROM a JOIN b ON a.b_id = b.id; ``` Result: ``` cid name type notnull dflt_value pk --- ---- ------- ------- ---------- -- 0 id INTEGER 1 1 1 name TEXT 0 0 2 b_id INTEGER 0 0 0 id INTEGER 1 1 1 name TEXT 0 0 addr opcode p1 p2 p3 p4 p5 comment ---- ------------- ---- ---- ---- ------------- -- ------------- 0 Init 0 16 0 0 Start at 16 1 OpenRead 0 2 0 3 0 root=2 iDb=0; a 2 OpenRead 1 3 0 2 0 root=3 iDb=0; b 3 Explain 3 0 0 SCAN a 0 4 Rewind 0 15 0 0 5 Explain 5 0 0 SEARCH b USING INTEGER PRIMARY KEY (rowid=?) 0 6 Column 0 2 1 0 r[1]=a.b_id 7 SeekRowid 1 14 1 0 intkey=r[1] 8 Rowid 0 2 0 0 r[2]=rowid 9 Column 0 1 3 0 r[3]=a.name 10 Column 0 2 4 0 r[4]=a.b_id 11 Rowid 1 5 0 0 r[5]=rowid 12 Column 1 1 6 0 r[6]=b.name 13 ResultRow 2 5 0 0 output=r[2..6] 14 Next 0 5 0 1 15 Halt 0 0 0 0 16 Transaction 0 0 2 0 1 usesStmtJournal=0 17 Goto 0 1 0 0 id name b_id id name -- ---- ---- -- ---- 1 one 2 2 two ``` This probably doesn't solve your problem, but it might give some inspiration.