Repository: great-expectations/great_expectations

Issue:
expect_compound_columns_to_be_unique divide by zero error when no rows
**Describe the bug**
[expect_compound_columns_to_be_unique](https://docs.greatexpectations.io/en/0.13.8/autoapi/great_expectations/expectations/core/expect_compound_columns_to_be_unique/index.html) errors with a divide by zero error when the table contains no rows as shown in this example stack trace from version 0.12.7:

```
float division by zero
Traceback (most recent call last):
    ...
  File "py_deps/pypi__great_expectations/great_expectations/data_asset/util.py", line 80, in f
    return self.mthd(obj, *args, **kwargs)
  File "py_deps/pypi__great_expectations/great_expectations/data_asset/data_asset.py", line 275, in wrapper
    raise err
  File "py_deps/pypi__great_expectations/great_expectations/data_asset/data_asset.py", line 260, in wrapper
    return_obj = func(self, **evaluation_args)
  File "py_deps/pypi__great_expectations/great_expectations/dataset/sqlalchemy_dataset.py", line 1380, in expect_compound_columns_to_be_unique
    "result": {"unexpected_percent": 100.0 * unexpected_count / total_count}
ZeroDivisionError: 
```

**To Reproduce**
Steps to reproduce the behavior:
1. Use expect_compound_columns_to_be_unique on a table with zero rows

**Expected behavior**
Expectation should pass.

**Environment (please complete the following information):**
 - Operating System: [e.g. Linux, MacOS, Windows]
 - Great Expectations Version: reproduced on 0.12.7 and 0.13.9

**Additional context**
Add any other context about the problem here.



Discussion:
I'm fixing this with https://github.com/great-expectations/great_expectations/pull/2454

Resolving patch:
diff --git a/great_expectations/dataset/sqlalchemy_dataset.py b/great_expectations/dataset/sqlalchemy_dataset.py
--- a/great_expectations/dataset/sqlalchemy_dataset.py
+++ b/great_expectations/dataset/sqlalchemy_dataset.py
@@ -1437,9 +1437,15 @@ def expect_compound_columns_to_be_unique(
         total_count_query = sa.select([sa.func.count()]).select_from(self._table)
         total_count = self.engine.execute(total_count_query).fetchone()[0]
 
+        if total_count > 0:
+            unexpected_percent = 100.0 * unexpected_count / total_count
+        else:
+            # If no rows, then zero percent are unexpected.
+            unexpected_percent = 0
+
         return {
             "success": unexpected_count == 0,
-            "result": {"unexpected_percent": 100.0 * unexpected_count / total_count},
+            "result": {"unexpected_percent": unexpected_percent},
         }
 
     ###


Test patch:
diff --git a/tests/dataset/test_sqlalchemydataset.py b/tests/dataset/test_sqlalchemydataset.py
--- a/tests/dataset/test_sqlalchemydataset.py
+++ b/tests/dataset/test_sqlalchemydataset.py
@@ -347,3 +347,21 @@ def test_expect_compound_columns_to_be_unique(sa):
     assert dataset.expect_compound_columns_to_be_unique(
         ["col1", "col2", "col4"]
     ).success
+
+
+def test_expect_compound_columns_to_be_unique_with_no_rows(sa):
+    engine = sa.create_engine("sqlite://")
+
+    data = pd.DataFrame(
+        {
+            "col1": [],
+            "col2": [],
+            "col3": [],
+            "col4": [],
+        }
+    )
+
+    data.to_sql(name="test_sql_data", con=engine, index=False)
+    dataset = SqlAlchemyDataset("test_sql_data", engine=engine)
+
+    assert dataset.expect_compound_columns_to_be_unique(["col1", "col2"]).success