You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by dh...@apache.org on 2021/05/05 10:25:56 UTC

[arrow-datafusion] branch master updated: Implement select distinct (#262)

This is an automated email from the ASF dual-hosted git repository.

dheres pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow-datafusion.git


The following commit(s) were added to refs/heads/master by this push:
     new 9e84f15  Implement select distinct (#262)
9e84f15 is described below

commit 9e84f15191860befab07d4f257ccb0be75f1b206
Author: Daniƫl Heres <da...@gmail.com>
AuthorDate: Wed May 5 12:25:46 2021 +0200

    Implement select distinct (#262)
    
    * Implement select distinct
    
    * Simplify implementation
    
    * Move out of project fn
    
    * Fix call
    
    * Fix docs
    
    * Add to docs
    
    * Add note of ALL support
    
    * Add test for SELECT ALL
    
    * Clippy
    
    * Update datafusion/tests/sql.rs
    
    Co-authored-by: Andrew Lamb <an...@nerdnetworks.org>
    
    Co-authored-by: Andrew Lamb <an...@nerdnetworks.org>
---
 datafusion/src/sql/planner.rs     | 33 +++++++++--------
 datafusion/tests/sql.rs           | 75 +++++++++++++++++++++++++++++++++++++++
 docs/user-guide/src/sql/select.md |  8 ++++-
 3 files changed, 100 insertions(+), 16 deletions(-)

diff --git a/datafusion/src/sql/planner.rs b/datafusion/src/sql/planner.rs
index a40d0be..48900f5 100644
--- a/datafusion/src/sql/planner.rs
+++ b/datafusion/src/sql/planner.rs
@@ -17,9 +17,9 @@
 
 //! SQL Query Planner (produces logical plan from SQL AST)
 
-use std::convert::TryInto;
 use std::str::FromStr;
 use std::sync::Arc;
+use std::{convert::TryInto, vec};
 
 use crate::catalog::TableReference;
 use crate::datasource::TableProvider;
@@ -621,7 +621,15 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
             plan
         };
 
-        self.project(&plan, select_exprs_post_aggr, false)
+        let plan = if select.distinct {
+            return LogicalPlanBuilder::from(&plan)
+                .aggregate(select_exprs_post_aggr, vec![])?
+                .build();
+        } else {
+            plan
+        };
+
+        self.project(&plan, select_exprs_post_aggr)
     }
 
     /// Returns the `Expr`'s corresponding to a SQL query's SELECT expressions.
@@ -645,24 +653,19 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> {
 
     /// Wrap a plan in a projection
     ///
-    /// If the `force` argument is `false`, the projection is applied only when
-    /// necessary, i.e., when the input fields are different than the
+    /// The projection is applied only when necessary,
+    /// i.e., when the input fields are different than the
     /// projection. Note that if the input fields are the same, but out of
     /// order, the projection will be applied.
-    fn project(
-        &self,
-        input: &LogicalPlan,
-        expr: Vec<Expr>,
-        force: bool,
-    ) -> Result<LogicalPlan> {
+    fn project(&self, input: &LogicalPlan, expr: Vec<Expr>) -> Result<LogicalPlan> {
         self.validate_schema_satisfies_exprs(&input.schema(), &expr)?;
+
         let plan = LogicalPlanBuilder::from(input).project(expr)?.build()?;
 
-        let project = force
-            || match input {
-                LogicalPlan::TableScan { .. } => true,
-                _ => plan.schema().fields() != input.schema().fields(),
-            };
+        let project = match input {
+            LogicalPlan::TableScan { .. } => true,
+            _ => plan.schema().fields() != input.schema().fields(),
+        };
 
         if project {
             Ok(plan)
diff --git a/datafusion/tests/sql.rs b/datafusion/tests/sql.rs
index 7169294..bf28525 100644
--- a/datafusion/tests/sql.rs
+++ b/datafusion/tests/sql.rs
@@ -373,6 +373,81 @@ async fn csv_query_group_by_float32() -> Result<()> {
 }
 
 #[tokio::test]
+async fn select_all() -> Result<()> {
+    let mut ctx = ExecutionContext::new();
+    register_aggregate_simple_csv(&mut ctx)?;
+
+    let sql = "SELECT c1 FROM aggregate_simple order by c1";
+    let actual_no_all = execute(&mut ctx, sql).await;
+
+    let sql_all = "SELECT ALL c1 FROM aggregate_simple order by c1";
+    let actual_all = execute(&mut ctx, sql_all).await;
+
+    assert_eq!(actual_no_all, actual_all);
+
+    Ok(())
+}
+
+#[tokio::test]
+async fn select_distinct() -> Result<()> {
+    let mut ctx = ExecutionContext::new();
+    register_aggregate_simple_csv(&mut ctx)?;
+
+    let sql = "SELECT DISTINCT * FROM aggregate_simple";
+    let mut actual = execute(&mut ctx, sql).await;
+    actual.sort();
+
+    let mut dedup = actual.clone();
+    dedup.dedup();
+
+    assert_eq!(actual, dedup);
+
+    Ok(())
+}
+
+#[tokio::test]
+async fn select_distinct_simple() -> Result<()> {
+    let mut ctx = ExecutionContext::new();
+    register_aggregate_simple_csv(&mut ctx)?;
+
+    let sql = "SELECT DISTINCT c1 FROM aggregate_simple order by c1";
+    let actual = execute(&mut ctx, sql).await;
+
+    let expected = vec![
+        vec!["0.00001"],
+        vec!["0.00002"],
+        vec!["0.00003"],
+        vec!["0.00004"],
+        vec!["0.00005"],
+    ];
+    assert_eq!(actual, expected);
+
+    let sql = "SELECT DISTINCT c1, c2 FROM aggregate_simple order by c1";
+    let actual = execute(&mut ctx, sql).await;
+
+    let expected = vec![
+        vec!["0.00001", "0.000000000001"],
+        vec!["0.00002", "0.000000000002"],
+        vec!["0.00003", "0.000000000003"],
+        vec!["0.00004", "0.000000000004"],
+        vec!["0.00005", "0.000000000005"],
+    ];
+    assert_eq!(actual, expected);
+
+    let sql = "SELECT distinct c3 FROM aggregate_simple order by c3";
+    let actual = execute(&mut ctx, sql).await;
+
+    let expected = vec![vec!["false"], vec!["true"]];
+    assert_eq!(actual, expected);
+
+    let sql = "SELECT distinct c1+c2 as a FROM aggregate_simple";
+    let actual = execute(&mut ctx, sql).await;
+
+    assert_eq!(actual.len(), 5);
+    Ok(())
+}
+
+#[tokio::test]
 async fn csv_query_group_by_float64() -> Result<()> {
     let mut ctx = ExecutionContext::new();
     register_aggregate_simple_csv(&mut ctx)?;
diff --git a/docs/user-guide/src/sql/select.md b/docs/user-guide/src/sql/select.md
index 777b4ff..78d0cb5 100644
--- a/docs/user-guide/src/sql/select.md
+++ b/docs/user-guide/src/sql/select.md
@@ -26,7 +26,7 @@ DataFusion supports the following syntax for queries:
 <code class="language-sql hljs">
 
 [ [WITH](#with-clause) with_query [, ...] ] <br/>
-[SELECT](#select-clause) select_expr [, ...] <br/>
+[SELECT](#select-clause) [ ALL | DISTINCT ] select_expr [, ...] <br/>
 [ [FROM](#from-clause) from_item [, ...] ] <br/>
 [ [WHERE](#where-clause) condition ] <br/>
 [ [GROUP BY](#group-by-clause) grouping_element [, ...] ] <br/>
@@ -55,6 +55,12 @@ Example:
 SELECT a, b, a + b FROM table 
 ```
 
+The `DISTINCT` quantifier can be added to make the query return all distinct rows.
+By default `ALL` will be used, which returns all the rows.
+
+```sql
+SELECT DISTINCT person, age FROM employees
+```
 
 # FROM clause