diff --git a/crates/nu-command/src/database/expressions/alias.rs b/crates/nu-command/src/database/commands/alias.rs
similarity index 62%
rename from crates/nu-command/src/database/expressions/alias.rs
rename to crates/nu-command/src/database/commands/alias.rs
index 9cda68a0b..407a0341f 100644
--- a/crates/nu-command/src/database/expressions/alias.rs
+++ b/crates/nu-command/src/database/commands/alias.rs
@@ -8,7 +8,7 @@ use nu_protocol::{
     engine::{Command, EngineState, Stack},
     Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape,
 };
-use sqlparser::ast::{Ident, SelectItem, SetExpr, TableAlias, TableFactor};
+use sqlparser::ast::{Ident, SelectItem, SetExpr, Statement, TableAlias, TableFactor};
 
 #[derive(Clone)]
 pub struct AliasExpr;
@@ -110,44 +110,56 @@ fn alias_db(
     new_alias: String,
     call: &Call,
 ) -> Result<PipelineData, ShellError> {
-    match db.query {
+    match db.statement.as_mut() {
         None => Err(ShellError::GenericError(
             "Error creating alias".into(),
-            "there is no query defined yet".into(),
+            "there is no statement defined yet".into(),
             Some(call.head),
             None,
             Vec::new(),
         )),
-        Some(ref mut query) => match &mut query.body {
-            SetExpr::Select(ref mut select) => {
-                select.as_mut().from.iter_mut().for_each(|table| {
-                    let new_alias = Some(TableAlias {
-                        name: Ident {
-                            value: new_alias.clone(),
-                            quote_style: None,
-                        },
-                        columns: Vec::new(),
+        Some(statement) => match statement {
+            Statement::Query(query) => match &mut query.body {
+                SetExpr::Select(select) => {
+                    select.as_mut().from.iter_mut().for_each(|table| {
+                        let new_alias = Some(TableAlias {
+                            name: Ident {
+                                value: new_alias.clone(),
+                                quote_style: None,
+                            },
+                            columns: Vec::new(),
+                        });
+
+                        if let TableFactor::Table { ref mut alias, .. } = table.relation {
+                            *alias = new_alias;
+                        } else if let TableFactor::Derived { ref mut alias, .. } = table.relation {
+                            *alias = new_alias;
+                        } else if let TableFactor::TableFunction { ref mut alias, .. } =
+                            table.relation
+                        {
+                            *alias = new_alias;
+                        }
                     });
 
-                    if let TableFactor::Table { ref mut alias, .. } = table.relation {
-                        *alias = new_alias;
-                    } else if let TableFactor::Derived { ref mut alias, .. } = table.relation {
-                        *alias = new_alias;
-                    } else if let TableFactor::TableFunction { ref mut alias, .. } = table.relation
-                    {
-                        *alias = new_alias;
-                    }
-                });
-
-                Ok(db.into_value(call.head).into_pipeline_data())
+                    Ok(db.into_value(call.head).into_pipeline_data())
+                }
+                _ => Err(ShellError::GenericError(
+                    "Error creating alias".into(),
+                    "Query has no select from defined".into(),
+                    Some(call.head),
+                    None,
+                    Vec::new(),
+                )),
+            },
+            s => {
+                return Err(ShellError::GenericError(
+                    "Connection doesnt define a query".into(),
+                    format!("Expected a connection with query. Got {}", s),
+                    Some(call.head),
+                    None,
+                    Vec::new(),
+                ))
             }
-            _ => Err(ShellError::GenericError(
-                "Error creating alias".into(),
-                "Query has no select from defined".into(),
-                Some(call.head),
-                None,
-                Vec::new(),
-            )),
         },
     }
 }
diff --git a/crates/nu-command/src/database/commands/and.rs b/crates/nu-command/src/database/commands/and.rs
index 45cdbc609..8e4d6dc60 100644
--- a/crates/nu-command/src/database/commands/and.rs
+++ b/crates/nu-command/src/database/commands/and.rs
@@ -8,7 +8,7 @@ use nu_protocol::{
     Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
     Value,
 };
-use sqlparser::ast::{BinaryOperator, Expr, Query, Select, SetExpr};
+use sqlparser::ast::{BinaryOperator, Expr, Query, Select, SetExpr, Statement};
 
 #[derive(Clone)]
 pub struct AndDb;
@@ -78,12 +78,23 @@ impl Command for AndDb {
 
             Ok(expression.into_value(call.head).into_pipeline_data())
         } else if let Ok(mut db) = SQLiteDatabase::try_from_value(value.clone()) {
-            db.query = match db.query {
-                Some(query) => Some(modify_query(query, expr, call.head)?),
+            match db.statement.as_mut() {
+                Some(statement) => match statement {
+                    Statement::Query(query) => modify_query(query, expr, call.head)?,
+                    s => {
+                        return Err(ShellError::GenericError(
+                            "Connection doesnt define a query".into(),
+                            format!("Expected a connection with query. Got {}", s),
+                            Some(call.head),
+                            None,
+                            Vec::new(),
+                        ))
+                    }
+                },
                 None => {
                     return Err(ShellError::GenericError(
-                        "Connection without query".into(),
-                        "Missing query in the connection".into(),
+                        "Connection without statement".into(),
+                        "The connection needs a statement defined".into(),
                         Some(call.head),
                         None,
                         Vec::new(),
@@ -103,26 +114,24 @@ impl Command for AndDb {
     }
 }
 
-fn modify_query(mut query: Query, expression: Expr, span: Span) -> Result<Query, ShellError> {
-    query.body = match query.body {
-        SetExpr::Select(select) => Ok(SetExpr::Select(modify_select(select, expression, span)?)),
-        _ => Err(ShellError::GenericError(
-            "Query without a select".into(),
-            "Missing a WHERE clause before an AND clause".into(),
-            Some(span),
-            None,
-            Vec::new(),
-        )),
-    }?;
+fn modify_query(query: &mut Box<Query>, expression: Expr, span: Span) -> Result<(), ShellError> {
+    match query.body {
+        SetExpr::Select(ref mut select) => modify_select(select, expression, span)?,
+        _ => {
+            return Err(ShellError::GenericError(
+                "Query without a select".into(),
+                "Missing a WHERE clause before an AND clause".into(),
+                Some(span),
+                None,
+                Vec::new(),
+            ))
+        }
+    };
 
-    Ok(query)
+    Ok(())
 }
 
-fn modify_select(
-    mut select: Box<Select>,
-    expression: Expr,
-    span: Span,
-) -> Result<Box<Select>, ShellError> {
+fn modify_select(select: &mut Box<Select>, expression: Expr, span: Span) -> Result<(), ShellError> {
     let new_expression = match &select.selection {
         Some(expr) => Ok(Expr::BinaryOp {
             left: Box::new(expr.clone()),
@@ -139,5 +148,5 @@ fn modify_select(
     }?;
 
     select.as_mut().selection = Some(new_expression);
-    Ok(select)
+    Ok(())
 }
diff --git a/crates/nu-command/src/database/expressions/col.rs b/crates/nu-command/src/database/commands/col.rs
similarity index 97%
rename from crates/nu-command/src/database/expressions/col.rs
rename to crates/nu-command/src/database/commands/col.rs
index f604d26b6..c94c294b9 100644
--- a/crates/nu-command/src/database/expressions/col.rs
+++ b/crates/nu-command/src/database/commands/col.rs
@@ -27,7 +27,7 @@ impl Command for ColExpr {
     fn examples(&self) -> Vec<Example> {
         vec![Example {
             description: "Creates a named column expression",
-            example: "col name_1",
+            example: "db col name_1",
             result: None,
         }]
     }
diff --git a/crates/nu-command/src/database/commands/from.rs b/crates/nu-command/src/database/commands/from.rs
index 4c9398eaa..fd7692ae4 100644
--- a/crates/nu-command/src/database/commands/from.rs
+++ b/crates/nu-command/src/database/commands/from.rs
@@ -3,9 +3,11 @@ use nu_engine::CallExt;
 use nu_protocol::{
     ast::Call,
     engine::{Command, EngineState, Stack},
-    Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape,
+    Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
+};
+use sqlparser::ast::{
+    Ident, ObjectName, Query, Select, SetExpr, Statement, TableFactor, TableWithJoins,
 };
-use sqlparser::ast::{Ident, ObjectName, Query, Select, SetExpr, TableFactor, TableWithJoins};
 
 #[derive(Clone)]
 pub struct FromDb;
@@ -51,17 +53,17 @@ impl Command for FromDb {
         let table: String = call.req(engine_state, stack, 0)?;
 
         let mut db = SQLiteDatabase::try_from_pipeline(input, call.head)?;
-        db.query = match db.query {
-            None => Some(create_query(table)),
-            Some(query) => Some(modify_query(query, table)),
+        db.statement = match db.statement {
+            None => Some(create_statement(table)),
+            Some(statement) => Some(modify_statement(statement, table, call.head)?),
         };
 
         Ok(db.into_value(call.head).into_pipeline_data())
     }
 }
 
-fn create_query(table: String) -> Query {
-    Query {
+fn create_statement(table: String) -> Statement {
+    let query = Query {
         with: None,
         body: SetExpr::Select(Box::new(create_select(table))),
         order_by: Vec::new(),
@@ -69,21 +71,35 @@ fn create_query(table: String) -> Query {
         offset: None,
         fetch: None,
         lock: None,
-    }
-}
-
-fn modify_query(mut query: Query, table: String) -> Query {
-    query.body = match query.body {
-        SetExpr::Select(select) => SetExpr::Select(modify_select(select, table)),
-        _ => SetExpr::Select(Box::new(create_select(table))),
     };
 
-    query
+    Statement::Query(Box::new(query))
 }
 
-fn modify_select(mut select: Box<Select>, table: String) -> Box<Select> {
-    select.as_mut().from = create_from(table);
-    select
+fn modify_statement(
+    mut statement: Statement,
+    table: String,
+    span: Span,
+) -> Result<Statement, ShellError> {
+    match statement {
+        Statement::Query(ref mut query) => {
+            match query.body {
+                SetExpr::Select(ref mut select) => select.as_mut().from = create_from(table),
+                _ => {
+                    query.as_mut().body = SetExpr::Select(Box::new(create_select(table)));
+                }
+            };
+
+            Ok(statement)
+        }
+        s => Err(ShellError::GenericError(
+            "Connection doesnt define a statement".into(),
+            format!("Expected a connection with query. Got {}", s),
+            Some(span),
+            None,
+            Vec::new(),
+        )),
+    }
 }
 
 fn create_select(table: String) -> Select {
diff --git a/crates/nu-command/src/database/commands/function.rs b/crates/nu-command/src/database/commands/function.rs
new file mode 100644
index 000000000..50e36c019
--- /dev/null
+++ b/crates/nu-command/src/database/commands/function.rs
@@ -0,0 +1,85 @@
+use crate::database::values::dsl::ExprDb;
+use nu_engine::CallExt;
+use nu_protocol::{
+    ast::Call,
+    engine::{Command, EngineState, Stack},
+    Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
+};
+use sqlparser::ast::{Expr, Function, FunctionArg, FunctionArgExpr, Ident, ObjectName};
+
+#[derive(Clone)]
+pub struct FunctionExpr;
+
+impl Command for FunctionExpr {
+    fn name(&self) -> &str {
+        "db fn"
+    }
+
+    fn signature(&self) -> Signature {
+        Signature::build(self.name())
+            .required("name", SyntaxShape::String, "function name")
+            .switch("distinct", "distict values", Some('d'))
+            .rest("arguments", SyntaxShape::Any, "function arguments")
+            .category(Category::Custom("database".into()))
+    }
+
+    fn usage(&self) -> &str {
+        "Creates function expression for a select operation"
+    }
+
+    fn examples(&self) -> Vec<Example> {
+        vec![Example {
+            description: "Creates a function expression",
+            example: "db fn count name_1",
+            result: None,
+        }]
+    }
+
+    fn search_terms(&self) -> Vec<&str> {
+        vec!["database", "function", "expression"]
+    }
+
+    fn run(
+        &self,
+        engine_state: &EngineState,
+        stack: &mut Stack,
+        call: &Call,
+        _input: PipelineData,
+    ) -> Result<PipelineData, ShellError> {
+        let name: String = call.req(engine_state, stack, 0)?;
+        let vals: Vec<Value> = call.rest(engine_state, stack, 1)?;
+        let value = Value::List {
+            vals,
+            span: call.head,
+        };
+        let expressions = ExprDb::extract_exprs(value)?;
+
+        let name: Vec<Ident> = name
+            .split('.')
+            .map(|part| Ident {
+                value: part.to_string(),
+                quote_style: None,
+            })
+            .collect();
+        let name = ObjectName(name);
+
+        let args: Vec<FunctionArg> = expressions
+            .into_iter()
+            .map(|expr| {
+                let arg = FunctionArgExpr::Expr(expr);
+
+                FunctionArg::Unnamed(arg)
+            })
+            .collect();
+
+        let expression: ExprDb = Expr::Function(Function {
+            name,
+            args,
+            over: None,
+            distinct: call.has_flag("distinct"),
+        })
+        .into();
+
+        Ok(expression.into_value(call.head).into_pipeline_data())
+    }
+}
diff --git a/crates/nu-command/src/database/commands/group_by.rs b/crates/nu-command/src/database/commands/group_by.rs
new file mode 100644
index 000000000..ceb2ed385
--- /dev/null
+++ b/crates/nu-command/src/database/commands/group_by.rs
@@ -0,0 +1,102 @@
+use crate::database::values::dsl::ExprDb;
+
+use super::super::SQLiteDatabase;
+use nu_engine::CallExt;
+use nu_protocol::{
+    ast::Call,
+    engine::{Command, EngineState, Stack},
+    Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
+};
+use sqlparser::ast::{SetExpr, Statement};
+
+#[derive(Clone)]
+pub struct GroupByDb;
+
+impl Command for GroupByDb {
+    fn name(&self) -> &str {
+        "db group-by"
+    }
+
+    fn usage(&self) -> &str {
+        "Group by query"
+    }
+
+    fn signature(&self) -> Signature {
+        Signature::build(self.name())
+            .rest(
+                "select",
+                SyntaxShape::Any,
+                "Select expression(s) on the table",
+            )
+            .category(Category::Custom("database".into()))
+    }
+
+    fn search_terms(&self) -> Vec<&str> {
+        vec!["database", "select"]
+    }
+
+    fn examples(&self) -> Vec<Example> {
+        vec![Example {
+            description: "orders query by a column",
+            example: r#"db open db.mysql 
+    | db from table_a 
+    | db select a 
+    | db group-by a 
+    | db describe"#,
+            result: None,
+        }]
+    }
+
+    fn run(
+        &self,
+        engine_state: &EngineState,
+        stack: &mut Stack,
+        call: &Call,
+        input: PipelineData,
+    ) -> Result<PipelineData, ShellError> {
+        let vals: Vec<Value> = call.rest(engine_state, stack, 0)?;
+        let value = Value::List {
+            vals,
+            span: call.head,
+        };
+        let expressions = ExprDb::extract_exprs(value)?;
+
+        let mut db = SQLiteDatabase::try_from_pipeline(input, call.head)?;
+        match db.statement.as_mut() {
+            Some(statement) => match statement {
+                Statement::Query(ref mut query) => match &mut query.body {
+                    SetExpr::Select(ref mut select) => select.group_by = expressions,
+                    s => {
+                        return Err(ShellError::GenericError(
+                            "Connection doesnt define a select".into(),
+                            format!("Expected a connection with select query. Got {}", s),
+                            Some(call.head),
+                            None,
+                            Vec::new(),
+                        ))
+                    }
+                },
+                s => {
+                    return Err(ShellError::GenericError(
+                        "Connection doesnt define a query".into(),
+                        format!("Expected a connection with query. Got {}", s),
+                        Some(call.head),
+                        None,
+                        Vec::new(),
+                    ))
+                }
+            },
+            None => {
+                return Err(ShellError::GenericError(
+                    "Connection without statement".into(),
+                    "The connection needs a statement defined".into(),
+                    Some(call.head),
+                    None,
+                    Vec::new(),
+                ))
+            }
+        };
+
+        Ok(db.into_value(call.head).into_pipeline_data())
+    }
+}
diff --git a/crates/nu-command/src/database/commands/limit.rs b/crates/nu-command/src/database/commands/limit.rs
index d2b7f1455..d46b7c48c 100644
--- a/crates/nu-command/src/database/commands/limit.rs
+++ b/crates/nu-command/src/database/commands/limit.rs
@@ -6,6 +6,7 @@ use nu_protocol::{
     engine::{Command, EngineState, Stack},
     Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
 };
+use sqlparser::ast::Statement;
 
 #[derive(Clone)]
 pub struct LimitDb;
@@ -56,11 +57,19 @@ impl Command for LimitDb {
         let expr = ExprDb::try_from_value(&limit)?.into_native();
 
         let mut db = SQLiteDatabase::try_from_pipeline(input, call.head)?;
-        db.query = match db.query {
-            Some(mut query) => {
-                query.limit = Some(expr);
-                Some(query)
-            }
+        match db.statement {
+            Some(ref mut statement) => match statement {
+                Statement::Query(query) => query.as_mut().limit = Some(expr),
+                s => {
+                    return Err(ShellError::GenericError(
+                        "Connection doesnt define a statement".into(),
+                        format!("Expected a connection with query. Got {}", s),
+                        Some(call.head),
+                        None,
+                        Vec::new(),
+                    ))
+                }
+            },
             None => {
                 return Err(ShellError::GenericError(
                     "Connection without query".into(),
diff --git a/crates/nu-command/src/database/commands/mod.rs b/crates/nu-command/src/database/commands/mod.rs
index 790691831..12a2b7aea 100644
--- a/crates/nu-command/src/database/commands/mod.rs
+++ b/crates/nu-command/src/database/commands/mod.rs
@@ -1,12 +1,17 @@
+mod alias;
 mod and;
+mod col;
 mod collect;
 mod command;
 mod describe;
 mod from;
+mod function;
+mod group_by;
 mod limit;
 mod open;
 mod or;
 mod order_by;
+mod over;
 mod query;
 mod schema;
 mod select;
@@ -18,21 +23,26 @@ use testing::TestingDb;
 
 use nu_protocol::engine::StateWorkingSet;
 
+use alias::AliasExpr;
 use and::AndDb;
+use col::ColExpr;
 use collect::CollectDb;
 use command::Database;
 use describe::DescribeDb;
 use from::FromDb;
+use function::FunctionExpr;
+use group_by::GroupByDb;
 use limit::LimitDb;
 use open::OpenDb;
 use or::OrDb;
 use order_by::OrderByDb;
+use over::OverExpr;
 use query::QueryDb;
 use schema::SchemaDb;
 use select::ProjectionDb;
 use where_::WhereDb;
 
-pub fn add_commands_decls(working_set: &mut StateWorkingSet) {
+pub fn add_database_decls(working_set: &mut StateWorkingSet) {
     macro_rules! bind_command {
             ( $command:expr ) => {
                 working_set.add_decl(Box::new($command));
@@ -44,17 +54,22 @@ pub fn add_commands_decls(working_set: &mut StateWorkingSet) {
 
     // Series commands
     bind_command!(
+        AliasExpr,
         AndDb,
         CollectDb,
+        ColExpr,
         Database,
         DescribeDb,
         FromDb,
+        FunctionExpr,
+        GroupByDb,
         QueryDb,
         LimitDb,
         ProjectionDb,
         OpenDb,
         OrderByDb,
         OrDb,
+        OverExpr,
         SchemaDb,
         TestingDb,
         WhereDb
diff --git a/crates/nu-command/src/database/commands/or.rs b/crates/nu-command/src/database/commands/or.rs
index 62ee26bbe..459342193 100644
--- a/crates/nu-command/src/database/commands/or.rs
+++ b/crates/nu-command/src/database/commands/or.rs
@@ -8,7 +8,7 @@ use nu_protocol::{
     Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
     Value,
 };
-use sqlparser::ast::{BinaryOperator, Expr, Query, Select, SetExpr};
+use sqlparser::ast::{BinaryOperator, Expr, Query, Select, SetExpr, Statement};
 
 #[derive(Clone)]
 pub struct OrDb;
@@ -78,12 +78,23 @@ impl Command for OrDb {
 
             Ok(expression.into_value(call.head).into_pipeline_data())
         } else if let Ok(mut db) = SQLiteDatabase::try_from_value(value.clone()) {
-            db.query = match db.query {
-                Some(query) => Some(modify_query(query, expr, call.head)?),
+            match db.statement {
+                Some(ref mut statement) => match statement {
+                    Statement::Query(query) => modify_query(query, expr, call.head)?,
+                    s => {
+                        return Err(ShellError::GenericError(
+                            "Connection doesnt define a query".into(),
+                            format!("Expected a connection with query. Got {}", s),
+                            Some(call.head),
+                            None,
+                            Vec::new(),
+                        ))
+                    }
+                },
                 None => {
                     return Err(ShellError::GenericError(
-                        "Connection without query".into(),
-                        "Missing query in the connection".into(),
+                        "Connection without statement".into(),
+                        "The connection needs a statement defined".into(),
                         Some(call.head),
                         None,
                         Vec::new(),
@@ -103,26 +114,24 @@ impl Command for OrDb {
     }
 }
 
-fn modify_query(mut query: Query, expression: Expr, span: Span) -> Result<Query, ShellError> {
-    query.body = match query.body {
-        SetExpr::Select(select) => Ok(SetExpr::Select(modify_select(select, expression, span)?)),
-        _ => Err(ShellError::GenericError(
-            "Query without a select".into(),
-            "Missing a WHERE clause before an OR clause".into(),
-            Some(span),
-            None,
-            Vec::new(),
-        )),
-    }?;
+fn modify_query(query: &mut Box<Query>, expression: Expr, span: Span) -> Result<(), ShellError> {
+    match query.body {
+        SetExpr::Select(ref mut select) => modify_select(select, expression, span)?,
+        _ => {
+            return Err(ShellError::GenericError(
+                "Query without a select".into(),
+                "Missing a WHERE clause before an OR clause".into(),
+                Some(span),
+                None,
+                Vec::new(),
+            ))
+        }
+    };
 
-    Ok(query)
+    Ok(())
 }
 
-fn modify_select(
-    mut select: Box<Select>,
-    expression: Expr,
-    span: Span,
-) -> Result<Box<Select>, ShellError> {
+fn modify_select(select: &mut Box<Select>, expression: Expr, span: Span) -> Result<(), ShellError> {
     let new_expression = match &select.selection {
         Some(expr) => Ok(Expr::BinaryOp {
             left: Box::new(expr.clone()),
@@ -139,5 +148,5 @@ fn modify_select(
     }?;
 
     select.as_mut().selection = Some(new_expression);
-    Ok(select)
+    Ok(())
 }
diff --git a/crates/nu-command/src/database/commands/order_by.rs b/crates/nu-command/src/database/commands/order_by.rs
index 7ce65ceae..6d8a726ed 100644
--- a/crates/nu-command/src/database/commands/order_by.rs
+++ b/crates/nu-command/src/database/commands/order_by.rs
@@ -7,7 +7,7 @@ use nu_protocol::{
     engine::{Command, EngineState, Stack},
     Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
 };
-use sqlparser::ast::OrderByExpr;
+use sqlparser::ast::{Expr, OrderByExpr, Statement};
 
 #[derive(Clone)]
 pub struct OrderByDb;
@@ -58,40 +58,100 @@ impl Command for OrderByDb {
     ) -> Result<PipelineData, ShellError> {
         let asc = call.has_flag("ascending");
         let nulls_first = call.has_flag("nulls_first");
-
-        let vals: Vec<Value> = call.rest(engine_state, stack, 0)?;
-        let value = Value::List {
-            vals,
+        let expressions: Vec<Value> = call.rest(engine_state, stack, 0)?;
+        let expressions = Value::List {
+            vals: expressions,
             span: call.head,
         };
-        let expressions = ExprDb::extract_exprs(value)?;
+        let expressions = ExprDb::extract_exprs(expressions)?;
+        let expressions: Vec<OrderByExpr> = expressions
+            .into_iter()
+            .map(|expr| OrderByExpr {
+                expr,
+                asc: if asc { Some(asc) } else { None },
+                nulls_first: if nulls_first { Some(nulls_first) } else { None },
+            })
+            .collect();
 
-        let mut db = SQLiteDatabase::try_from_pipeline(input, call.head)?;
-        db.query = match db.query {
-            Some(mut query) => {
-                let mut order_expr: Vec<OrderByExpr> = expressions
-                    .into_iter()
-                    .map(|expr| OrderByExpr {
-                        expr,
-                        asc: if asc { Some(asc) } else { None },
-                        nulls_first: if nulls_first { Some(nulls_first) } else { None },
-                    })
-                    .collect();
+        let value = input.into_value(call.head);
 
-                query.order_by.append(&mut order_expr);
-                Some(query)
-            }
+        if let Ok(expr) = ExprDb::try_from_value(&value) {
+            update_expressions(expr, expressions, call)
+        } else if let Ok(db) = SQLiteDatabase::try_from_value(value.clone()) {
+            update_connection(db, expressions, call)
+        } else {
+            Err(ShellError::CantConvert(
+                "expression or query".into(),
+                value.get_type().to_string(),
+                value.span()?,
+                None,
+            ))
+        }
+    }
+}
+
+fn update_expressions(
+    mut expr: ExprDb,
+    mut expressions: Vec<OrderByExpr>,
+    call: &Call,
+) -> Result<PipelineData, ShellError> {
+    match expr.as_mut() {
+        Expr::Function(function) => match &mut function.over {
+            Some(over) => over.order_by.append(&mut expressions),
             None => {
                 return Err(ShellError::GenericError(
-                    "Connection without query".into(),
-                    "The connection needs a query defined".into(),
+                    "Expression doesnt define a partition to order".into(),
+                    "Expected an expression with partition".into(),
                     Some(call.head),
                     None,
                     Vec::new(),
                 ))
             }
-        };
+        },
+        s => {
+            return Err(ShellError::GenericError(
+                "Expression doesnt define a function".into(),
+                format!("Expected an expression with a function. Got {}", s),
+                Some(call.head),
+                None,
+                Vec::new(),
+            ))
+        }
+    };
 
-        Ok(db.into_value(call.head).into_pipeline_data())
-    }
+    Ok(expr.into_value(call.head).into_pipeline_data())
+}
+
+fn update_connection(
+    mut db: SQLiteDatabase,
+    mut expressions: Vec<OrderByExpr>,
+    call: &Call,
+) -> Result<PipelineData, ShellError> {
+    match db.statement.as_mut() {
+        Some(statement) => match statement {
+            Statement::Query(query) => {
+                query.order_by.append(&mut expressions);
+            }
+            s => {
+                return Err(ShellError::GenericError(
+                    "Connection doesnt define a query".into(),
+                    format!("Expected a connection with query. Got {}", s),
+                    Some(call.head),
+                    None,
+                    Vec::new(),
+                ))
+            }
+        },
+        None => {
+            return Err(ShellError::GenericError(
+                "Connection without statement".into(),
+                "The connection needs a statement defined".into(),
+                Some(call.head),
+                None,
+                Vec::new(),
+            ))
+        }
+    };
+
+    Ok(db.into_value(call.head).into_pipeline_data())
 }
diff --git a/crates/nu-command/src/database/commands/over.rs b/crates/nu-command/src/database/commands/over.rs
new file mode 100644
index 000000000..b47f2b5db
--- /dev/null
+++ b/crates/nu-command/src/database/commands/over.rs
@@ -0,0 +1,80 @@
+use crate::database::values::dsl::ExprDb;
+use nu_engine::CallExt;
+use nu_protocol::{
+    ast::Call,
+    engine::{Command, EngineState, Stack},
+    Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
+};
+use sqlparser::ast::{Expr, WindowSpec};
+
+#[derive(Clone)]
+pub struct OverExpr;
+
+impl Command for OverExpr {
+    fn name(&self) -> &str {
+        "db over"
+    }
+
+    fn signature(&self) -> Signature {
+        Signature::build(self.name())
+            .rest(
+                "partition-by",
+                SyntaxShape::Any,
+                "columns to partition the window function",
+            )
+            .category(Category::Custom("database".into()))
+    }
+
+    fn usage(&self) -> &str {
+        "Adds a partition to an expression function"
+    }
+
+    fn examples(&self) -> Vec<Example> {
+        vec![Example {
+            description: "Adds a partition to a function expresssion",
+            example: "db function avg col_a | db over col_b",
+            result: None,
+        }]
+    }
+
+    fn search_terms(&self) -> Vec<&str> {
+        vec!["database", "column", "expression"]
+    }
+
+    fn run(
+        &self,
+        engine_state: &EngineState,
+        stack: &mut Stack,
+        call: &Call,
+        input: PipelineData,
+    ) -> Result<PipelineData, ShellError> {
+        let vals: Vec<Value> = call.rest(engine_state, stack, 0)?;
+        let value = Value::List {
+            vals,
+            span: call.head,
+        };
+        let partitions = ExprDb::extract_exprs(value)?;
+
+        let mut expression = ExprDb::try_from_pipeline(input, call.head)?;
+        match expression.as_mut() {
+            Expr::Function(function) => {
+                function.over = Some(WindowSpec {
+                    partition_by: partitions,
+                    order_by: Vec::new(),
+                    window_frame: None,
+                });
+            }
+            s => {
+                return Err(ShellError::GenericError(
+                    "Expression doesnt define a function".into(),
+                    format!("Expected an expression with a function. Got {}", s),
+                    Some(call.head),
+                    None,
+                    Vec::new(),
+                ))
+            }
+        };
+
+        Ok(expression.into_value(call.head).into_pipeline_data())
+    }
+}
diff --git a/crates/nu-command/src/database/commands/select.rs b/crates/nu-command/src/database/commands/select.rs
index 78a366a8b..e550b510b 100644
--- a/crates/nu-command/src/database/commands/select.rs
+++ b/crates/nu-command/src/database/commands/select.rs
@@ -3,9 +3,10 @@ use nu_engine::CallExt;
 use nu_protocol::{
     ast::Call,
     engine::{Command, EngineState, Stack},
-    Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
+    Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
+    Value,
 };
-use sqlparser::ast::{Query, Select, SelectItem, SetExpr};
+use sqlparser::ast::{Query, Select, SelectItem, SetExpr, Statement};
 
 #[derive(Clone)]
 pub struct ProjectionDb;
@@ -63,17 +64,17 @@ impl Command for ProjectionDb {
         let projection = SelectDb::extract_selects(value)?;
 
         let mut db = SQLiteDatabase::try_from_pipeline(input, call.head)?;
-        db.query = match db.query {
-            None => Some(create_query(projection)),
-            Some(query) => Some(modify_query(query, projection)),
+        db.statement = match db.statement {
+            None => Some(create_statement(projection)),
+            Some(statement) => Some(modify_statement(statement, projection, call.head)?),
         };
 
         Ok(db.into_value(call.head).into_pipeline_data())
     }
 }
 
-fn create_query(expressions: Vec<SelectItem>) -> Query {
-    Query {
+fn create_statement(expressions: Vec<SelectItem>) -> Statement {
+    let query = Query {
         with: None,
         body: SetExpr::Select(Box::new(create_select(expressions))),
         order_by: Vec::new(),
@@ -81,21 +82,35 @@ fn create_query(expressions: Vec<SelectItem>) -> Query {
         offset: None,
         fetch: None,
         lock: None,
-    }
-}
-
-fn modify_query(mut query: Query, expressions: Vec<SelectItem>) -> Query {
-    query.body = match query.body {
-        SetExpr::Select(select) => SetExpr::Select(modify_select(select, expressions)),
-        _ => SetExpr::Select(Box::new(create_select(expressions))),
     };
 
-    query
+    Statement::Query(Box::new(query))
 }
 
-fn modify_select(mut select: Box<Select>, projection: Vec<SelectItem>) -> Box<Select> {
-    select.as_mut().projection = projection;
-    select
+fn modify_statement(
+    mut statement: Statement,
+    expressions: Vec<SelectItem>,
+    span: Span,
+) -> Result<Statement, ShellError> {
+    match statement {
+        Statement::Query(ref mut query) => {
+            match query.body {
+                SetExpr::Select(ref mut select) => select.as_mut().projection = expressions,
+                _ => {
+                    query.as_mut().body = SetExpr::Select(Box::new(create_select(expressions)));
+                }
+            };
+
+            Ok(statement)
+        }
+        s => Err(ShellError::GenericError(
+            "Connection doesnt define a statement".into(),
+            format!("Expected a connection with query. Got {}", s),
+            Some(span),
+            None,
+            Vec::new(),
+        )),
+    }
 }
 
 fn create_select(projection: Vec<SelectItem>) -> Select {
diff --git a/crates/nu-command/src/database/commands/where_.rs b/crates/nu-command/src/database/commands/where_.rs
index 47e6f9ed1..f14a22afa 100644
--- a/crates/nu-command/src/database/commands/where_.rs
+++ b/crates/nu-command/src/database/commands/where_.rs
@@ -7,7 +7,7 @@ use nu_protocol::{
     engine::{Command, EngineState, Stack},
     Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
 };
-use sqlparser::ast::{Expr, Query, Select, SetExpr};
+use sqlparser::ast::{Expr, Query, Select, SetExpr, Statement};
 
 #[derive(Clone)]
 pub struct WhereDb;
@@ -54,12 +54,23 @@ impl Command for WhereDb {
         let expr = ExprDb::try_from_value(&value)?.into_native();
 
         let mut db = SQLiteDatabase::try_from_pipeline(input, call.head)?;
-        db.query = match db.query {
-            Some(query) => Some(modify_query(query, expr)),
+        match db.statement.as_mut() {
+            Some(statement) => match statement {
+                Statement::Query(query) => modify_query(query, expr),
+                s => {
+                    return Err(ShellError::GenericError(
+                        "Connection doesnt define a query".into(),
+                        format!("Expected a connection with query. Got {}", s),
+                        Some(call.head),
+                        None,
+                        Vec::new(),
+                    ))
+                }
+            },
             None => {
                 return Err(ShellError::GenericError(
-                    "Connection without query".into(),
-                    "The connection needs a query defined".into(),
+                    "Connection without statement".into(),
+                    "The connection needs a statement defined".into(),
                     Some(call.head),
                     None,
                     Vec::new(),
@@ -71,18 +82,17 @@ impl Command for WhereDb {
     }
 }
 
-fn modify_query(mut query: Query, expression: Expr) -> Query {
-    query.body = match query.body {
-        SetExpr::Select(select) => SetExpr::Select(modify_select(select, expression)),
-        _ => SetExpr::Select(Box::new(create_select(expression))),
+fn modify_query(query: &mut Box<Query>, expression: Expr) {
+    match query.body {
+        SetExpr::Select(ref mut select) => modify_select(select, expression),
+        _ => {
+            query.as_mut().body = SetExpr::Select(Box::new(create_select(expression)));
+        }
     };
-
-    query
 }
 
-fn modify_select(mut select: Box<Select>, expression: Expr) -> Box<Select> {
+fn modify_select(select: &mut Box<Select>, expression: Expr) {
     select.as_mut().selection = Some(expression);
-    select
 }
 
 fn create_select(expression: Expr) -> Select {
diff --git a/crates/nu-command/src/database/expressions/mod.rs b/crates/nu-command/src/database/expressions/mod.rs
deleted file mode 100644
index 0f7a7d3c2..000000000
--- a/crates/nu-command/src/database/expressions/mod.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-mod alias;
-mod col;
-
-use nu_protocol::engine::StateWorkingSet;
-
-use alias::AliasExpr;
-use col::ColExpr;
-
-pub fn add_expression_decls(working_set: &mut StateWorkingSet) {
-    macro_rules! bind_command {
-            ( $command:expr ) => {
-                working_set.add_decl(Box::new($command));
-            };
-            ( $( $command:expr ),* ) => {
-                $( working_set.add_decl(Box::new($command)); )*
-            };
-        }
-
-    // Series commands
-    bind_command!(AliasExpr, ColExpr);
-}
diff --git a/crates/nu-command/src/database/mod.rs b/crates/nu-command/src/database/mod.rs
index 6087a936a..b2393f059 100644
--- a/crates/nu-command/src/database/mod.rs
+++ b/crates/nu-command/src/database/mod.rs
@@ -1,16 +1,8 @@
 mod commands;
 mod values;
 
-mod expressions;
-pub use commands::add_commands_decls;
-pub use expressions::add_expression_decls;
-use nu_protocol::engine::StateWorkingSet;
+pub use commands::add_database_decls;
 pub use values::{
     convert_sqlite_row_to_nu_value, convert_sqlite_value_to_nu_value, open_connection_in_memory,
     SQLiteDatabase,
 };
-
-pub fn add_database_decls(working_set: &mut StateWorkingSet) {
-    add_commands_decls(working_set);
-    add_expression_decls(working_set);
-}
diff --git a/crates/nu-command/src/database/values/dsl/expression.rs b/crates/nu-command/src/database/values/dsl/expression.rs
index 896cf4d50..e2e57f9a4 100644
--- a/crates/nu-command/src/database/values/dsl/expression.rs
+++ b/crates/nu-command/src/database/values/dsl/expression.rs
@@ -1,6 +1,6 @@
 use nu_protocol::{
     ast::{Operator, PathMember},
-    CustomValue, ShellError, Span, Type, Value,
+    CustomValue, PipelineData, ShellError, Span, Type, Value,
 };
 use serde::{Deserialize, Serialize};
 use sqlparser::ast::{BinaryOperator, Expr, Ident};
@@ -160,6 +160,11 @@ impl ExprDb {
         }
     }
 
+    pub fn try_from_pipeline(input: PipelineData, span: Span) -> Result<Self, ShellError> {
+        let value = input.into_value(span);
+        Self::try_from_value(&value)
+    }
+
     pub fn into_value(self, span: Span) -> Value {
         Value::CustomValue {
             val: Box::new(self),
@@ -273,6 +278,41 @@ impl ExprDb {
 
                 Value::Record { cols, vals, span }
             }
+            Expr::Function(function) => {
+                let cols = vec![
+                    "name".into(),
+                    "args".into(),
+                    "over".into(),
+                    "distinct".into(),
+                ];
+                let name = Value::String {
+                    val: function.name.to_string(),
+                    span,
+                };
+
+                let args: Vec<Value> = function
+                    .args
+                    .iter()
+                    .map(|arg| Value::String {
+                        val: arg.to_string(),
+                        span,
+                    })
+                    .collect();
+                let args = Value::List { vals: args, span };
+
+                let over = Value::String {
+                    val: format!("{:?}", function.over),
+                    span,
+                };
+
+                let distinct = Value::Bool {
+                    val: function.distinct,
+                    span,
+                };
+
+                let vals = vec![name, args, over, distinct];
+                Value::Record { cols, vals, span }
+            }
             Expr::Nested(expr) => ExprDb::expr_to_value(expr, span),
             Expr::CompoundIdentifier(_) => todo!(),
             Expr::IsNull(_) => todo!(),
@@ -292,7 +332,6 @@ impl ExprDb {
             Expr::Collate { .. } => todo!(),
             Expr::TypedString { .. } => todo!(),
             Expr::MapAccess { .. } => todo!(),
-            Expr::Function(_) => todo!(),
             Expr::Case { .. } => todo!(),
             Expr::Exists(_) => todo!(),
             Expr::Subquery(_) => todo!(),
diff --git a/crates/nu-command/src/database/values/sqlite.rs b/crates/nu-command/src/database/values/sqlite.rs
index 2189bcf0b..cb2c80199 100644
--- a/crates/nu-command/src/database/values/sqlite.rs
+++ b/crates/nu-command/src/database/values/sqlite.rs
@@ -5,7 +5,7 @@ use crate::database::values::definitions::{
 use nu_protocol::{CustomValue, PipelineData, ShellError, Span, Spanned, Value};
 use rusqlite::{types::ValueRef, Connection, Row};
 use serde::{Deserialize, Serialize};
-use sqlparser::ast::Query;
+use sqlparser::ast::Statement;
 use std::{
     fs::File,
     io::Read,
@@ -20,14 +20,14 @@ pub struct SQLiteDatabase {
     // 1) YAGNI, 2) it's not obvious how cloning a connection could work, 3) state
     // management gets tricky quick. Revisit this approach if we find a compelling use case.
     pub path: PathBuf,
-    pub query: Option<Query>,
+    pub statement: Option<Statement>,
 }
 
 impl SQLiteDatabase {
     pub fn new(path: &Path) -> Self {
         Self {
             path: PathBuf::from(path),
-            query: None,
+            statement: None,
         }
     }
 
@@ -52,7 +52,7 @@ impl SQLiteDatabase {
             Value::CustomValue { val, span } => match val.as_any().downcast_ref::<Self>() {
                 Some(db) => Ok(Self {
                     path: db.path.clone(),
-                    query: db.query.clone(),
+                    statement: db.statement.clone(),
                 }),
                 None => Err(ShellError::CantConvert(
                     "database".into(),
@@ -96,8 +96,8 @@ impl SQLiteDatabase {
     }
 
     pub fn collect(&self, call_span: Span) -> Result<Value, ShellError> {
-        let sql = match &self.query {
-            Some(query) => Ok(format!("{}", query)),
+        let sql = match &self.statement {
+            Some(statement) => Ok(format!("{}", statement)),
             None => Err(ShellError::GenericError(
                 "Error collecting from db".into(),
                 "No query found in connection".into(),
@@ -131,8 +131,8 @@ impl SQLiteDatabase {
             span,
         };
 
-        let query = match &self.query {
-            Some(query) => format!("{query}"),
+        let query = match &self.statement {
+            Some(statement) => format!("{statement}"),
             None => "".into(),
         };
 
@@ -351,7 +351,7 @@ impl CustomValue for SQLiteDatabase {
     fn clone_value(&self, span: Span) -> Value {
         let cloned = SQLiteDatabase {
             path: self.path.clone(),
-            query: self.query.clone(),
+            statement: self.statement.clone(),
         };
 
         Value::CustomValue {