Repository: great-expectations/great_expectations

Issue:
TSQL mean on `int` columns returns incorrect result
**Describe the bug**
TSQL mean on `int` columns returns an integer result obfuscating the true aggregate result.

**To Reproduce**
Steps to reproduce the behavior:
1. With a MSSQL backend
2. and an integer column named `foo`
3. with data like this 1, 2, 1, 1
4. and an expectation like this
```python
expect_column_mean_to_be_between("foo")
```
5. Note the output
```python
{
  "success": true,
  "result": {
    "observed_value": 1,
    "element_count": 4,
    "missing_count": null,
    "missing_percent": null
  },
  "exception_info": null,
  "meta": {}
}
```

**Expected behavior**
I would expect the exact value of 1.25 to be returned.

**Environment (please complete the following information):**
 - OS: [e.g. iOS] macOS, MSSQL Server
 - GE Version: [e.g. 0.10.0] 0.13.1

**Additional context**
Add any other context about the problem here.

There is probably an easy fix to this by casting the integer to a numeric before the average is taken.



Discussion:

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
@@ -741,8 +741,9 @@ def get_column_value_counts(self, column, sort="value", collate=None):
         return series
 
     def get_column_mean(self, column):
+        # column * 1.0 needed for correct calculation of avg in MSSQL
         return self.engine.execute(
-            sa.select([sa.func.avg(sa.column(column))]).select_from(self._table)
+            sa.select([sa.func.avg(sa.column(column) * 1.0)]).select_from(self._table)
         ).scalar()
 
     def get_column_unique_count(self, column):
diff --git a/great_expectations/expectations/metrics/column_aggregate_metrics/column_mean.py b/great_expectations/expectations/metrics/column_aggregate_metrics/column_mean.py
--- a/great_expectations/expectations/metrics/column_aggregate_metrics/column_mean.py
+++ b/great_expectations/expectations/metrics/column_aggregate_metrics/column_mean.py
@@ -26,7 +26,8 @@ def _pandas(cls, column, **kwargs):
     @column_aggregate_partial(engine=SqlAlchemyExecutionEngine)
     def _sqlalchemy(cls, column, **kwargs):
         """SqlAlchemy Mean Implementation"""
-        return sa.func.avg(column)
+        # column * 1.0 needed for correct calculation of avg in MSSQL
+        return sa.func.avg(column * 1.0)
 
     @column_aggregate_partial(engine=SparkDFExecutionEngine)
     def _spark(cls, column, _table, _column_name, **kwargs):


Test patch:
diff --git a/tests/test_definitions/column_aggregate_expectations/expect_column_mean_to_be_between.json b/tests/test_definitions/column_aggregate_expectations/expect_column_mean_to_be_between.json
--- a/tests/test_definitions/column_aggregate_expectations/expect_column_mean_to_be_between.json
+++ b/tests/test_definitions/column_aggregate_expectations/expect_column_mean_to_be_between.json
@@ -3,7 +3,7 @@
   "datasets": [{
       "data": {
         "x": [2.0, 5.0],
-        "y": [5, 5],
+        "y": [1, 2],
         "z": [0, 10],
         "n": [0, null],
         "b": [true, false]
@@ -55,12 +55,12 @@
           "exact_match_out": false,
           "in": {
             "column": "y",
-            "min_value": 5,
-            "max_value": 5
+            "min_value": 1.5,
+            "max_value": 1.5
           },
           "out": {
             "success": true,
-            "observed_value": 5
+            "observed_value": 1.5
           }
         },
         {
@@ -73,7 +73,7 @@
           },
           "out": {
             "success": false,
-            "observed_value": 5
+            "observed_value": 1.5
           }
         },
         {