Explain the difference between inner joins, left outer joins, and self-joins with practical examples.