Repository: kayak/pypika
Pull request #12 (2016-08-26 09:55:50)

Removed usage of pointer references for table equality
Changed the behavior of pypika to no longer require that the same object be used when building a query.  This would otherwise be a huge pitfall for developers.  Now, the table name is used as the alias with joins and any table object with the same table name/schema can be use interchangeably.  For complex requirements, an alias can explicitly be set on a table.


Patch:
diff --git a/README.rst b/README.rst
index 7b830a2..24eb7ba 100644
--- a/README.rst
+++ b/README.rst
@@ -310,7 +310,7 @@ calling :class:`Joiner.on()` the original query builder is returned and addition
 
 .. code-block:: sql
 
-    SELECT t0.* FROM history t0 JOIN customers t1 ON t0.customer_id=t1.id WHERE t1.id=5
+    SELECT history.* FROM history JOIN customers ON history.customer_id=customers.id WHERE customers.id=5
 
 Unions
 """"""
diff --git a/pypika/queries.py b/pypika/queries.py
index 1d5a985..885a4d5 100644
--- a/pypika/queries.py
+++ b/pypika/queries.py
@@ -1,6 +1,4 @@
 # coding: utf8
-import uuid
-from collections import OrderedDict
 
 from pypika.enums import JoinType, UnionType
 from pypika.utils import JoinException, UnionException, RollupException
@@ -13,7 +11,6 @@ __email__ = "theys@kayak.com"
 
 class Selectable(object):
     def __init__(self, alias):
-        self.item_id = uuid.uuid1().int
         self.alias = alias
 
     def field(self, name):
@@ -30,13 +27,13 @@ class Selectable(object):
 
         return self.field(name)
 
-    def __hash__(self):
-        return self.item_id
+        # def __hash__(self):
+        #     return hash(str(self))
 
 
 class Table(Selectable):
-    def __init__(self, name, schema=None):
-        super(Table, self).__init__(None)
+    def __init__(self, name, schema=None, alias=None):
+        super(Table, self).__init__(alias)
         self.table_name = name
         self.schema = schema
 
@@ -62,14 +59,29 @@ class Table(Selectable):
 
         return name
 
+    def __str__(self):
+        return self.get_sql()
+
     def __eq__(self, other):
-        return isinstance(other, Table) and self.table_name == other.table_name
+        if not isinstance(other, Table):
+            return False
 
-    def __hash__(self):
-        return self.item_id
+        if self.table_name != other.table_name:
+            return False
 
-    def __str__(self):
-        return self.get_sql()
+        if self.schema != other.schema:
+            return False
+
+        if self.alias != other.alias:
+            return False
+
+        return True
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+    def __hash__(self):
+        return hash(str(self))
 
 
 def make_tables(*names, **kwargs):
@@ -140,8 +152,6 @@ class QueryBuilder(Selectable, Term):
     def __init__(self):
         super(QueryBuilder, self).__init__(None)
 
-        self._selectables = OrderedDict()
-
         self._from = None
         self._insert_table = None
 
@@ -162,6 +172,8 @@ class QueryBuilder(Selectable, Term):
         self._mysql_rollup = False
         self._select_into = False
 
+        self._subquery_count = 0
+
     @builder
     def from_(self, selectable):
         """
@@ -180,7 +192,10 @@ class QueryBuilder(Selectable, Term):
             raise AttributeError("'Query' object has no attribute '%s'" % 'from_')
 
         self._from = Table(selectable) if isinstance(selectable, str) else selectable
-        self._selectables[self._from.item_id] = self._from
+
+        if isinstance(selectable, QueryBuilder):
+            selectable.table_name = 'sq0'
+            self._subquery_count += 1
 
     @builder
     def into(self, table):
@@ -196,11 +211,11 @@ class QueryBuilder(Selectable, Term):
     def select(self, *terms):
         for term in terms:
             if isinstance(term, Field):
-                self._select_field(self._replace_table_ref(term))
+                self._select_field(term)
             elif isinstance(term, str):
                 self._select_field_str(term)
             elif isinstance(term, (Function, ArithmeticExpression)):
-                self._select_other(self._replace_table_ref(term))
+                self._select_other(term)
             else:
                 self._select_other(self._wrap(term))
 
@@ -237,7 +252,7 @@ class QueryBuilder(Selectable, Term):
 
     @builder
     def where(self, criterion):
-        self._replace_table_ref(criterion)
+        self._validate_term(criterion)
 
         if self._wheres:
             self._wheres &= criterion
@@ -245,57 +260,57 @@ class QueryBuilder(Selectable, Term):
             self._wheres = criterion
 
     @builder
-    def having(self, criteria):
-        for field in criteria.fields():
-            self._replace_table_ref(field)
+    def having(self, criterion):
+        self._validate_term(criterion)
 
         if self._havings:
-            self._havings &= criteria
+            self._havings &= criterion
         else:
-            self._havings = criteria
+            self._havings = criterion
 
     @builder
-    def groupby(self, *fields):
-        for field in fields:
-            if isinstance(field, str):
-                field = Field(field, table=self._from)
-            self._groupbys.append(self._replace_table_ref(field))
+    def groupby(self, *terms):
+        for term in terms:
+            if isinstance(term, str):
+                term = Field(term, table=self._from)
+
+            self._validate_term(term)
+            self._groupbys.append(term)
 
     @builder
-    def rollup(self, *fields, **kwargs):
+    def rollup(self, *terms, **kwargs):
         for_mysql = 'mysql' == kwargs.get('vendor')
 
         if self._mysql_rollup:
             raise AttributeError("'Query' object has no attribute '%s'" % 'rollup')
 
         if for_mysql:
-            if not fields and not self._groupbys:
+            if not terms and not self._groupbys:
                 raise RollupException('At least one group is required. Call Query.groupby(term) or pass'
                                       'as parameter to rollup.')
 
             self._mysql_rollup = True
-            self._groupbys += fields
+            self._groupbys += terms
 
         else:
-            self._groupbys.append(Rollup(*fields))
+            self._groupbys.append(Rollup(*terms))
 
     @builder
     def orderby(self, *fields, **kwargs):
         for field in fields:
-            if isinstance(field, str):
-                field = Field(field, table=self._from)
-            else:
-                field = self._replace_table_ref(self._wrap(field))
+            field = (Field(field, table=self._from)
+                     if isinstance(field, str)
+                     else self._wrap(field))
 
             self._orderbys.append((field, kwargs.get('order')))
 
     @builder
     def join(self, item, how=JoinType.inner):
         if isinstance(item, Table):
-            return TableJoiner(self, item, how)
+            return Joiner(self, item, how, type_label='table')
 
         elif isinstance(item, QueryBuilder):
-            return SubqueryJoiner(self, item, how)
+            return Joiner(self, item, how, type_label='subquery')
 
         raise ValueError("Cannot join on type '%s'" % type(item))
 
@@ -331,6 +346,8 @@ class QueryBuilder(Selectable, Term):
             # Do not add select terms after a star is selected
             return
 
+        self._validate_term(term)
+
         if term.table in self._select_star_tables:
             # Do not add select terms for table after a table star is selected
             return
@@ -344,6 +361,7 @@ class QueryBuilder(Selectable, Term):
         self._selects.append(term)
 
     def _select_other(self, function):
+        self._validate_term(function)
         self._selects.append(function)
 
     def fields(self):
@@ -371,38 +389,69 @@ class QueryBuilder(Selectable, Term):
         return self._list_aliases(self._groupbys)
 
     def do_join(self, item, criterion, how):
-        self._selectables[item.item_id] = item
-        self._joins.append(Join(item.item_id, criterion, how))
+        self._validate_join(criterion, item)
 
-        for field in criterion.fields():
-            self._replace_table_ref(field)
+        if isinstance(item, QueryBuilder):
+            self._tag_subquery(item)
 
-    def _replace_table_ref(self, term):
-        for field in term.fields():
-            if field.table is None:
-                field.table = self._from
-                continue
+        if (isinstance(item, Table) and isinstance(self._from, Table) and
+                    item.alias is None and item.table_name == self._from.table_name):
+            # On the odd chance that we join the same table as the FROM table and don't set an alias
+            item.alias = item.table_name + '2'
+
+        self._joins.append(Join(item, criterion, how))
 
-            if field.table.item_id not in self._selectables:
+    def _validate_term(self, term):
+        for field in term.fields():
+            if (field.table is not None
+                and field.table != self._from
+                and field.table not in [join.item for join in self._joins]):
                 raise JoinException('Table [%s] missing from query.  '
                                     'Table must be first joined before any of '
                                     'its fields can be used' % field.table)
 
-            field.table = self._selectables[field.table.item_id]
-        return term
+    def _validate_join(self, criterion, item):
+        criterion_tables = set([f.table for f in criterion.fields()])
+        join_tables = ({self._from} | set(self._joins) | {item}) & criterion_tables
+        missing_tables = criterion_tables - join_tables
+        if missing_tables:
+            raise JoinException('Invalid join criterion. One field is required from the joined item and '
+                                'another from the selected table or an existing join.  Found [{tables}]'.format(
+                tables=', '.join(map(str, missing_tables))
+            ))
+
+    def _tag_subquery(self, subquery):
+        subquery.alias = 'sq%d' % self._subquery_count
+        self._subquery_count += 1
 
     def __str__(self):
         return self.get_sql(with_unions=True)
 
+    def __eq__(self, other):
+        if not isinstance(other, QueryBuilder):
+            return False
+
+        if not self.alias == other.alias:
+            return False
+
+        if not self._from == other._from:
+            return False
+
+        return True
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+    def __hash__(self):
+        return hash(self.alias) + hash(self._from)
+
     def get_sql(self, with_alias=False, subquery=False, with_unions=False, **kwargs):
         if not (self._selects or self._insert_table):
             return ''
         if self._insert_table and not (self._selects or self._values):
             return ''
 
-        if self._joins:
-            for i, table in enumerate(self._selectables.values()):
-                table.alias = table.alias or 't%d' % i
+        kwargs = {'with_namespace': bool(self._joins)}
 
         if not self._select_into and self._insert_table:
             querystring = self._insert_sql()
@@ -413,10 +462,10 @@ class QueryBuilder(Selectable, Term):
             if self._values:
                 return querystring + self._values_sql()
             else:
-                querystring += ' ' + self._select_sql()
+                querystring += ' ' + self._select_sql(**kwargs)
 
         else:
-            querystring = self._select_sql()
+            querystring = self._select_sql(**kwargs)
 
             if self._insert_table:
                 querystring += self._into_sql()
@@ -428,21 +477,21 @@ class QueryBuilder(Selectable, Term):
             for join_item in self._joins:
                 if join_item.how.value:
                     querystring += self._jointype_sql(join_item)
-                querystring += self._join_sql(join_item)
+                querystring += self._join_sql(join_item, **kwargs)
 
         if self._wheres:
-            querystring += self._where_sql()
+            querystring += self._where_sql(**kwargs)
 
         if self._groupbys:
-            querystring += self._group_sql()
+            querystring += self._group_sql(**kwargs)
             if self._mysql_rollup:
                 querystring += self._rollup_sql()
 
         if self._havings:
-            querystring += self._having_sql()
+            querystring += self._having_sql(**kwargs)
 
         if self._orderbys:
-            querystring += self._orderby_sql()
+            querystring += self._orderby_sql(**kwargs)
 
         if subquery:
             querystring = '({query})'.format(
@@ -457,10 +506,10 @@ class QueryBuilder(Selectable, Term):
 
         return querystring
 
-    def _select_sql(self):
+    def _select_sql(self, **kwargs):
         return 'SELECT {distinct}{select}'.format(
             distinct='distinct ' if self._distinct else '',
-            select=','.join(term.get_sql(with_quotes=True, with_alias=True)
+            select=','.join(term.get_sql(with_quotes=True, with_alias=True, **kwargs)
                             for term in self._selects),
         )
 
@@ -497,35 +546,35 @@ class QueryBuilder(Selectable, Term):
     def _jointype_sql(self, join_item):
         return ' {type}'.format(type=join_item.how.value)
 
-    def _join_sql(self, join_item):
+    def _join_sql(self, join, **kwargs):
         return ' JOIN {table} ON {criterion}'.format(
-            table=self._selectables[join_item.table_id].get_sql(with_quotes=True, subquery=True, with_alias=True),
-            criterion=join_item.criteria.get_sql(with_quotes=True),
+            table=join.item.get_sql(with_quotes=True, subquery=True, with_alias=True),
+            criterion=join.criteria.get_sql(with_quotes=True, **kwargs),
         )
 
-    def _where_sql(self):
-        return ' WHERE {where}'.format(where=self._wheres.get_sql(with_quotes=True, subquery=True))
+    def _where_sql(self, **kwargs):
+        return ' WHERE {where}'.format(where=self._wheres.get_sql(with_quotes=True, subquery=True, **kwargs))
 
-    def _group_sql(self):
+    def _group_sql(self, **kwargs):
         return ' GROUP BY {groupby}'.format(
-            groupby=','.join(term.get_sql(with_quotes=True)
+            groupby=','.join(term.get_sql(with_quotes=True, **kwargs)
                              for term in self._groupbys)
         )
 
     def _rollup_sql(self):
         return ' WITH ROLLUP'
 
-    def _having_sql(self):
-        return ' HAVING {having}'.format(having=self._havings.get_sql(with_quotes=True))
+    def _having_sql(self, **kwargs):
+        return ' HAVING {having}'.format(having=self._havings.get_sql(with_quotes=True, **kwargs))
 
-    def _orderby_sql(self):
+    def _orderby_sql(self, **kwargs):
         return ' ORDER BY {orderby}'.format(
             orderby=','.join(
                 '{field} {orient}'.format(
                     field=field.get_sql(with_quotes=True),
                     orient=orient.value,
                 ) if orient is not None else
-                field.get_sql(with_quotes=True)
+                field.get_sql(with_quotes=True, **kwargs)
                 for field, orient in self._orderbys
             )
         )
@@ -533,7 +582,7 @@ class QueryBuilder(Selectable, Term):
     def _queryalias_sql(self, querystring):
         return '{query} \"{alias}\"'.format(
             query=querystring,
-            alias=self.alias,
+            alias=self.alias or self.table_name,
         )
 
     def _union_sql(self, querystring):
@@ -554,42 +603,23 @@ class QueryBuilder(Selectable, Term):
 
 
 class Joiner(object):
-    def __init__(self, query, how):
+    def __init__(self, query, item, how, type_label):
         self.query = query
+        self.item = item
         self.how = how
-
-    def on(self, criterion):
-        raise NotImplementedError()
-
-
-class TableJoiner(Joiner):
-    def __init__(self, query, table, how):
-        super(TableJoiner, self).__init__(query, how)
-        self.table = table
-
-    def on(self, criterion):
-        if criterion is None:
-            raise JoinException("Parameter 'on' is required when joining a table but was not supplied.")
-
-        self.query.do_join(self.table, criterion, self.how)
-        return self.query
-
-
-class SubqueryJoiner(Joiner):
-    def __init__(self, query, subquery, how):
-        super(SubqueryJoiner, self).__init__(query, how)
-        self.subquery = subquery
+        self.type_label = type_label
 
     def on(self, criterion):
         if criterion is None:
-            raise JoinException("Parameter 'on' is required when joining a subquery but was not supplied.")
+            raise JoinException("Parameter 'on' is required when joining a "
+                                "{type} but was not supplied.".format(type=self.type_label))
 
-        self.query.do_join(self.subquery, criterion, self.how)
+        self.query.do_join(self.item, criterion, self.how)
         return self.query
 
 
 class Join(object):
-    def __init__(self, table_id, criteria, how):
-        self.table_id = table_id
+    def __init__(self, item, criteria, how):
+        self.item = item
         self.criteria = criteria
         self.how = how
diff --git a/pypika/terms.py b/pypika/terms.py
index 2cf124c..a88711b 100644
--- a/pypika/terms.py
+++ b/pypika/terms.py
@@ -192,12 +192,13 @@ class Field(Term):
         self.table = table
         return self
 
-    def get_sql(self, with_alias=False, with_quotes=True, **kwargs):
+    def get_sql(self, with_alias=False, with_quotes=True, with_namespace=False, **kwargs):
         quote_char = '\"' if with_quotes else ''
 
-        if getattr(self, 'table', None) and getattr(self.table, 'alias', None):
+        # Need to add namespace if the table has an alias
+        if self.table and (with_namespace or self.table.alias):
             name = "{quote}{namespace}{quote}.{quote}{name}{quote}".format(
-                namespace=self.table.alias,
+                namespace=self.table.alias or self.table.table_name,
                 name=self.name,
                 quote=quote_char,
             )
@@ -221,10 +222,10 @@ class Star(Field):
     def __init__(self, table=None):
         super(Star, self).__init__('*', table=table)
 
-    def get_sql(self, with_alias=False, **kwargs):
-        if self.table is not None and self.table.alias is not None:
+    def get_sql(self, with_alias=False, with_namespace=False, **kwargs):
+        if self.table and (with_namespace or self.table.alias):
             return "\"{namespace}\".*".format(
-                namespace=self.table.alias,
+                namespace=self.table.alias or self.table.table_name,
             )
 
         return '*'
@@ -520,11 +521,12 @@ class Function(Term):
                        for param in self.params]
         return self
 
-    def get_sql(self, with_alias=False, **kwargs):
+    def get_sql(self, with_alias=False, with_namespace=False, **kwargs):
         # FIXME escape
         return '{name}({params}){alias}'.format(
             name=self.name,
-            params=','.join(p.get_sql(with_quotes=True, with_alias=False) if hasattr(p, 'get_sql')
+            params=','.join(p.get_sql(with_quotes=True, with_alias=False, with_namespace=with_namespace)
+                            if hasattr(p, 'get_sql')
                             else str(p)
                             for p in self.params),
             alias=' \"{}\"'.format(self.alias) if self.alias is not None and with_alias else ''


Test patch:
diff --git a/pypika/tests/test_criterions.py b/pypika/tests/test_criterions.py
index 89c7c5d..782526b 100644
--- a/pypika/tests/test_criterions.py
+++ b/pypika/tests/test_criterions.py
@@ -10,8 +10,7 @@ __email__ = "theys@kayak.com"
 
 
 class CriterionTests(unittest.TestCase):
-    t = Table('test')
-    t.alias = 't0'
+    t = Table('test', alias = 'crit')
 
     def test__criterion_eq_number(self):
         c1 = Field('foo') == 1
@@ -19,15 +18,15 @@ class CriterionTests(unittest.TestCase):
         c3 = Field('foo', table=self.t) == -1
 
         self.assertEqual('"foo"=1', str(c1))
-        self.assertEqual('"t0"."foo"=0', str(c2))
-        self.assertEqual('"t0"."foo"=-1', str(c3))
+        self.assertEqual('"crit"."foo"=0', str(c2))
+        self.assertEqual('"crit"."foo"=-1', str(c3))
 
     def test__criterion_eq_decimal(self):
         c1 = Field('foo') == 1.0
         c2 = Field('foo', table=self.t).eq(0.5)
 
         self.assertEqual('"foo"=1.0', str(c1))
-        self.assertEqual('"t0"."foo"=0.5', str(c2))
+        self.assertEqual('"crit"."foo"=0.5', str(c2))
 
     def test__criterion_eq_bool(self):
         c1 = Field('foo') == True
@@ -36,51 +35,51 @@ class CriterionTests(unittest.TestCase):
         c4 = Field('foo', table=self.t).eq(False)
 
         self.assertEqual('"foo"=true', str(c1))
-        self.assertEqual('"t0"."foo"=true', str(c2))
+        self.assertEqual('"crit"."foo"=true', str(c2))
         self.assertEqual('"foo"=false', str(c3))
-        self.assertEqual('"t0"."foo"=false', str(c4))
+        self.assertEqual('"crit"."foo"=false', str(c4))
 
     def test__criterion_eq_str(self):
         c1 = Field('foo') == 'abc'
         c2 = Field('foo', table=self.t).eq('abc')
 
         self.assertEqual('"foo"=\'abc\'', str(c1))
-        self.assertEqual('"t0"."foo"=\'abc\'', str(c2))
+        self.assertEqual('"crit"."foo"=\'abc\'', str(c2))
 
     def test__criterion_eq_date(self):
         c1 = Field('foo') == date(2000, 1, 1)
         c2 = Field('foo', table=self.t).eq(date(2000, 1, 1))
 
         self.assertEqual('"foo"=\'2000-01-01\'', str(c1))
-        self.assertEqual('"t0"."foo"=\'2000-01-01\'', str(c2))
+        self.assertEqual('"crit"."foo"=\'2000-01-01\'', str(c2))
 
     def test__criterion_eq_datetime(self):
         c1 = Field('foo') == datetime(2000, 1, 1, 12, 30, 55)
         c2 = Field('foo', table=self.t).eq(datetime(2000, 1, 1, 12, 30, 55))
 
         self.assertEqual('"foo"=\'2000-01-01T12:30:55\'', str(c1))
-        self.assertEqual('"t0"."foo"=\'2000-01-01T12:30:55\'', str(c2))
+        self.assertEqual('"crit"."foo"=\'2000-01-01T12:30:55\'', str(c2))
 
     def test__criterion_eq_right(self):
         c1 = 1 == Field('foo')
         c2 = -1 == Field('foo', table=self.t)
 
         self.assertEqual('"foo"=1', str(c1))
-        self.assertEqual('"t0"."foo"=-1', str(c2))
+        self.assertEqual('"crit"."foo"=-1', str(c2))
 
     def test__criterion_is_null(self):
         c1 = Field('foo').isnull()
         c2 = Field('foo', table=self.t).isnull()
 
         self.assertEqual('"foo" IS NULL', str(c1))
-        self.assertEqual('"t0"."foo" IS NULL', str(c2))
+        self.assertEqual('"crit"."foo" IS NULL', str(c2))
 
     def test__criterion_is_not_null(self):
         c1 = Field('foo').notnull()
         c2 = Field('foo', table=self.t).notnull()
 
         self.assertEqual('"foo" IS NOT NULL', str(c1))
-        self.assertEqual('"t0"."foo" IS NOT NULL', str(c2))
+        self.assertEqual('"crit"."foo" IS NOT NULL', str(c2))
 
     def test__criterion_ne_number(self):
         c1 = Field('foo') != 1
@@ -88,7 +87,7 @@ class CriterionTests(unittest.TestCase):
         c3 = Field('foo') != -1
 
         self.assertEqual('"foo"<>1', str(c1))
-        self.assertEqual('"t0"."foo"<>0', str(c2))
+        self.assertEqual('"crit"."foo"<>0', str(c2))
         self.assertEqual('"foo"<>-1', str(c3))
 
     def test__criterion_ne_str(self):
@@ -96,28 +95,28 @@ class CriterionTests(unittest.TestCase):
         c2 = Field('foo', table=self.t).ne('abc')
 
         self.assertEqual('"foo"<>\'abc\'', str(c1))
-        self.assertEqual('"t0"."foo"<>\'abc\'', str(c2))
+        self.assertEqual('"crit"."foo"<>\'abc\'', str(c2))
 
     def test__criterion_ne_date(self):
         c1 = Field('foo') != date(2000, 1, 1)
         c2 = Field('foo', table=self.t).ne(date(2000, 1, 1))
 
         self.assertEqual('"foo"<>\'2000-01-01\'', str(c1))
-        self.assertEqual('"t0"."foo"<>\'2000-01-01\'', str(c2))
+        self.assertEqual('"crit"."foo"<>\'2000-01-01\'', str(c2))
 
     def test__criterion_ne_datetime(self):
         c1 = Field('foo') != datetime(2000, 1, 1, 12, 30, 55)
         c2 = Field('foo', table=self.t).ne(datetime(2000, 1, 1, 12, 30, 55))
 
         self.assertEqual('"foo"<>\'2000-01-01T12:30:55\'', str(c1))
-        self.assertEqual('"t0"."foo"<>\'2000-01-01T12:30:55\'', str(c2))
+        self.assertEqual('"crit"."foo"<>\'2000-01-01T12:30:55\'', str(c2))
 
     def test__criterion_ne_right(self):
         c1 = 1 != Field('foo')
         c2 = -1 != Field('foo', table=self.t)
 
         self.assertEqual('"foo"<>1', str(c1))
-        self.assertEqual('"t0"."foo"<>-1', str(c2))
+        self.assertEqual('"crit"."foo"<>-1', str(c2))
 
     def test__criterion_lt_number(self):
         c1 = Field('foo') < 1
@@ -125,7 +124,7 @@ class CriterionTests(unittest.TestCase):
         c3 = Field('foo') < -1
 
         self.assertEqual('"foo"<1', str(c1))
-        self.assertEqual('"t0"."foo"<0', str(c2))
+        self.assertEqual('"crit"."foo"<0', str(c2))
         self.assertEqual('"foo"<-1', str(c3))
 
     def test__criterion_lt_date(self):
@@ -133,21 +132,21 @@ class CriterionTests(unittest.TestCase):
         c2 = Field('foo', table=self.t).lt(date(2000, 1, 1))
 
         self.assertEqual('"foo"<\'2000-01-01\'', str(c1))
-        self.assertEqual('"t0"."foo"<\'2000-01-01\'', str(c2))
+        self.assertEqual('"crit"."foo"<\'2000-01-01\'', str(c2))
 
     def test__criterion_lt_datetime(self):
         c1 = Field('foo') < datetime(2000, 1, 1, 12, 30, 55)
         c2 = Field('foo', table=self.t).lt(datetime(2000, 1, 1, 12, 30, 55))
 
         self.assertEqual('"foo"<\'2000-01-01T12:30:55\'', str(c1))
-        self.assertEqual('"t0"."foo"<\'2000-01-01T12:30:55\'', str(c2))
+        self.assertEqual('"crit"."foo"<\'2000-01-01T12:30:55\'', str(c2))
 
     def test__criterion_lt_right(self):
         c1 = 1 > Field('foo')
         c2 = -1 > Field('foo', table=self.t)
 
         self.assertEqual('"foo"<1', str(c1))
-        self.assertEqual('"t0"."foo"<-1', str(c2))
+        self.assertEqual('"crit"."foo"<-1', str(c2))
 
     def test__criterion_gt_number(self):
         c1 = Field('foo') > 1
@@ -155,7 +154,7 @@ class CriterionTests(unittest.TestCase):
         c3 = Field('foo') > -1
 
         self.assertEqual('"foo">1', str(c1))
-        self.assertEqual('"t0"."foo">0', str(c2))
+        self.assertEqual('"crit"."foo">0', str(c2))
         self.assertEqual('"foo">-1', str(c3))
 
     def test__criterion_gt_date(self):
@@ -163,21 +162,21 @@ class CriterionTests(unittest.TestCase):
         c2 = Field('foo', table=self.t).gt(date(2000, 1, 1))
 
         self.assertEqual('"foo">\'2000-01-01\'', str(c1))
-        self.assertEqual('"t0"."foo">\'2000-01-01\'', str(c2))
+        self.assertEqual('"crit"."foo">\'2000-01-01\'', str(c2))
 
     def test__criterion_gt_datetime(self):
         c1 = Field('foo') > datetime(2000, 1, 1, 12, 30, 55)
         c2 = Field('foo', table=self.t).gt(datetime(2000, 1, 1, 12, 30, 55))
 
         self.assertEqual('"foo">\'2000-01-01T12:30:55\'', str(c1))
-        self.assertEqual('"t0"."foo">\'2000-01-01T12:30:55\'', str(c2))
+        self.assertEqual('"crit"."foo">\'2000-01-01T12:30:55\'', str(c2))
 
     def test__criterion_gt_right(self):
         c1 = 1 < Field('foo')
         c2 = -1 < Field('foo', table=self.t)
 
         self.assertEqual('"foo">1', str(c1))
-        self.assertEqual('"t0"."foo">-1', str(c2))
+        self.assertEqual('"crit"."foo">-1', str(c2))
 
     def test__criterion_lte_number(self):
         c1 = Field('foo') <= 1
@@ -185,7 +184,7 @@ class CriterionTests(unittest.TestCase):
         c3 = Field('foo') <= -1
 
         self.assertEqual('"foo"<=1', str(c1))
-        self.assertEqual('"t0"."foo"<=0', str(c2))
+        self.assertEqual('"crit"."foo"<=0', str(c2))
         self.assertEqual('"foo"<=-1', str(c3))
 
     def test__criterion_lte_date(self):
@@ -193,21 +192,21 @@ class CriterionTests(unittest.TestCase):
         c2 = Field('foo', table=self.t).lte(date(2000, 1, 1))
 
         self.assertEqual('"foo"<=\'2000-01-01\'', str(c1))
-        self.assertEqual('"t0"."foo"<=\'2000-01-01\'', str(c2))
+        self.assertEqual('"crit"."foo"<=\'2000-01-01\'', str(c2))
 
     def test__criterion_lte_datetime(self):
         c1 = Field('foo') <= datetime(2000, 1, 1, 12, 30, 55)
         c2 = Field('foo', table=self.t).lte(datetime(2000, 1, 1, 12, 30, 55))
 
         self.assertEqual('"foo"<=\'2000-01-01T12:30:55\'', str(c1))
-        self.assertEqual('"t0"."foo"<=\'2000-01-01T12:30:55\'', str(c2))
+        self.assertEqual('"crit"."foo"<=\'2000-01-01T12:30:55\'', str(c2))
 
     def test__criterion_lte_right(self):
         c1 = 1 >= Field('foo')
         c2 = -1 >= Field('foo', table=self.t)
 
         self.assertEqual('"foo"<=1', str(c1))
-        self.assertEqual('"t0"."foo"<=-1', str(c2))
+        self.assertEqual('"crit"."foo"<=-1', str(c2))
 
     def test__criterion_gte_number(self):
         c1 = Field('foo') >= 1
@@ -215,7 +214,7 @@ class CriterionTests(unittest.TestCase):
         c3 = Field('foo') >= -1
 
         self.assertEqual('"foo">=1', str(c1))
-        self.assertEqual('"t0"."foo">=0', str(c2))
+        self.assertEqual('"crit"."foo">=0', str(c2))
         self.assertEqual('"foo">=-1', str(c3))
 
     def test__criterion_gte_date(self):
@@ -223,26 +222,25 @@ class CriterionTests(unittest.TestCase):
         c2 = Field('foo', table=self.t).gte(date(2000, 1, 1))
 
         self.assertEqual('"foo">=\'2000-01-01\'', str(c1))
-        self.assertEqual('"t0"."foo">=\'2000-01-01\'', str(c2))
+        self.assertEqual('"crit"."foo">=\'2000-01-01\'', str(c2))
 
     def test__criterion_gte_datetime(self):
         c1 = Field('foo') >= datetime(2000, 1, 1, 12, 30, 55)
         c2 = Field('foo', table=self.t).gte(datetime(2000, 1, 1, 12, 30, 55))
 
         self.assertEqual('"foo">=\'2000-01-01T12:30:55\'', str(c1))
-        self.assertEqual('"t0"."foo">=\'2000-01-01T12:30:55\'', str(c2))
+        self.assertEqual('"crit"."foo">=\'2000-01-01T12:30:55\'', str(c2))
 
     def test__criterion_gte_right(self):
         c1 = 1 <= Field('foo')
         c2 = -1 <= Field('foo', table=self.t)
 
         self.assertEqual('"foo">=1', str(c1))
-        self.assertEqual('"t0"."foo">=-1', str(c2))
+        self.assertEqual('"crit"."foo">=-1', str(c2))
 
 
 class BetweenTests(unittest.TestCase):
-    t = Table('abc')
-    t.alias = 't0'
+    t = Table('abc', alias = 'btw')
 
     def test__between_number(self):
         c1 = Field('foo').between(0, 1)
@@ -250,7 +248,7 @@ class BetweenTests(unittest.TestCase):
         c3 = Field('foo')[0:1]
 
         self.assertEqual('"foo" BETWEEN 0 AND 1', str(c1))
-        self.assertEqual('"t0"."foo" BETWEEN 0 AND 1', str(c2))
+        self.assertEqual('"btw"."foo" BETWEEN 0 AND 1', str(c2))
         self.assertEqual('"foo" BETWEEN 0 AND 1', str(c3))
 
     def test__between_date(self):
@@ -259,7 +257,7 @@ class BetweenTests(unittest.TestCase):
         c3 = Field('foo')[date(2000, 1, 1):date(2000, 12, 31)]
 
         self.assertEqual('"foo" BETWEEN \'2000-01-01\' AND \'2000-12-31\'', str(c1))
-        self.assertEqual('"t0"."foo" BETWEEN \'2000-01-01\' AND \'2000-12-31\'', str(c2))
+        self.assertEqual('"btw"."foo" BETWEEN \'2000-01-01\' AND \'2000-12-31\'', str(c2))
         self.assertEqual('"foo" BETWEEN \'2000-01-01\' AND \'2000-12-31\'', str(c3))
 
     def test__between_datetime(self):
@@ -268,7 +266,7 @@ class BetweenTests(unittest.TestCase):
         c3 = Field('foo')[datetime(2000, 1, 1, 0, 0, 0):datetime(2000, 12, 31, 23, 59, 59)]
 
         self.assertEqual('"foo" BETWEEN \'2000-01-01T00:00:00\' AND \'2000-12-31T23:59:59\'', str(c1))
-        self.assertEqual('"t0"."foo" BETWEEN \'2000-01-01T00:00:00\' AND \'2000-12-31T23:59:59\'', str(c2))
+        self.assertEqual('"btw"."foo" BETWEEN \'2000-01-01T00:00:00\' AND \'2000-12-31T23:59:59\'', str(c2))
         self.assertEqual('"foo" BETWEEN \'2000-01-01T00:00:00\' AND \'2000-12-31T23:59:59\'', str(c3))
 
     def test__function_between(self):
@@ -277,7 +275,7 @@ class BetweenTests(unittest.TestCase):
         c3 = fn.Coalesce(Field('foo', table=self.t), 0).between(0, 1)
 
         self.assertEqual('COALESCE("foo",0) BETWEEN 0 AND 1', str(c1))
-        self.assertEqual('COALESCE("t0"."foo",0) BETWEEN 0 AND 1', str(c2))
+        self.assertEqual('COALESCE("btw"."foo",0) BETWEEN 0 AND 1', str(c2))
 
     def test_get_item_only_works_with_slice(self):
         with self.assertRaises(TypeError):
@@ -291,69 +289,67 @@ class BetweenTests(unittest.TestCase):
 
 
 class IsInTests(unittest.TestCase):
-    t = Table('abc')
-    t.alias = 't0'
+    t = Table('abc',alias = 'isin')
 
     def test__in_number(self):
         c1 = Field('foo').isin([0, 1])
         c2 = Field('foo', table=self.t).isin([0, 1])
 
         self.assertEqual('"foo" IN (0,1)', str(c1))
-        self.assertEqual('"t0"."foo" IN (0,1)', str(c2))
+        self.assertEqual('"isin"."foo" IN (0,1)', str(c2))
 
     def test__in_character(self):
         c1 = Field('foo').isin(['a', 'b'])
         c2 = Field('foo', table=self.t).isin(['a', 'b'])
 
         self.assertEqual('"foo" IN (\'a\',\'b\')', str(c1))
-        self.assertEqual('"t0"."foo" IN (\'a\',\'b\')', str(c2))
+        self.assertEqual('"isin"."foo" IN (\'a\',\'b\')', str(c2))
 
     def test__in_date(self):
         c1 = Field('foo').isin([date(2000, 1, 1), date(2000, 12, 31)])
         c2 = Field('foo', table=self.t).isin([date(2000, 1, 1), date(2000, 12, 31)])
 
         self.assertEqual('"foo" IN (\'2000-01-01\',\'2000-12-31\')', str(c1))
-        self.assertEqual('"t0"."foo" IN (\'2000-01-01\',\'2000-12-31\')', str(c2))
+        self.assertEqual('"isin"."foo" IN (\'2000-01-01\',\'2000-12-31\')', str(c2))
 
     def test__in_datetime(self):
         c1 = Field('foo').isin([datetime(2000, 1, 1, 0, 0, 0), datetime(2000, 12, 31, 23, 59, 59)])
         c2 = Field('foo', table=self.t).isin([datetime(2000, 1, 1, 0, 0, 0), datetime(2000, 12, 31, 23, 59, 59)])
 
         self.assertEqual('"foo" IN (\'2000-01-01T00:00:00\',\'2000-12-31T23:59:59\')', str(c1))
-        self.assertEqual('"t0"."foo" IN (\'2000-01-01T00:00:00\',\'2000-12-31T23:59:59\')', str(c2))
+        self.assertEqual('"isin"."foo" IN (\'2000-01-01T00:00:00\',\'2000-12-31T23:59:59\')', str(c2))
 
     def test__function_isin(self):
         c1 = fn.Coalesce(Field('foo'), 0).isin([0, 1])
         c2 = fn.Coalesce(Field('foo', table=self.t), 0).isin([0, 1])
 
         self.assertEqual('COALESCE("foo",0) IN (0,1)', str(c1))
-        self.assertEqual('COALESCE("t0"."foo",0) IN (0,1)', str(c2))
+        self.assertEqual('COALESCE("isin"."foo",0) IN (0,1)', str(c2))
 
 
 class ComplexCriterionTests(unittest.TestCase):
-    t0, t1 = Table('abc'), Table('efg')
-    t0.alias, t1.alias = 't0', 't1'
+    table_abc, table_efg = Table('abc', alias='cx0'), Table('efg', alias='cx1')
 
     def test__and(self):
         c1 = (Field('foo') == 1) & (Field('bar') == 2)
-        c2 = (Field('foo', table=self.t0) == 1) & (Field('bar', table=self.t1) == 2)
+        c2 = (Field('foo', table=self.table_abc) == 1) & (Field('bar', table=self.table_efg) == 2)
 
         self.assertEqual('"foo"=1 AND "bar"=2', str(c1))
-        self.assertEqual('"t0"."foo"=1 AND "t1"."bar"=2', str(c2))
+        self.assertEqual('"cx0"."foo"=1 AND "cx1"."bar"=2', str(c2))
 
     def test__or(self):
         c1 = (Field('foo') == 1) | (Field('bar') == 2)
-        c2 = (Field('foo', table=self.t0) == 1) | (Field('bar', table=self.t1) == 2)
+        c2 = (Field('foo', table=self.table_abc) == 1) | (Field('bar', table=self.table_efg) == 2)
 
         self.assertEqual('"foo"=1 OR "bar"=2', str(c1))
-        self.assertEqual('"t0"."foo"=1 OR "t1"."bar"=2', str(c2))
+        self.assertEqual('"cx0"."foo"=1 OR "cx1"."bar"=2', str(c2))
 
     def test__xor(self):
         c1 = (Field('foo') == 1) ^ (Field('bar') == 2)
-        c2 = (Field('foo', table=self.t0) == 1) ^ (Field('bar', table=self.t1) == 2)
+        c2 = (Field('foo', table=self.table_abc) == 1) ^ (Field('bar', table=self.table_efg) == 2)
 
         self.assertEqual('"foo"=1 XOR "bar"=2', str(c1))
-        self.assertEqual('"t0"."foo"=1 XOR "t1"."bar"=2', str(c2))
+        self.assertEqual('"cx0"."foo"=1 XOR "cx1"."bar"=2', str(c2))
 
     def test__nested__and(self):
         c = (Field('foo') == 1) & (Field('bar') == 2) & (Field('buz') == 3)
@@ -377,51 +373,50 @@ class ComplexCriterionTests(unittest.TestCase):
 
 
 class CriterionOperationsTests(unittest.TestCase):
-    t0, t1 = Table('abc'), Table('efg')
-    t0.alias, t1.alias = 't0', 't1'
+    table_abc, table_efg = Table('abc', alias='cx0'), Table('efg', alias='cx1')
 
     def test_field_for_table(self):
-        f = self.t0.foo.for_(self.t1)
+        f = self.table_abc.foo.for_(self.table_efg)
 
-        self.assertEqual('"t1"."foo"', str(f))
+        self.assertEqual('"cx1"."foo"', str(f))
 
     def test_arithmeticfunction_for_table(self):
-        f = (self.t0.foo + self.t0.bar).for_(self.t1)
+        f = (self.table_abc.foo + self.table_abc.bar).for_(self.table_efg)
 
-        self.assertEqual('"t1"."foo"+"t1"."bar"', str(f))
+        self.assertEqual('"cx1"."foo"+"cx1"."bar"', str(f))
 
     def test_criterion_for_table(self):
-        f = (self.t0.foo < self.t0.bar).for_(self.t1)
+        f = (self.table_abc.foo < self.table_abc.bar).for_(self.table_efg)
 
-        self.assertEqual('"t1"."foo"<"t1"."bar"', str(f))
+        self.assertEqual('"cx1"."foo"<"cx1"."bar"', str(f))
 
     def test_complexcriterion_for_table(self):
-        f = ((self.t0.foo < self.t0.bar) & (self.t0.fiz > self.t0.buz)).for_(self.t1)
+        f = ((self.table_abc.foo < self.table_abc.bar) & (self.table_abc.fiz > self.table_abc.buz)).for_(self.table_efg)
 
-        self.assertEqual('"t1"."foo"<"t1"."bar" AND "t1"."fiz">"t1"."buz"', str(f))
+        self.assertEqual('"cx1"."foo"<"cx1"."bar" AND "cx1"."fiz">"cx1"."buz"', str(f))
 
     def test_function_with_only_fields_for_table(self):
         f = fn.Sum(self.
-                   t0.foo).for_(self.t1)
+                   table_abc.foo).for_(self.table_efg)
 
-        self.assertEqual('SUM("t1"."foo")', str(f))
+        self.assertEqual('SUM("cx1"."foo")', str(f))
 
     def test_function_with_values_and_fields_for_table(self):
-        f = Mod(self.t0.foo, 2).for_(self.t1)
+        f = Mod(self.table_abc.foo, 2).for_(self.table_efg)
 
-        self.assertEqual('MOD("t1"."foo",2)', str(f))
+        self.assertEqual('MOD("cx1"."foo",2)', str(f))
 
     def test_betweencriterion_for_table(self):
-        f = self.t0.foo[0:1].for_(self.t1)
+        f = self.table_abc.foo[0:1].for_(self.table_efg)
 
-        self.assertEqual('"t1"."foo" BETWEEN 0 AND 1', str(f))
+        self.assertEqual('"cx1"."foo" BETWEEN 0 AND 1', str(f))
 
     def test_nullcriterion_for_table(self):
-        f = self.t0.foo.isnull().for_(self.t1)
+        f = self.table_abc.foo.isnull().for_(self.table_efg)
 
-        self.assertEqual('"t1"."foo" IS NULL', str(f))
+        self.assertEqual('"cx1"."foo" IS NULL', str(f))
 
     def test_notnullcriterion_for_table(self):
-        f = self.t0.foo.notnull().for_(self.t1)
+        f = self.table_abc.foo.notnull().for_(self.table_efg)
 
-        self.assertEqual('"t1"."foo" IS NOT NULL', str(f))
+        self.assertEqual('"cx1"."foo" IS NOT NULL', str(f))
diff --git a/pypika/tests/test_inserts.py b/pypika/tests/test_inserts.py
index 508f7cf..d7646f2 100644
--- a/pypika/tests/test_inserts.py
+++ b/pypika/tests/test_inserts.py
@@ -124,8 +124,8 @@ class InsertSelectFromTests(unittest.TestCase):
         )
 
         self.assertEqual('INSERT INTO "abc" ("c1","c2","c3","c4") '
-                         'SELECT "t0"."foo","t0"."bar","t1"."fiz","t1"."buz" FROM "efg" "t0" '
-                         'JOIN "hij" "t1" ON "t0"."id"="t1"."abc_id"', str(query))
+                         'SELECT "efg"."foo","efg"."bar","hij"."fiz","hij"."buz" FROM "efg" '
+                         'JOIN "hij" ON "efg"."id"="hij"."abc_id"', str(query))
 
 
 class SelectIntoTests(unittest.TestCase):
@@ -152,6 +152,6 @@ class SelectIntoTests(unittest.TestCase):
             self.table_hij.fiz, self.table_hij.buz
         ).into(self.table_efg)
 
-        self.assertEqual('SELECT "t0"."foo","t0"."bar","t1"."fiz","t1"."buz" '
-                         'INTO "efg" FROM "abc" "t0" '
-                         'JOIN "hij" "t1" ON "t0"."id"="t1"."abc_id"', str(query))
+        self.assertEqual('SELECT "abc"."foo","abc"."bar","hij"."fiz","hij"."buz" '
+                         'INTO "efg" FROM "abc" '
+                         'JOIN "hij" ON "abc"."id"="hij"."abc_id"', str(query))
diff --git a/pypika/tests/test_joins.py b/pypika/tests/test_joins.py
index 38fca98..fae4511 100644
--- a/pypika/tests/test_joins.py
+++ b/pypika/tests/test_joins.py
@@ -8,19 +8,19 @@ __email__ = "theys@kayak.com"
 
 
 class JoinTypeTests(unittest.TestCase):
-    table0, table1, t2 = Tables('abc', 'efg', 'hij')
+    table0, table1, hij = Tables('abc', 'efg', 'hij')
 
     def test_left_join(self):
         query = Query.from_(self.table0).join(self.table1, how=JoinType.left).on(
             self.table0.foo == self.table1.bar).select('*')
 
-        self.assertEqual('SELECT * FROM "abc" "t0" LEFT JOIN "efg" "t1" ON "t0"."foo"="t1"."bar"', str(query))
+        self.assertEqual('SELECT * FROM "abc" LEFT JOIN "efg" ON "abc"."foo"="efg"."bar"', str(query))
 
     def test_right_join(self):
         q = Query.from_(self.table0).join(self.table1, how=JoinType.right).on(
             self.table0.foo == self.table1.bar).select('*')
 
-        self.assertEqual('SELECT * FROM "abc" "t0" RIGHT JOIN "efg" "t1" ON "t0"."foo"="t1"."bar"', str(q))
+        self.assertEqual('SELECT * FROM "abc" RIGHT JOIN "efg" ON "abc"."foo"="efg"."bar"', str(q))
 
     def test_inner_join(self):
         query = Query.from_(self.table0).join(self.table1).on(
@@ -28,21 +28,21 @@ class JoinTypeTests(unittest.TestCase):
         query_explicit = Query.from_(self.table0).join(self.table1, how=JoinType.inner).on(
             self.table0.foo == self.table1.bar).select('*')
 
-        self.assertEqual('SELECT * FROM "abc" "t0" JOIN "efg" "t1" ON "t0"."foo"="t1"."bar"', str(query))
-        self.assertEqual('SELECT * FROM "abc" "t0" JOIN "efg" "t1" ON "t0"."foo"="t1"."bar"', str(query_explicit))
+        self.assertEqual('SELECT * FROM "abc" JOIN "efg" ON "abc"."foo"="efg"."bar"', str(query))
+        self.assertEqual('SELECT * FROM "abc" JOIN "efg" ON "abc"."foo"="efg"."bar"', str(query_explicit))
 
     def test_outer_join(self):
         query = Query.from_(self.table0).join(self.table1, how=JoinType.outer).on(
             self.table0.foo == self.table1.bar).select('*')
 
-        self.assertEqual('SELECT * FROM "abc" "t0" OUTER JOIN "efg" "t1" ON "t0"."foo"="t1"."bar"', str(query))
+        self.assertEqual('SELECT * FROM "abc" OUTER JOIN "efg" ON "abc"."foo"="efg"."bar"', str(query))
 
     def test_join_arithmetic_field(self):
         q = Query.from_(self.table0).join(self.table1).on(
             self.table0.dt == (self.table1.dt - Interval(weeks=1))).select('*')
 
-        self.assertEqual('SELECT * FROM "abc" "t0" '
-                         'JOIN "efg" "t1" ON "t0"."dt"="t1"."dt"-INTERVAL \'1 WEEK\'', str(q))
+        self.assertEqual('SELECT * FROM "abc" '
+                         'JOIN "efg" ON "abc"."dt"="efg"."dt"-INTERVAL \'1 WEEK\'', str(q))
 
     def test_join_with_arithmetic_function_in_select(self):
         q = Query.from_(
@@ -51,180 +51,194 @@ class JoinTypeTests(unittest.TestCase):
             self.table0.dt == (self.table1.dt - Interval(weeks=1))
         ).select(self.table0.fiz - self.table0.buz, self.table1.star)
 
-        self.assertEqual('SELECT "t0"."fiz"-"t0"."buz","t1".* FROM "abc" "t0" '
-                         'JOIN "efg" "t1" ON "t0"."dt"="t1"."dt"-INTERVAL \'1 WEEK\'', str(q))
+        self.assertEqual('SELECT "abc"."fiz"-"abc"."buz","efg".* FROM "abc" '
+                         'JOIN "efg" ON "abc"."dt"="efg"."dt"-INTERVAL \'1 WEEK\'', str(q))
 
     def test_join_on_complex_criteria(self):
         q = Query.from_(self.table0).join(self.table1, how=JoinType.right).on(
             (self.table0.foo == self.table1.fiz) & (self.table0.bar == self.table1.buz)
         ).select('*')
 
-        self.assertEqual('SELECT * FROM "abc" "t0" '
-                         'RIGHT JOIN "efg" "t1" ON "t0"."foo"="t1"."fiz" AND "t0"."bar"="t1"."buz"', str(q))
+        self.assertEqual('SELECT * FROM "abc" '
+                         'RIGHT JOIN "efg" ON "abc"."foo"="efg"."fiz" AND "abc"."bar"="efg"."buz"', str(q))
 
 
 class JoinBehaviorTests(unittest.TestCase):
-    table0, table1, table2, table3 = Tables('abc', 'efg', 'hij', 'klm')
+    table_abc, table_efg, table_hij, table_klm = Tables('abc', 'efg', 'hij', 'klm')
 
     def test_select__ordered_select_clauses(self):
-        q = Query.from_(self.table0).join(self.table1).on(self.table0.foo == self.table1.bar).select(
-            self.table0.baz,
-            self.table1.buz,
-            self.table0.fiz,
-            self.table1.bam,
+        q = Query.from_(self.table_abc).join(self.table_efg).on(self.table_abc.foo == self.table_efg.bar).select(
+            self.table_abc.baz,
+            self.table_efg.buz,
+            self.table_abc.fiz,
+            self.table_efg.bam,
         )
 
-        self.assertEqual('SELECT "t0"."baz","t1"."buz","t0"."fiz","t1"."bam" FROM "abc" "t0" '
-                         'JOIN "efg" "t1" ON "t0"."foo"="t1"."bar"', str(q))
+        self.assertEqual('SELECT "abc"."baz","efg"."buz","abc"."fiz","efg"."bam" FROM "abc" '
+                         'JOIN "efg" ON "abc"."foo"="efg"."bar"', str(q))
 
     def test_select__star_for_table(self):
-        q = Query.from_(self.table0).join(self.table1).on(
-            self.table0.foo == self.table1.bar
-        ).join(self.table2).on(
-            self.table0.buz == self.table2.bam
-        ).select(self.table0.star).select(self.table1.star).select(self.table2.star)
+        q = Query.from_(self.table_abc).join(self.table_efg).on(
+            self.table_abc.foo == self.table_efg.bar
+        ).join(self.table_hij).on(
+            self.table_abc.buz == self.table_hij.bam
+        ).select(self.table_abc.star).select(self.table_efg.star).select(self.table_hij.star)
 
-        self.assertEqual('SELECT "t0".*,"t1".*,"t2".* FROM "abc" "t0" '
-                         'JOIN "efg" "t1" ON "t0"."foo"="t1"."bar" '
-                         'JOIN "hij" "t2" ON "t0"."buz"="t2"."bam"', str(q))
+        self.assertEqual('SELECT "abc".*,"efg".*,"hij".* FROM "abc" '
+                         'JOIN "efg" ON "abc"."foo"="efg"."bar" '
+                         'JOIN "hij" ON "abc"."buz"="hij"."bam"', str(q))
 
     def test_select__star_for_table__replacement(self):
-        q = Query.from_(self.table0).join(self.table1).on(
-            self.table0.foo == self.table1.bar
-        ).join(self.table2).on(
-            self.table0.buz == self.table2.bam
+        q = Query.from_(self.table_abc).join(self.table_efg).on(
+            self.table_abc.foo == self.table_efg.bar
+        ).join(self.table_hij).on(
+            self.table_abc.buz == self.table_hij.bam
         ).select(
-            self.table0.foo, self.table1.bar, self.table2.bam
+            self.table_abc.foo, self.table_efg.bar, self.table_hij.bam
         ).select(
-            self.table0.star, self.table1.star, self.table2.star
+            self.table_abc.star, self.table_efg.star, self.table_hij.star
         )
 
-        self.assertEqual('SELECT "t0".*,"t1".*,"t2".* FROM "abc" "t0" '
-                         'JOIN "efg" "t1" ON "t0"."foo"="t1"."bar" '
-                         'JOIN "hij" "t2" ON "t0"."buz"="t2"."bam"', str(q))
+        self.assertEqual('SELECT "abc".*,"efg".*,"hij".* FROM "abc" '
+                         'JOIN "efg" ON "abc"."foo"="efg"."bar" '
+                         'JOIN "hij" ON "abc"."buz"="hij"."bam"', str(q))
 
     def test_select_fields_with_where(self):
-        q = Query.from_(self.table0).join(
-            self.table1).on(self.table0.foo == self.table1.bar
-                            ).join(
-            self.table2).on(self.table0.buz == self.table2.bam
-                            ).select(
-            self.table0.foo, self.table1.bar, self.table2.bam
-        ).where(self.table0.foo > 1).where(self.table1.bar != 2)
-
-        self.assertEqual('SELECT "t0"."foo","t1"."bar","t2"."bam" FROM "abc" "t0" '
-                         'JOIN "efg" "t1" ON "t0"."foo"="t1"."bar" '
-                         'JOIN "hij" "t2" ON "t0"."buz"="t2"."bam" '
-                         'WHERE "t0"."foo">1 AND "t1"."bar"<>2', str(q))
+        q = Query.from_(self.table_abc).join(
+            self.table_efg).on(self.table_abc.foo == self.table_efg.bar
+                               ).join(
+            self.table_hij).on(self.table_abc.buz == self.table_hij.bam
+                               ).select(
+            self.table_abc.foo, self.table_efg.bar, self.table_hij.bam
+        ).where(self.table_abc.foo > 1).where(self.table_efg.bar != 2)
+
+        self.assertEqual('SELECT "abc"."foo","efg"."bar","hij"."bam" FROM "abc" '
+                         'JOIN "efg" ON "abc"."foo"="efg"."bar" '
+                         'JOIN "hij" ON "abc"."buz"="hij"."bam" '
+                         'WHERE "abc"."foo">1 AND "efg"."bar"<>2', str(q))
 
     def test_require_condition(self):
         with self.assertRaises(JoinException):
-            Query.from_(self.table0).join(self.table1).on(None)
+            Query.from_(self.table_abc).join(self.table_efg).on(None)
 
     def test_require_condition_with_both_tables(self):
         with self.assertRaises(JoinException):
-            Query.from_(self.table0).join(self.table1).on(self.table0.foo == self.table2.bar)
+            Query.from_(self.table_abc).join(self.table_efg).on(self.table_abc.foo == self.table_hij.bar)
 
         with self.assertRaises(JoinException):
-            Query.from_(self.table0).join(self.table1).on(self.table2.foo == self.table1.bar)
+            Query.from_(self.table_abc).join(self.table_efg).on(self.table_hij.foo == self.table_efg.bar)
 
         with self.assertRaises(JoinException):
-            Query.from_(self.table0).join(self.table1).on(self.table2.foo == self.table3.bar)
+            Query.from_(self.table_abc).join(self.table_efg).on(self.table_hij.foo == self.table_klm.bar)
 
     def test_join_same_table(self):
         table1 = Table('abc')
-        q = Query.from_(self.table0).join(table1).on(self.table0.foo == table1.bar).select(self.table0.foo, table1.buz)
+        table2 = Table('abc')
+        q = Query.from_(table1).join(table2).on(table1.foo == table2.bar).select(table1.foo, table2.buz)
+
+        self.assertEqual('SELECT "abc"."foo","abc2"."buz" FROM "abc" '
+                         'JOIN "abc" "abc2" ON "abc"."foo"="abc2"."bar"', str(q))
 
-        self.assertEqual('SELECT "t0"."foo","t1"."buz" FROM "abc" "t0" '
-                         'JOIN "abc" "t1" ON "t0"."foo"="t1"."bar"', str(q))
+    def test_join_same_table_with_prefixes(self):
+        table1 = Table('abc', alias='x')
+        table2 = Table('abc', alias='y')
+        q = Query.from_(table1).join(table2).on(table1.foo == table2.bar).select(table1.foo, table2.buz)
+
+        self.assertEqual('SELECT "x"."foo","y"."buz" FROM "abc" "x" '
+                         'JOIN "abc" "y" ON "x"."foo"="y"."bar"', str(q))
 
     def test_join_table_twice(self):
-        table1, table2 = Tables('efg', 'efg')
-        q = Query.from_(self.table0).join(
-            table1).on(self.table0.foo == table1.bar
-                       ).join(
-            table2).on(self.table0.foo == table2.bam
-                       ).select(self.table0.foo, table1.fiz, table2.buz)
+        table1, table2 = Table('efg', alias='efg1'), Table('efg', alias='efg2')
+        q = Query.from_(self.table_abc) \
+            .join(table1).on(self.table_abc.foo == table1.bar) \
+            .join(table2).on(self.table_abc.foo == table2.bam) \
+            .select(self.table_abc.foo, table1.fiz, table2.buz)
 
-        self.assertEqual('SELECT "t0"."foo","t1"."fiz","t2"."buz" FROM "abc" "t0" '
-                         'JOIN "efg" "t1" ON "t0"."foo"="t1"."bar" '
-                         'JOIN "efg" "t2" ON "t0"."foo"="t2"."bam"', str(q))
+        self.assertEqual('SELECT "abc"."foo","efg1"."fiz","efg2"."buz" FROM "abc" '
+                         'JOIN "efg" "efg1" ON "abc"."foo"="efg1"."bar" '
+                         'JOIN "efg" "efg2" ON "abc"."foo"="efg2"."bam"', str(q))
 
     def test_select__fields_after_table_star(self):
-        q = Query.from_(self.table0).join(self.table1).on(self.table0.foo == self.table1.bar).select(self.table0.star,
-                                                                                                     self.table1.bar).select(
-            self.table0.foo)
+        q = Query.from_(self.table_abc).join(self.table_efg).on(self.table_abc.foo == self.table_efg.bar).select(
+            self.table_abc.star,
+            self.table_efg.bar).select(
+            self.table_abc.foo)
 
-        self.assertEqual('SELECT "t0".*,"t1"."bar" FROM "abc" "t0" JOIN "efg" "t1" ON "t0"."foo"="t1"."bar"',
+        self.assertEqual('SELECT "abc".*,"efg"."bar" FROM "abc" JOIN "efg" ON "abc"."foo"="efg"."bar"',
                          str(q))
 
     def test_fail_when_joining_unknown_type(self):
         with self.assertRaises(ValueError):
-            Query.from_(self.table0).join('this is a string')
+            Query.from_(self.table_abc).join('this is a string')
 
     def test_immutable__queries_after_join(self):
-        query1 = Query.from_(self.table0).select(self.table0.foo)
-        query2 = query1.join(self.table1).on(self.table0.foo == self.table1.bar).select(self.table1.buz)
+        query1 = Query.from_(self.table_abc).select(self.table_abc.foo)
+        query2 = query1.join(self.table_efg).on(self.table_abc.foo == self.table_efg.bar).select(self.table_efg.buz)
 
         self.assertEqual('SELECT "foo" FROM "abc"', str(query1))
-        self.assertEqual('SELECT "t0"."foo","t1"."buz" FROM "abc" "t0" '
-                         'JOIN "efg" "t1" ON "t0"."foo"="t1"."bar"', str(query2))
+        self.assertEqual('SELECT "abc"."foo","efg"."buz" FROM "abc" '
+                         'JOIN "efg" ON "abc"."foo"="efg"."bar"', str(query2))
 
     def test_immutable__tables(self):
-        query1 = Query.from_(self.table0).select(self.table0.foo)
-        query2 = Query.from_(self.table0).join(self.table1).on(self.table0.foo == self.table1.bar).select(
-            self.table0.foo,
-            self.table1.buz)
+        query1 = Query.from_(self.table_abc).select(self.table_abc.foo)
+        query2 = Query.from_(self.table_abc).join(self.table_efg).on(self.table_abc.foo == self.table_efg.bar).select(
+            self.table_abc.foo,
+            self.table_efg.buz)
 
-        self.assertEqual('SELECT "t0"."foo","t1"."buz" FROM "abc" "t0" '
-                         'JOIN "efg" "t1" ON "t0"."foo"="t1"."bar"', str(query2))
+        self.assertEqual('SELECT "abc"."foo","efg"."buz" FROM "abc" '
+                         'JOIN "efg" ON "abc"."foo"="efg"."bar"', str(query2))
         self.assertEqual('SELECT "foo" FROM "abc"', str(query1))
 
     def test_select_field_from_missing_table(self):
         with self.assertRaises(JoinException):
-            Query.from_(self.table0).select(self.table1.foo)
+            Query.from_(self.table_abc).select(self.table_efg.foo)
 
         with self.assertRaises(JoinException):
-            Query.from_(self.table0).where(self.table1.foo == 0)
+            Query.from_(self.table_abc).where(self.table_efg.foo == 0)
 
         with self.assertRaises(JoinException):
-            Query.from_(self.table0).where(fn.Sum(self.table1.foo) == 0)
+            Query.from_(self.table_abc).where(fn.Sum(self.table_efg.foo) == 0)
 
         with self.assertRaises(JoinException):
-            Query.from_(self.table0).select(fn.Sum(self.table0.bar * 2) + fn.Sum(self.table1.foo * 2))
+            Query.from_(self.table_abc).select(fn.Sum(self.table_abc.bar * 2) + fn.Sum(self.table_efg.foo * 2))
 
         with self.assertRaises(JoinException):
-            Query.from_(self.table0).groupby(self.table1.foo)
+            Query.from_(self.table_abc).groupby(self.table_efg.foo)
 
         with self.assertRaises(JoinException):
-            Query.from_(self.table0).groupby(self.table0.foo).having(self.table1.bar)
+            Query.from_(self.table_abc).groupby(self.table_abc.foo).having(self.table_efg.bar)
+
+    def test_ignore_table_references(self):
+        query = Query.from_(Table('abc')).select(Table('abc').foo)
+
+        self.assertEqual('SELECT "foo" FROM "abc"', str(query))
 
     def test_prefixes_added_to_groupby(self):
-        test_query = Query.from_(self.table0).join(self.table1).on(
-            self.table0.foo == self.table1.bar
-        ).select(self.table0.foo, fn.Sum(self.table1.buz)).groupby(self.table0.foo)
+        test_query = Query.from_(self.table_abc).join(self.table_efg).on(
+            self.table_abc.foo == self.table_efg.bar
+        ).select(self.table_abc.foo, fn.Sum(self.table_efg.buz)).groupby(self.table_abc.foo)
 
-        self.assertEqual('SELECT "t0"."foo",SUM("t1"."buz") FROM "abc" "t0" '
-                         'JOIN "efg" "t1" ON "t0"."foo"="t1"."bar" '
-                         'GROUP BY "t0"."foo"', str(test_query))
+        self.assertEqual('SELECT "abc"."foo",SUM("efg"."buz") FROM "abc" '
+                         'JOIN "efg" ON "abc"."foo"="efg"."bar" '
+                         'GROUP BY "abc"."foo"', str(test_query))
 
     def test_prefixes_added_to_orderby(self):
-        test_query = Query.from_(self.table0).join(self.table1).on(
-            self.table0.foo == self.table1.bar
-        ).select(self.table0.foo, self.table1.buz).orderby(self.table0.foo)
+        test_query = Query.from_(self.table_abc).join(self.table_efg).on(
+            self.table_abc.foo == self.table_efg.bar
+        ).select(self.table_abc.foo, self.table_efg.buz).orderby(self.table_abc.foo)
 
-        self.assertEqual('SELECT "t0"."foo","t1"."buz" FROM "abc" "t0" '
-                         'JOIN "efg" "t1" ON "t0"."foo"="t1"."bar" '
-                         'ORDER BY "t0"."foo"', str(test_query))
+        self.assertEqual('SELECT "abc"."foo","efg"."buz" FROM "abc" '
+                         'JOIN "efg" ON "abc"."foo"="efg"."bar" '
+                         'ORDER BY "abc"."foo"', str(test_query))
 
     def test_prefixes_added_to_function_in_orderby(self):
-        test_query = Query.from_(self.table0).join(self.table1).on(
-            self.table0.foo == self.table1.bar
-        ).select(self.table0.foo, self.table1.buz).orderby(fn.Date(self.table0.foo))
+        test_query = Query.from_(self.table_abc).join(self.table_efg).on(
+            self.table_abc.foo == self.table_efg.bar
+        ).select(self.table_abc.foo, self.table_efg.buz).orderby(fn.Date(self.table_abc.foo))
 
-        self.assertEqual('SELECT "t0"."foo","t1"."buz" FROM "abc" "t0" '
-                         'JOIN "efg" "t1" ON "t0"."foo"="t1"."bar" '
-                         'ORDER BY DATE("t0"."foo")', str(test_query))
+        self.assertEqual('SELECT "abc"."foo","efg"."buz" FROM "abc" '
+                         'JOIN "efg" ON "abc"."foo"="efg"."bar" '
+                         'ORDER BY DATE("abc"."foo")', str(test_query))
 
 
 class UnionTests(unittest.TestCase):
diff --git a/pypika/tests/test_selects.py b/pypika/tests/test_selects.py
index 8a433c3..5012a6f 100644
--- a/pypika/tests/test_selects.py
+++ b/pypika/tests/test_selects.py
@@ -180,50 +180,50 @@ class GroupByTests(unittest.TestCase):
 
 
 class HavingTests(unittest.TestCase):
-    t0, t1 = Tables('abc', 'efg')
+    table_abc, table_efg = Tables('abc', 'efg')
 
     def test_having_greater_than(self):
-        q = Query.from_(self.t0).select(
-            self.t0.foo, fn.Sum(self.t0.bar)
+        q = Query.from_(self.table_abc).select(
+            self.table_abc.foo, fn.Sum(self.table_abc.bar)
         ).groupby(
-            self.t0.foo
+            self.table_abc.foo
         ).having(
-            fn.Sum(self.t0.bar) > 1
+            fn.Sum(self.table_abc.bar) > 1
         )
 
         self.assertEqual('SELECT "foo",SUM("bar") FROM "abc" GROUP BY "foo" HAVING SUM("bar")>1', str(q))
 
     def test_having_and(self):
-        q = Query.from_(self.t0).select(
-            self.t0.foo, fn.Sum(self.t0.bar)
+        q = Query.from_(self.table_abc).select(
+            self.table_abc.foo, fn.Sum(self.table_abc.bar)
         ).groupby(
-            self.t0.foo
+            self.table_abc.foo
         ).having(
-            (fn.Sum(self.t0.bar) > 1) & (fn.Sum(self.t0.bar) < 100)
+            (fn.Sum(self.table_abc.bar) > 1) & (fn.Sum(self.table_abc.bar) < 100)
         )
 
         self.assertEqual('SELECT "foo",SUM("bar") FROM "abc" GROUP BY "foo" HAVING SUM("bar")>1 AND SUM("bar")<100',
                          str(q))
 
     def test_having_join_and_equality(self):
-        q = Query.from_(self.t0).join(
-            self.t1
+        q = Query.from_(self.table_abc).join(
+            self.table_efg
         ).on(
-            self.t0.foo == self.t1.foo
+            self.table_abc.foo == self.table_efg.foo
         ).select(
-            self.t0.foo, fn.Sum(self.t1.bar), self.t0.buz
+            self.table_abc.foo, fn.Sum(self.table_efg.bar), self.table_abc.buz
         ).groupby(
-            self.t0.foo
+            self.table_abc.foo
         ).having(
-            self.t0.buz == 'fiz'
+            self.table_abc.buz == 'fiz'
         ).having(
-            fn.Sum(self.t1.bar) > 100
+            fn.Sum(self.table_efg.bar) > 100
         )
 
-        self.assertEqual('SELECT "t0"."foo",SUM("t1"."bar"),"t0"."buz" FROM "abc" "t0" '
-                         'JOIN "efg" "t1" ON "t0"."foo"="t1"."foo" '
-                         'GROUP BY "t0"."foo" '
-                         "HAVING \"t0\".\"buz\"='fiz' AND SUM(\"t1\".\"bar\")>100", str(q))
+        self.assertEqual('SELECT "abc"."foo",SUM("efg"."bar"),"abc"."buz" FROM "abc" '
+                         'JOIN "efg" ON "abc"."foo"="efg"."foo" '
+                         'GROUP BY "abc"."foo" '
+                         "HAVING \"abc\".\"buz\"='fiz' AND SUM(\"efg\".\"bar\")>100", str(q))
 
 
 class OrderByTests(unittest.TestCase):
@@ -388,9 +388,9 @@ class SubqueryTests(unittest.TestCase):
             self.table_abc.bar == subquery.buz
         ).select(self.table_abc.foo, subquery.fiz)
 
-        self.assertEqual('SELECT "t0"."foo","t1"."fiz" FROM "abc" "t0" '
-                         'JOIN (SELECT "fiz","buz" FROM "efg" WHERE "buz"=0) "t1" '
-                         'ON "t0"."bar"="t1"."buz"', str(q))
+        self.assertEqual('SELECT "abc"."foo","sq0"."fiz" FROM "abc" '
+                         'JOIN (SELECT "fiz","buz" FROM "efg" WHERE "buz"=0) "sq0" '
+                         'ON "abc"."bar"="sq0"."buz"', str(q))
 
     def test_where__equality(self):
         subquery = Query.from_('efg').select('fiz').where(F('buz') == 0)
@@ -437,15 +437,15 @@ class SubqueryTests(unittest.TestCase):
         )
 
         self.assertEqual('SELECT '
-                         '"t0"."foo","t0"."fizzbuzz",'
-                         '"t1"."foo_two","t1"."bar" '
+                         '"sq0"."foo","sq0"."fizzbuzz",'
+                         '"sq1"."foo_two","sq1"."bar" '
                          'FROM ('
                          'SELECT '
                          '"foo",SUM("fizz"+"buzz") "fizzbuzz" '
                          'FROM "abc" '
                          'GROUP BY "foo"'
-                         ') "t0" JOIN ('
+                         ') "sq0" JOIN ('
                          'SELECT '
                          '"foo" "foo_two","bar" '
                          'FROM "efg"'
-                         ') "t1" ON "t0"."foo"="t1"."foo_two"', str(query))
+                         ') "sq1" ON "sq0"."foo"="sq1"."foo_two"', str(query))