Skip to content

Commit 8115393

Browse files
Merge pull request #964 from jverswijver/union_bug
Fix bug with unions.
2 parents 3bdfcf3 + 7f4ea4b commit 8115393

File tree

4 files changed

+22
-6
lines changed

4 files changed

+22
-6
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
## Release notes
22

3-
### 0.13.3 -- TBD
3+
### 0.13.3 -- Feb 9, 2022
44
* Bugfix - Fix error in listing ancestors, descendants with part tables.
55
* Bugfix - Fix Python 3.10 compatibility (#983) PR #972
66
* Bugfix - Allow renaming non-conforming attributes in proj (#982) PR #972
@@ -16,6 +16,7 @@
1616
* Bugfix - Fix count for left-joined `QueryExpressions` (#951) PR #966
1717
* Bugfix - Fix assertion error when performing a union into a join (#930) PR #967
1818
* Update `~jobs.error_stack` from blob to mediumblob to allow error stacks >64kB in jobs (#984) PR #986
19+
* Bugfix - Fix error when performing a union on multiple tables (#926) PR #964
1920
* Add - Allow optional keyword arguments for `make()` in `populate()` PR #971
2021

2122
### 0.13.2 -- May 7, 2021

datajoint/expression.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ def from_clause(self):
102102
return clause
103103

104104
def where_clause(self):
105-
return '' if not self.restriction else ' WHERE(%s)' % ')AND('.join(
105+
return '' if not self.restriction else ' WHERE (%s)' % ')AND('.join(
106106
str(s) for s in self.restriction)
107107

108108
def make_sql(self, fields=None):
@@ -606,6 +606,8 @@ class Union(QueryExpression):
606606
"""
607607
Union is the private DataJoint class that implements the union operator.
608608
"""
609+
__count = count()
610+
609611
@classmethod
610612
def create(cls, arg1, arg2):
611613
if inspect.isclass(arg2) and issubclass(arg2, QueryExpression):
@@ -632,9 +634,11 @@ def make_sql(self):
632634
if not arg1.heading.secondary_attributes and not arg2.heading.secondary_attributes:
633635
# no secondary attributes: use UNION DISTINCT
634636
fields = arg1.primary_key
635-
return "({sql1}) UNION ({sql2})".format(
636-
sql1=arg1.make_sql(fields),
637-
sql2=arg2.make_sql(fields))
637+
return ("SELECT * FROM (({sql1}) UNION ({sql2})) as `_u{alias}`".format(
638+
sql1=arg1.make_sql() if isinstance(arg1, Union) else arg1.make_sql(fields),
639+
sql2=arg2.make_sql() if isinstance(arg2, Union) else arg2.make_sql(fields),
640+
alias=next(self.__count)
641+
))
638642
# with secondary attributes, use union of left join with antijoin
639643
fields = self.heading.names
640644
sql1 = arg1.join(arg2, left=True).make_sql(fields)

docs-parts/intro/Releases_lang1.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
0.13.3 -- TBD
1+
0.13.3 -- Feb 9, 2022
22
----------------------
33
* Bugfix - Fix error in listing ancestors, descendants with part tables.
44
* Bugfix - Fix Python 3.10 compatibility (#983) PR #972
@@ -15,6 +15,7 @@
1515
* Bugfix - Fix assertion error when performing a union into a join (#930) PR #967
1616
* Bugfix - Fix regression issue with `DISTINCT` clause and `GROUP_BY` (#914) PR #963
1717
* Update `~jobs.error_stack` from blob to mediumblob to allow error stacks >64kB in jobs (#984) PR #986
18+
* Bugfix - Fix error when performing a union on multiple tables (#926) PR #964
1819
* Add - Allow optional keyword arguments for `make()` in `populate()` PR #971
1920

2021
0.13.2 -- May 7, 2021

tests/test_relational_operand.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,3 +516,13 @@ def test_joins_with_aggregation():
516516
session_dates = ((SessionDateA * (subj_query & 'date_trained<"2020-12-21"')) &
517517
'session_date<date_trained')
518518
assert len(session_dates) == 1
519+
520+
@staticmethod
521+
def test_union_multiple():
522+
# https://github.com/datajoint/datajoint-python/issues/926
523+
q1 = IJ & dict(j=2)
524+
q2 = (IJ & dict(j=2, i=0)) + (IJ & dict(j=2, i=1)) + (IJ & dict(j=2, i=2))
525+
x = set(zip(*q1.fetch('i', 'j')))
526+
y = set(zip(*q2.fetch('i', 'j')))
527+
assert x == y
528+
assert q1.fetch(as_dict=True) == q2.fetch(as_dict=True)

0 commit comments

Comments
 (0)