Repository: ploomber/jupysql (language: python)

Issue:
Interested in Spark SQL support via spark connect?
Now that there is a thin client for spark: Spark Connect, I've forked your library and been able to add in basic Spark support fairly easily. For now to avoid computation I've directly outputted the Dataframe, as this avoids unnecessary computation. If there would be interest in merging this back to your main, I can work on integrating with the `ResultSet`.

Open to suggestions, but for now this is working really well for me, in terms of providing all the great features like composable CTEs and syntax highlighting, with lazy eval, but still validating the sql against spark, inc schema as it goes.

https://github.com/gilcloud/jupysql


Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bfefa57d2..a15174f7f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,8 @@
 
 ## 0.10.7dev
 
+* [Feature] Add Spark Connection as a dialect for Jupysql ([#965](https://github.com/ploomber/jupysql/issues/965)) (by [@gilandose](https://github.com/gilandose))
+
 ## 0.10.6 (2023-12-21)
 
 * [Fix] Fix error when `%sql` includes a query with negative numbers ([#958](https://github.com/ploomber/jupysql/issues/958))
diff --git a/doc/_toc.yml b/doc/_toc.yml
index 2d9850b10..f667e807b 100644
--- a/doc/_toc.yml
+++ b/doc/_toc.yml
@@ -43,6 +43,7 @@ parts:
       - file: integrations/duckdb-native
       - file: integrations/compatibility
       - file: integrations/chdb
+      - file: integrations/spark
 
   - caption: API Reference
     chapters:
diff --git a/doc/api/configuration.md b/doc/api/configuration.md
index e2bb114a5..254ea712a 100644
--- a/doc/api/configuration.md
+++ b/doc/api/configuration.md
@@ -234,6 +234,26 @@ value enables the ones from previous values plus new ones:
 - `2`: All feedback
   - Footer to distinguish pandas/polars data frames from JupySQL's result sets
 
+## `lazy_execution`
+
+```{versionadded} 0.10.7
+This option only works when connecting to Spark
+```
+
+Default: `False`
+
+Return lazy relation to dataset rather than executing through JupySql.
+
+```{code-cell} ipython3
+%config SqlMagic.lazy_execution = True
+df = %sql SELECT * FROM languages
+```
+
+```{code-cell} ipython3
+%config SqlMagic.lazy_execution = False
+res = %sql SELECT * FROM languages
+```
+
 ## `named_parameters`
 
 ```{versionadded} 0.9
diff --git a/doc/conf.py b/doc/conf.py
index 5e1792154..39080d77d 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -27,6 +27,7 @@
     "integrations/oracle.ipynb",
     "integrations/snowflake.ipynb",
     "integrations/redshift.ipynb",
+    "integrations/spark.ipynb",
 ]
 nb_execution_in_temp = True
 nb_execution_show_tb = True
diff --git a/doc/integrations/compatibility.md b/doc/integrations/compatibility.md
index 4e6b36432..d59760a98 100644
--- a/doc/integrations/compatibility.md
+++ b/doc/integrations/compatibility.md
@@ -114,4 +114,20 @@ These table reflects the compatibility status of JupySQL `>=0.7`
 - Listing tables with `%sqlcmd tables` ✅
 - Listing columns with `%sqlcmd columns` ✅
 - Parametrized SQL queries via `{{parameter}}` ✅
-- Interactive SQL queries via `--interact` ✅
\ No newline at end of file
+- Interactive SQL queries via `--interact` ✅
+
+## Spark
+
+- Running queries with `%%sql` ✅
+- CTEs with `%%sql --save NAME` ✅
+- Plotting with `%%sqlplot boxplot` ❓
+- Plotting with `%%sqlplot bar` ✅
+- Plotting with `%%sqlplot pie` ✅
+- Plotting with `%%sqlplot histogram` ✅
+- Plotting with `ggplot` ✅ 
+- Profiling tables with `%sqlcmd profile` ✅
+- Listing tables with `%sqlcmd tables` ❌
+- Listing columns with `%sqlcmd columns` ❌
+- Parametrized SQL queries via `{{parameter}}` ✅
+- Interactive SQL queries via `--interact` ✅
+- Persisting Dataframes via `--persist` ✅
\ No newline at end of file
diff --git a/doc/integrations/spark.ipynb b/doc/integrations/spark.ipynb
new file mode 100644
index 000000000..4f150500d
--- /dev/null
+++ b/doc/integrations/spark.ipynb
@@ -0,0 +1,1399 @@
+{
+ "cells": [
+  {
+   "attachments": {},
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Spark\n",
+    "\n",
+    "This tutorial will show you how to get a Spark instance up and running locally to integrate with JupySQL. You can run this in a Jupyter notebook. We'll use [Spark Connect](https://spark.apache.org/docs/latest/api/python/getting_started/quickstart_connect.html) which is the new thin client for Spark"
+   ]
+  },
+  {
+   "attachments": {},
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Pre-requisites\n",
+    "\n",
+    "To run this tutorial, you need to install following Python packages:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 14,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Note: you may need to restart the kernel to use updated packages.\n"
+     ]
+    }
+   ],
+   "source": [
+    "%pip install jupysql pyspark==3.4.1 arrow pyarrow==12.0.1 pandas grpcio-status --quiet"
+   ]
+  },
+  {
+   "attachments": {},
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Start Spark instance\n",
+    "\n",
+    "We fetch the official image, create a new database, and user (this will take a few seconds)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "12f699ee8e8e35ab10186f3c39024a7e443691bb4213e56ca3c2e90cd80daf1b\n"
+     ]
+    }
+   ],
+   "source": [
+    "%%bash\n",
+    "docker run -p 15002:15002 -p 4040:4040 -d --name spark wh1isper/sparglim-server"
+   ]
+  },
+  {
+   "attachments": {},
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Our database is running, let's load some data!"
+   ]
+  },
+  {
+   "attachments": {},
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Load sample data\n",
+    "\n",
+    "Now, let's fetch some sample data. We'll be using the [NYC taxi dataset](https://www.nyc.gov/site/tlc/about/tlc-trip-record-data.page):"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "import pandas as pd\n",
+    "from pyspark.sql.connect.session import SparkSession\n",
+    "\n",
+    "spark = SparkSession.builder.remote(\"sc://localhost\").getOrCreate()\n",
+    "\n",
+    "df = pd.read_parquet(\n",
+    "    \"https://d37ci6vzurychx.cloudfront.net/trip-data/yellow_tripdata_2021-01.parquet\"\n",
+    ")\n",
+    "sparkDf = spark.createDataFrame(df.head(10000))"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Set [eagerEval](https://spark.apache.org/docs/latest/api/python/getting_started/quickstart_df.html#Viewing-Data) on to print dataframes, This makes Spark print dataframes eagerly in notebook environments, rather than it's default lazy execution which requires .show() to see the data. In Spark 3.4.1 we need to override, as below, but in 3.5.0 it will print in html. "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 17,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def __pretty_(self, p, cycle):\n",
+    "    self.show(truncate=False)\n",
+    "\n",
+    "\n",
+    "from pyspark.sql.connect.dataframe import DataFrame\n",
+    "\n",
+    "DataFrame._repr_pretty_ = __pretty_\n",
+    "spark.conf.set(\"spark.sql.repl.eagerEval.enabled\", True)"
+   ]
+  },
+  {
+   "attachments": {},
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Add dataset to temporary view to allow querying:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "sparkDf.createOrReplaceTempView(\"taxi\")"
+   ]
+  },
+  {
+   "attachments": {},
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Query\n",
+    "\n",
+    "Now, let's start JupySQL, authenticate, and query the data!"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 19,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "The sql extension is already loaded. To reload it, use:\n",
+      "  %reload_ext sql\n"
+     ]
+    }
+   ],
+   "source": [
+    "%load_ext sql"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 20,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "%sql spark"
+   ]
+  },
+  {
+   "attachments": {},
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "```{important}\n",
+    "If the cell above fails, you might have some missing packages. Message us on [Slack](https://ploomber.io/community) and we'll help you!\n",
+    "```"
+   ]
+  },
+  {
+   "attachments": {},
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "List the tables in the database:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 22,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<span style=\"None\">Running query in &#x27;SparkSession&#x27;</span>"
+      ],
+      "text/plain": [
+       "Running query in 'SparkSession'"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "<table>\n",
+       "    <thead>\n",
+       "        <tr>\n",
+       "            <th>namespace</th>\n",
+       "            <th>viewName</th>\n",
+       "            <th>isTemporary</th>\n",
+       "        </tr>\n",
+       "    </thead>\n",
+       "    <tbody>\n",
+       "        <tr>\n",
+       "            <td></td>\n",
+       "            <td>taxi</td>\n",
+       "            <td>True</td>\n",
+       "        </tr>\n",
+       "    </tbody>\n",
+       "</table>"
+      ],
+      "text/plain": [
+       "+-----------+----------+-------------+\n",
+       "| namespace | viewName | isTemporary |\n",
+       "+-----------+----------+-------------+\n",
+       "|           |   taxi   |     True    |\n",
+       "+-----------+----------+-------------+"
+      ]
+     },
+     "execution_count": 22,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "%sql show views in default"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "We can turn on `lazy_spark` to avoid executing spark plan and return a Spark Dataframe"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 23,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%config SqlMagic.lazy_execution = True"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<span style=\"None\">Running query in &#x27;SparkSession&#x27;</span>"
+      ],
+      "text/plain": [
+       "Running query in 'SparkSession'"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "+---------+--------+-----------+\n",
+      "|namespace|viewName|isTemporary|\n",
+      "+---------+--------+-----------+\n",
+      "|         |taxi    |true       |\n",
+      "+---------+--------+-----------+\n",
+      "\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": []
+     },
+     "execution_count": 8,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "%sql show views in default"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 24,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%config SqlMagic.lazy_execution = False"
+   ]
+  },
+  {
+   "attachments": {},
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "List columns in the taxi table:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 25,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<span style=\"None\">Running query in &#x27;SparkSession&#x27;</span>"
+      ],
+      "text/plain": [
+       "Running query in 'SparkSession'"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "root\n",
+      " |-- VendorID: long (nullable = true)\n",
+      " |-- tpep_pickup_datetime: timestamp (nullable = true)\n",
+      " |-- tpep_dropoff_datetime: timestamp (nullable = true)\n",
+      " |-- passenger_count: double (nullable = true)\n",
+      " |-- trip_distance: double (nullable = true)\n",
+      " |-- RatecodeID: double (nullable = true)\n",
+      " |-- store_and_fwd_flag: string (nullable = true)\n",
+      " |-- PULocationID: long (nullable = true)\n",
+      " |-- DOLocationID: long (nullable = true)\n",
+      " |-- payment_type: long (nullable = true)\n",
+      " |-- fare_amount: double (nullable = true)\n",
+      " |-- extra: double (nullable = true)\n",
+      " |-- mta_tax: double (nullable = true)\n",
+      " |-- tip_amount: double (nullable = true)\n",
+      " |-- tolls_amount: double (nullable = true)\n",
+      " |-- improvement_surcharge: double (nullable = true)\n",
+      " |-- total_amount: double (nullable = true)\n",
+      " |-- congestion_surcharge: double (nullable = true)\n",
+      " |-- airport_fee: double (nullable = true)\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "df = %sql select * from taxi\n",
+    "df.sqlaproxy.dataframe.printSchema()"
+   ]
+  },
+  {
+   "attachments": {},
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Query our data:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 26,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<span style=\"None\">Running query in &#x27;SparkSession&#x27;</span>"
+      ],
+      "text/plain": [
+       "Running query in 'SparkSession'"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "<table>\n",
+       "    <thead>\n",
+       "        <tr>\n",
+       "            <th>count(1)</th>\n",
+       "        </tr>\n",
+       "    </thead>\n",
+       "    <tbody>\n",
+       "        <tr>\n",
+       "            <td>10000</td>\n",
+       "        </tr>\n",
+       "    </tbody>\n",
+       "</table>"
+      ],
+      "text/plain": [
+       "+----------+\n",
+       "| count(1) |\n",
+       "+----------+\n",
+       "|  10000   |\n",
+       "+----------+"
+      ]
+     },
+     "execution_count": 26,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "%%sql\n",
+    "SELECT COUNT(*) FROM taxi"
+   ]
+  },
+  {
+   "attachments": {},
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Parameterize queries"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 27,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "threshold = 10"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 28,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<span style=\"None\">Running query in &#x27;SparkSession&#x27;</span>"
+      ],
+      "text/plain": [
+       "Running query in 'SparkSession'"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "<table>\n",
+       "    <thead>\n",
+       "        <tr>\n",
+       "            <th>count(1)</th>\n",
+       "        </tr>\n",
+       "    </thead>\n",
+       "    <tbody>\n",
+       "        <tr>\n",
+       "            <td>9476</td>\n",
+       "        </tr>\n",
+       "    </tbody>\n",
+       "</table>"
+      ],
+      "text/plain": [
+       "+----------+\n",
+       "| count(1) |\n",
+       "+----------+\n",
+       "|   9476   |\n",
+       "+----------+"
+      ]
+     },
+     "execution_count": 28,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "%%sql\n",
+    "SELECT COUNT(*) FROM taxi\n",
+    "WHERE trip_distance < {{threshold}}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 29,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "threshold = 0.5"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 30,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<span style=\"None\">Running query in &#x27;SparkSession&#x27;</span>"
+      ],
+      "text/plain": [
+       "Running query in 'SparkSession'"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "<table>\n",
+       "    <thead>\n",
+       "        <tr>\n",
+       "            <th>count(1)</th>\n",
+       "        </tr>\n",
+       "    </thead>\n",
+       "    <tbody>\n",
+       "        <tr>\n",
+       "            <td>642</td>\n",
+       "        </tr>\n",
+       "    </tbody>\n",
+       "</table>"
+      ],
+      "text/plain": [
+       "+----------+\n",
+       "| count(1) |\n",
+       "+----------+\n",
+       "|   642    |\n",
+       "+----------+"
+      ]
+     },
+     "execution_count": 30,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "%%sql\n",
+    "SELECT COUNT(*) FROM taxi\n",
+    "WHERE trip_distance < {{threshold}}"
+   ]
+  },
+  {
+   "attachments": {},
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## CTEs"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 31,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<span style=\"None\">Running query in &#x27;SparkSession&#x27;</span>"
+      ],
+      "text/plain": [
+       "Running query in 'SparkSession'"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "<span style=\"None\">Skipping execution...</span>"
+      ],
+      "text/plain": [
+       "Skipping execution..."
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%%sql --save many_passengers --no-execute\n",
+    "SELECT *\n",
+    "FROM taxi\n",
+    "WHERE passenger_count > 3\n",
+    "-- remove top 1% outliers for better visualization\n",
+    "AND trip_distance < 18.93"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 32,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<span style=\"None\">Running query in &#x27;SparkSession&#x27;</span>"
+      ],
+      "text/plain": [
+       "Running query in 'SparkSession'"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "<table>\n",
+       "    <thead>\n",
+       "        <tr>\n",
+       "            <th>min(trip_distance)</th>\n",
+       "            <th>avg(trip_distance)</th>\n",
+       "            <th>max(trip_distance)</th>\n",
+       "        </tr>\n",
+       "    </thead>\n",
+       "    <tbody>\n",
+       "        <tr>\n",
+       "            <td>0.0</td>\n",
+       "            <td>3.1091381872213963</td>\n",
+       "            <td>18.46</td>\n",
+       "        </tr>\n",
+       "    </tbody>\n",
+       "</table>"
+      ],
+      "text/plain": [
+       "+--------------------+--------------------+--------------------+\n",
+       "| min(trip_distance) | avg(trip_distance) | max(trip_distance) |\n",
+       "+--------------------+--------------------+--------------------+\n",
+       "|        0.0         | 3.1091381872213963 |       18.46        |\n",
+       "+--------------------+--------------------+--------------------+"
+      ]
+     },
+     "execution_count": 32,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "%%sql --save trip_stats --with many_passengers\n",
+    "SELECT MIN(trip_distance), AVG(trip_distance), MAX(trip_distance)\n",
+    "FROM many_passengers"
+   ]
+  },
+  {
+   "attachments": {},
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "This is what JupySQL executes:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 33,
+   "metadata": {
+    "scrolled": true,
+    "tags": []
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "WITH `many_passengers` AS (\n",
+      "SELECT *\n",
+      "FROM taxi\n",
+      "WHERE passenger_count > 3\n",
+      "\n",
+      "AND trip_distance < 18.93)\n",
+      "SELECT MIN(trip_distance), AVG(trip_distance), MAX(trip_distance)\n",
+      "FROM many_passengers\n"
+     ]
+    }
+   ],
+   "source": [
+    "query = %sqlcmd snippets trip_stats\n",
+    "print(query)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Profiling"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 34,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<div style='position: sticky; left: 0; padding: 10px; font-size: 12px; color: #FFA500'><strong></strong> Following statistics are not available in\n",
+       "            SparkSession: STD, 25%, 50%, 75%</div><style>\n",
+       " #profile-table td:first-child {\n",
+       "  position: sticky;\n",
+       "  left: 0;\n",
+       "  background-color: var(--jp-cell-editor-background);\n",
+       "  font-weight: bold;\n",
+       "}\n",
+       " #profile-table thead tr th:first-child {\n",
+       "  position: sticky;\n",
+       "  left: 0;\n",
+       "  background-color: var(--jp-cell-editor-background);\n",
+       "  font-weight: bold; /* Adding bold text */\n",
+       "}\n",
+       "            </style><style></style><table id=\"profile-table-928b62f4de2f447091660aad39b6d103\">\n",
+       "    <thead>\n",
+       "        <tr>\n",
+       "            <th> </th>\n",
+       "            <th>VendorID</th>\n",
+       "            <th>tpep_pickup_datetime</th>\n",
+       "            <th>tpep_dropoff_datetime</th>\n",
+       "            <th>passenger_count</th>\n",
+       "            <th>trip_distance</th>\n",
+       "            <th>RatecodeID</th>\n",
+       "            <th>store_and_fwd_flag</th>\n",
+       "            <th>PULocationID</th>\n",
+       "            <th>DOLocationID</th>\n",
+       "            <th>payment_type</th>\n",
+       "            <th>fare_amount</th>\n",
+       "            <th>extra</th>\n",
+       "            <th>mta_tax</th>\n",
+       "            <th>tip_amount</th>\n",
+       "            <th>tolls_amount</th>\n",
+       "            <th>improvement_surcharge</th>\n",
+       "            <th>total_amount</th>\n",
+       "            <th>congestion_surcharge</th>\n",
+       "            <th>airport_fee</th>\n",
+       "        </tr>\n",
+       "    </thead>\n",
+       "    <tbody>\n",
+       "        <tr>\n",
+       "            <td>count</td>\n",
+       "            <td>10000</td>\n",
+       "            <td>10000</td>\n",
+       "            <td>10000</td>\n",
+       "            <td>10000</td>\n",
+       "            <td>10000</td>\n",
+       "            <td>10000</td>\n",
+       "            <td>10000</td>\n",
+       "            <td>10000</td>\n",
+       "            <td>10000</td>\n",
+       "            <td>10000</td>\n",
+       "            <td>10000</td>\n",
+       "            <td>10000</td>\n",
+       "            <td>10000</td>\n",
+       "            <td>10000</td>\n",
+       "            <td>10000</td>\n",
+       "            <td>10000</td>\n",
+       "            <td>10000</td>\n",
+       "            <td>10000</td>\n",
+       "            <td>0</td>\n",
+       "        </tr>\n",
+       "        <tr>\n",
+       "            <td>unique</td>\n",
+       "            <td>2</td>\n",
+       "            <td>8766</td>\n",
+       "            <td>8745</td>\n",
+       "            <td>7</td>\n",
+       "            <td>1243</td>\n",
+       "            <td>6</td>\n",
+       "            <td>2</td>\n",
+       "            <td>173</td>\n",
+       "            <td>230</td>\n",
+       "            <td>4</td>\n",
+       "            <td>228</td>\n",
+       "            <td>8</td>\n",
+       "            <td>3</td>\n",
+       "            <td>504</td>\n",
+       "            <td>18</td>\n",
+       "            <td>3</td>\n",
+       "            <td>959</td>\n",
+       "            <td>3</td>\n",
+       "            <td>0</td>\n",
+       "        </tr>\n",
+       "        <tr>\n",
+       "            <td>top</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>2021-01-01 00:41:19</td>\n",
+       "            <td>2021-01-02 00:00:00</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>N</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>None</td>\n",
+       "        </tr>\n",
+       "        <tr>\n",
+       "            <td>freq</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>4</td>\n",
+       "            <td>7</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>9808</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>0</td>\n",
+       "        </tr>\n",
+       "        <tr>\n",
+       "            <td>mean</td>\n",
+       "            <td>1.6901</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>1.5080</td>\n",
+       "            <td>3.1002</td>\n",
+       "            <td>1.0712</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>158.5551</td>\n",
+       "            <td>154.7296</td>\n",
+       "            <td>1.3819</td>\n",
+       "            <td>11.8822</td>\n",
+       "            <td>0.8259</td>\n",
+       "            <td>0.4864</td>\n",
+       "            <td>1.7846</td>\n",
+       "            <td>0.2246</td>\n",
+       "            <td>0.2945</td>\n",
+       "            <td>16.9696</td>\n",
+       "            <td>2.1063</td>\n",
+       "            <td>nan</td>\n",
+       "        </tr>\n",
+       "        <tr>\n",
+       "            <td>std</td>\n",
+       "            <td>0.4625</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>1.1354</td>\n",
+       "            <td>3.5970</td>\n",
+       "            <td>1.0755</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>70.9288</td>\n",
+       "            <td>75.2504</td>\n",
+       "            <td>0.5552</td>\n",
+       "            <td>10.8420</td>\n",
+       "            <td>1.1167</td>\n",
+       "            <td>0.1041</td>\n",
+       "            <td>2.4351</td>\n",
+       "            <td>1.2730</td>\n",
+       "            <td>0.0570</td>\n",
+       "            <td>12.5023</td>\n",
+       "            <td>0.9562</td>\n",
+       "            <td>nan</td>\n",
+       "        </tr>\n",
+       "        <tr>\n",
+       "            <td>min</td>\n",
+       "            <td>1</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>0.0</td>\n",
+       "            <td>0.0</td>\n",
+       "            <td>1.0</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>1</td>\n",
+       "            <td>1</td>\n",
+       "            <td>1</td>\n",
+       "            <td>-100.0</td>\n",
+       "            <td>-0.5</td>\n",
+       "            <td>-0.5</td>\n",
+       "            <td>-1.07</td>\n",
+       "            <td>-6.12</td>\n",
+       "            <td>-0.3</td>\n",
+       "            <td>-100.3</td>\n",
+       "            <td>-2.5</td>\n",
+       "            <td>nan</td>\n",
+       "        </tr>\n",
+       "        <tr>\n",
+       "            <td>25%</td>\n",
+       "            <td>1.0000</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>1.0000</td>\n",
+       "            <td>1.0400</td>\n",
+       "            <td>1.0000</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>100.0000</td>\n",
+       "            <td>83.0000</td>\n",
+       "            <td>1.0000</td>\n",
+       "            <td>6.0000</td>\n",
+       "            <td>0.0000</td>\n",
+       "            <td>0.5000</td>\n",
+       "            <td>0.0000</td>\n",
+       "            <td>0.0000</td>\n",
+       "            <td>0.3000</td>\n",
+       "            <td>10.3000</td>\n",
+       "            <td>2.5000</td>\n",
+       "            <td>nan</td>\n",
+       "        </tr>\n",
+       "        <tr>\n",
+       "            <td>50%</td>\n",
+       "            <td>2.0000</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>1.0000</td>\n",
+       "            <td>1.9300</td>\n",
+       "            <td>1.0000</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>152.0000</td>\n",
+       "            <td>151.0000</td>\n",
+       "            <td>1.0000</td>\n",
+       "            <td>8.5000</td>\n",
+       "            <td>0.5000</td>\n",
+       "            <td>0.5000</td>\n",
+       "            <td>1.5400</td>\n",
+       "            <td>0.0000</td>\n",
+       "            <td>0.3000</td>\n",
+       "            <td>13.5500</td>\n",
+       "            <td>2.5000</td>\n",
+       "            <td>nan</td>\n",
+       "        </tr>\n",
+       "        <tr>\n",
+       "            <td>75%</td>\n",
+       "            <td>2.0000</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>2.0000</td>\n",
+       "            <td>3.6000</td>\n",
+       "            <td>1.0000</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>234.0000</td>\n",
+       "            <td>234.0000</td>\n",
+       "            <td>2.0000</td>\n",
+       "            <td>13.5000</td>\n",
+       "            <td>2.5000</td>\n",
+       "            <td>0.5000</td>\n",
+       "            <td>2.6500</td>\n",
+       "            <td>0.0000</td>\n",
+       "            <td>0.3000</td>\n",
+       "            <td>19.3000</td>\n",
+       "            <td>2.5000</td>\n",
+       "            <td>nan</td>\n",
+       "        </tr>\n",
+       "        <tr>\n",
+       "            <td>max</td>\n",
+       "            <td>2</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>6.0</td>\n",
+       "            <td>45.92</td>\n",
+       "            <td>99.0</td>\n",
+       "            <td>nan</td>\n",
+       "            <td>265</td>\n",
+       "            <td>265</td>\n",
+       "            <td>4</td>\n",
+       "            <td>121.0</td>\n",
+       "            <td>3.5</td>\n",
+       "            <td>0.5</td>\n",
+       "            <td>80.0</td>\n",
+       "            <td>25.5</td>\n",
+       "            <td>0.3</td>\n",
+       "            <td>137.76</td>\n",
+       "            <td>2.5</td>\n",
+       "            <td>nan</td>\n",
+       "        </tr>\n",
+       "    </tbody>\n",
+       "</table><div style='position: sticky; left: 0; padding: 10px; font-size: 12px; color: black; background-color: white;'><strong></strong> </div>"
+      ],
+      "text/plain": [
+       "+--------+----------+----------------------+-----------------------+-----------------+---------------+------------+--------------------+--------------+--------------+--------------+-------------+--------+---------+------------+--------------+-----------------------+--------------+----------------------+-------------+\n",
+       "|        | VendorID | tpep_pickup_datetime | tpep_dropoff_datetime | passenger_count | trip_distance | RatecodeID | store_and_fwd_flag | PULocationID | DOLocationID | payment_type | fare_amount | extra  | mta_tax | tip_amount | tolls_amount | improvement_surcharge | total_amount | congestion_surcharge | airport_fee |\n",
+       "+--------+----------+----------------------+-----------------------+-----------------+---------------+------------+--------------------+--------------+--------------+--------------+-------------+--------+---------+------------+--------------+-----------------------+--------------+----------------------+-------------+\n",
+       "| count  |  10000   |        10000         |         10000         |      10000      |     10000     |   10000    |       10000        |    10000     |    10000     |    10000     |    10000    | 10000  |  10000  |   10000    |    10000     |         10000         |    10000     |        10000         |      0      |\n",
+       "| unique |    2     |         8766         |          8745         |        7        |      1243     |     6      |         2          |     173      |     230      |      4       |     228     |   8    |    3    |    504     |      18      |           3           |     959      |          3           |      0      |\n",
+       "|  top   |   nan    | 2021-01-01 00:41:19  |  2021-01-02 00:00:00  |       nan       |      nan      |    nan     |         N          |     nan      |     nan      |     nan      |     nan     |  nan   |   nan   |    nan     |     nan      |          nan          |     nan      |         nan          |     None    |\n",
+       "|  freq  |   nan    |          4           |           7           |       nan       |      nan      |    nan     |        9808        |     nan      |     nan      |     nan      |     nan     |  nan   |   nan   |    nan     |     nan      |          nan          |     nan      |         nan          |      0      |\n",
+       "|  mean  |  1.6901  |         nan          |          nan          |      1.5080     |     3.1002    |   1.0712   |        nan         |   158.5551   |   154.7296   |    1.3819    |   11.8822   | 0.8259 |  0.4864 |   1.7846   |    0.2246    |         0.2945        |   16.9696    |        2.1063        |     nan     |\n",
+       "|  std   |  0.4625  |         nan          |          nan          |      1.1354     |     3.5970    |   1.0755   |        nan         |   70.9288    |   75.2504    |    0.5552    |   10.8420   | 1.1167 |  0.1041 |   2.4351   |    1.2730    |         0.0570        |   12.5023    |        0.9562        |     nan     |\n",
+       "|  min   |    1     |         nan          |          nan          |       0.0       |      0.0      |    1.0     |        nan         |      1       |      1       |      1       |    -100.0   |  -0.5  |   -0.5  |   -1.07    |    -6.12     |          -0.3         |    -100.3    |         -2.5         |     nan     |\n",
+       "|  25%   |  1.0000  |         nan          |          nan          |      1.0000     |     1.0400    |   1.0000   |        nan         |   100.0000   |   83.0000    |    1.0000    |    6.0000   | 0.0000 |  0.5000 |   0.0000   |    0.0000    |         0.3000        |   10.3000    |        2.5000        |     nan     |\n",
+       "|  50%   |  2.0000  |         nan          |          nan          |      1.0000     |     1.9300    |   1.0000   |        nan         |   152.0000   |   151.0000   |    1.0000    |    8.5000   | 0.5000 |  0.5000 |   1.5400   |    0.0000    |         0.3000        |   13.5500    |        2.5000        |     nan     |\n",
+       "|  75%   |  2.0000  |         nan          |          nan          |      2.0000     |     3.6000    |   1.0000   |        nan         |   234.0000   |   234.0000   |    2.0000    |   13.5000   | 2.5000 |  0.5000 |   2.6500   |    0.0000    |         0.3000        |   19.3000    |        2.5000        |     nan     |\n",
+       "|  max   |    2     |         nan          |          nan          |       6.0       |     45.92     |    99.0    |        nan         |     265      |     265      |      4       |    121.0    |  3.5   |   0.5   |    80.0    |     25.5     |          0.3          |    137.76    |         2.5          |     nan     |\n",
+       "+--------+----------+----------------------+-----------------------+-----------------+---------------+------------+--------------------+--------------+--------------+--------------+-------------+--------+---------+------------+--------------+-----------------------+--------------+----------------------+-------------+"
+      ]
+     },
+     "execution_count": 34,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "%sqlcmd profile -t taxi"
+   ]
+  },
+  {
+   "attachments": {},
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Plotting"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 35,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<Axes: title={'center': \"'trip_distance' from 'taxi'\"}, xlabel='trip_distance', ylabel='Count'>"
+      ]
+     },
+     "execution_count": 35,
+     "metadata": {},
+     "output_type": "execute_result"
+    },
+    {
+     "data": {
+      "image/png": "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VtOmTTVkyBBt27ZNISEheuedd5Sdna2FCxeWehtt27ZVv3799PrrrysvL0+33367kpOTdfDgwSu+d9GiRXr99dfVu3dvNW7cWCdPntRbb70lu92ue+65R9Lvl4wiIyP1/vvvq2nTpqpdu7Zatmypli1bqkuXLpo5c6bOnTunG264QevWrVNGRsZVzYX0+z1VL7zwgl588UV17txZDz74oHx8fLRt2zaFhYVp+vTpstvtmj9/vgYMGKB27dqpb9++CgoKUmZmplatWqU77rhDr7766lX3UBoTJkzQe++9p549e2rMmDGqXbu2Fi1apIyMDH3wwQclbgivaOXxGb300ktKT09XcnKyatasqdatW2vy5MmaNGmSHnroIfPnAagy3PeAGwDD+P3x7tjYWKNmzZqGJPMR/OJH2i/2CPulHruPjY011q5da7Ru3drw8fExmjdvbixbtqzMPZ05c8YYM2aMUadOHaNGjRrGfffdZxw+fPiKj93v2LHD6Nevn9GwYUPDx8fHCA4ONu69915j+/btLtvfvHmzERUVZXh7e7ts86effjJ69+5tBAYGGgEBAcbDDz9sHDlypMR+L/VY+8XmxTAM45133jFuueUWw8fHx6hVq5bRtWtXIykpyaVmw4YNRkxMjBEQEGD4+voajRs3NgYNGlSi99K43GP3sbGxF33P999/bzz00ENGYGCg4evra9x2223GypUrS/QoqcRneqmflUv1URp/5jNKS0szPD09jdGjR7ts8/z588att95qhIWFGSdOnHDpEXA3m2GU4912ANwmPDxcLVu21MqVK93dCgBcc7iHCAAAWB73EAEWcqUvZ/Tz8+MJIACWRCACLKRevXqXHR84cKASExMrpxkAqEIIRMB1ojTfRJ2UlHTZ8bCwsHLqBgCuLdxUDQAALI+bqgEAgOVxyawUioqKdOTIEdWsWZM/TAgAwDXCMAydPHlSYWFhV/yCUwJRKRw5cqTEX5EGAADXhsOHD6t+/fqXrSEQlULNmjUl/T6hdrvdzd0AAIDScDqdatCggfl7/HIIRKVQfJnMbrcTiAAAuMaU5nYXbqoGAACWRyACAACWRyACAACWRyACAACWRyACAACWRyACAACWRyACAACWRyACAACWRyACAACWRyACAACWRyACAACWRyACAACWRyACAACWRyACAACWRyACAACW5+nu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FAzD0KhRo7R8+XKtX79eERERLuNRUVHy8vJymd/9+/crMzOT+f0TioqKlJ+fz/yWg+7du2vXrl1KT083l/bt26t///7mv5nj8nXq1Cl9//33qlevXvn+DP+JG79RRS1ZssTw8fExEhMTjb179xrDhw83AgMDjaysLHe3dk06efKk8fXXXxtff/21Icl45ZVXjK+//tr48ccfDcMwjBkzZhiBgYHGRx99ZOzcudN44IEHjIiICOPMmTNu7rzqGzlypBEQEGBs3LjROHr0qLn89ttvZs2IESOMhg0bGuvXrze2b99uOBwOw+FwuLHra8uECROMlJQUIyMjw9i5c6cxYcIEw2azGevWrTMMg/mtCBc+ZWYYzPGf9cwzzxgbN240MjIyjC+//NKIjo426tata+Tk5BiGUX7zSyC6Tv3zn/80GjZsaHh7exu33XabsWXLFne3dM3asGGDIanEMnDgQMMwfn/0/m9/+5sREhJi+Pj4GN27dzf279/v3qavERebV0nGwoULzZozZ84YTz31lFGrVi2jevXqRu/evY2jR4+6r+lrzODBg41GjRoZ3t7eRlBQkNG9e3czDBkG81sR/hiImOM/55FHHjHq1atneHt7GzfccIPxyCOPGAcPHjTHy2t+bYZhGOVwBgsAAOCaxT1EAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEANwqISFBbdu2rdB93HnnnYqPjzdfh4eHa86cORW6TwDXFgIRgArxxxByKc8++6zL3yGqDNu2bdPw4cNLVUt4AqzB090NALAmwzBUWFgof39/+fv7V+q+g4KCKnV/AKo+zhABKHeDBg1SSkqK5s6dK5vNJpvNpsTERNlsNq1evVpRUVHy8fHRF198UeKS2aBBg9SrVy9NnTpVQUFBstvtGjFihAoKCkq179OnT+vxxx+Xv7+/6tWrp1mzZpWoufCsj2EYSkhIUMOGDeXj46OwsDCNGTNG0u9nuX788UeNHTvWPA5J+vXXX9WvXz/dcMMNql69ulq1aqX33nvPZR933nmnxowZo/Hjx6t27doKDQ1VQkKCS01ubq6efPJJhYSEyNfXVy1bttTKlSvN8S+++EKdO3eWn5+fGjRooDFjxuj06dOlmgcAZUMgAlDu5s6dK4fDoWHDhuno0aM6evSoGjRoIEmaMGGCZsyYoW+//VatW7e+6PuTk5P17bffauPGjXrvvff04YcfaurUqaXa93PPPaeUlBR99NFHWrdunTZu3KgdO3Zcsv6DDz7Q7Nmz9cYbb+jAgQNasWKFWrVqJUn68MMPVb9+fU2bNs08Dkk6e/asoqKitGrVKu3evVvDhw/XgAED9NVXX7lse9GiRapRo4a2bt2qmTNnatq0aUpKSpIkFRUVqWfPnvryyy/17rvvau/evZoxY4aqVasmSfr+++919913q0+fPtq5c6fef/99ffHFFxo1alSp5gFAGZXXX6MFgAv98S9+b9iwwZBkrFixwqVuypQpRps2bczXAwcONGrXrm2cPn3aXDd//nzD39/fKCwsvOw+T548aXh7extLly411/3666+Gn5+fSy+NGjUyZs+ebRiGYcyaNcto2rSpUVBQcNFtXlh7ObGxscYzzzxjvu7atavRqVMnl5pbb73VeP755w3DMIy1a9caHh4exv79+y+6vSFDhhjDhw93Wff5558bHh4expkzZ67YD4Cy4QwRgErVvn37K9a0adNG1atXN187HA6dOnVKhw8fvuz7vv/+exUUFKhDhw7mutq1a6tZs2aXfM/DDz+sM2fO6MYbb9SwYcO0fPlynT9//rL7KSws1IsvvqhWrVqpdu3a8vf319q1a5WZmelS98czYPXq1VNOTo4kKT09XfXr11fTpk0vuo9vvvlGiYmJ5j1W/v7+iomJUVFRkTIyMi7bH4Cy46ZqAJWqRo0a7m7BRYMGDbR//3599tlnSkpK0lNPPaWXX35ZKSkp8vLyuuh7Xn75Zc2dO1dz5sxRq1atVKNGDcXHx5e4z+mP77fZbCoqKpIk+fn5XbavU6dO6cknnzTvZ7pQw4YNy3KIAEqBQASgQnh7e6uwsPCq3vvNN9/ozJkzZmjYsmWL/P39zfuQLqVx48by8vLS1q1bzdBw4sQJfffdd+ratesl3+fn56f77rtP9913n+Li4tS8eXPt2rVL7dq1u+hxfPnll3rggQf02GOPSfr9fqDvvvtOkZGRpT7G1q1b66efftJ333130bNE7dq10969e9WkSZNSbxPA1eOSGYAKER4erq1bt+rQoUP65ZdfzDMjpVFQUKAhQ4Zo7969+vTTTzVlyhSNGjVKHh6X/0+Wv7+/hgwZoueee07r16/X7t27NWjQoMu+LzExUf/617+0e/du/fDDD3r33Xfl5+enRo0amcexadMm/fzzz/rll18kSTfddJOSkpK0efNmffvtt3ryySeVnZ1d6uOTpK5du6pLly7q06ePkpKSlJGRodWrV2vNmjWSpOeff16bN2/WqFGjlJ6ergMHDuijjz7ipmqgghCIAFSIZ599VtWqVVNkZKSCgoJK3F9zOd27d9dNN92kLl266JFHHtH9999f4pH1S3n55ZfVuXNn3XfffYqOjlanTp0UFRV1yfrAwEC99dZbuuOOO9S6dWt99tln+uSTT1SnTh1J0rRp03To0CE1btzY/P6iSZMmqV27doqJidGdd96p0NBQ9erVq9THV+yDDz7Qrbfeqn79+ikyMlLjx483z0a1bt1aKSkp+u6779S5c2fdcsstmjx5ssLCwsq8HwBXZjMMw3B3EwBQbNCgQcrNzdWKFSvc3QoAC+EMEQAAsDwCEYBrRmZmpstj6H9cynJZDgAuxCUzANeM8+fP69ChQ5ccDw8Pl6cnD88CKDsCEQAAsDwumQEAAMsjEAEAAMsjEAEAAMsjEAEAAMsjEAEAAMsjEAEAAMsjEAEAAMsjEAEAAMv7f+dZjQYV06HwAAAAAElFTkSuQmCC",
+      "text/plain": [
+       "<Figure size 640x480 with 1 Axes>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%sqlplot histogram --table taxi --column trip_distance --bins 10"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 36,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<Axes: title={'center': \"'trip_distance' from 'taxi'\"}, ylabel='trip_distance'>"
+      ]
+     },
+     "execution_count": 36,
+     "metadata": {},
+     "output_type": "execute_result"
+    },
+    {
+     "data": {
+      "image/png": "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p379+mnEiBHq16+f4uLilJmZ6enSAHgAYQaAqWRmZmro0KFKTExUbm6uSktLlZubq8TERA0dOpRAAzRDFsMwDE8X0ZBKSkoUEhKi4uJi7s0EmJzValVcXJwSExO1dOlSeXn97/uYzWZTamqq8vLytGfPHk45ASZXn89vRmYAmEZOTo4KCgr01FNPOQQZSfLy8lJaWpry8/OVk5PjoQoBeAJhBoBpFBYWSpISEhLq3F7TXtMPQPNAmAFgGpGRkZKkvLy8OrfXtNf0A9A8EGYAmEZKSopiYmL04osvymazOWyz2WxKT09XbGysUlJSPFQhAE8gzAAwDW9vb82aNUvLly9Xamqqw9VMqampWr58uV577TUm/wLNDIvmATCVwYMHa/HixXrkkUfUq1cve3tsbKwWL16swYMHe7A6AJ7ApdkATIkVgIGmrT6f34zMADAlb29v9e3b19NlAGgEmDMDAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMjTADAABMrVGFmZdeekkWi0VTpkyxt508eVITJkxQaGioAgMDNWTIEB06dMhzRQIAgEal0YSZDRs26E9/+pOSkpIc2qdOnaply5bp448/1po1a3Tw4EENHjzYQ1UCAIDGplGEmRMnTuiuu+7SggUL1KZNG3t7cXGx3n77bc2ePVvXX3+9kpOTtXDhQq1du1br1q3zYMUAAKCxaBRhZsKECRo0aJD69+/v0L5p0yadOnXKoT0+Pl4dOnRQbm5unfuqrKxUSUmJww8AAGi6Wni6gA8//FCbN2/Whg0bam0rKiqSj4+PWrdu7dAeHh6uoqKiOveXnp6uGTNmNESpAACgEfLoyMz+/fv18MMP629/+5v8/Pzcss+0tDQVFxfbf/bv3++W/QIAgMbJo2Fm06ZNOnz4sLp3764WLVqoRYsWWrNmjV5//XW1aNFC4eHhqqqq0vHjxx2ed+jQIUVERNS5T19fXwUHBzv8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pvP4449rzpw5DmtctWjRQlOnTtUrr7ziwcoAuEt9Pr9dGpn5/PPPtXLlylrtK1eu1BdffOHKLgHAKY8//rheffVVhYaGasGCBSosLNSCBQsUGhqqV199VY8//rinSwRwgbk0MpOUlKSXXnpJN998s0P7ihUr9MQTT+j77793W4Hni5EZoOmoqqpSq1atFBoaqgMHDqhFi/9N+6uurlb79u119OhRlZWVycfHx4OVAjhfDT4ys2fPHnXt2rVWe3x8vH744QdXdgkA55SRkaHq6mo9//zzslgsys7O1gcffKDs7GxZLBbNnDlT1dXVysjI8HSpAC4gl65mCgkJ0Y8//qiYmBiH9h9++EGtWrVyR10AUEvNopwWi0VxcXEqKCiwb4uJidHTTz/t0A9A8+BSmLnttts0ZcoULVmyRJ06dZJ0Osg88sgjuvXWW91aIADUqPl7M3bsWA0aNEiPPfaY/P39VVFRoS+++EIPPPCAQz8AzYNLc2aKi4t10003aePGjWrfvr0k6cCBA0pJSVFmZqZat27t7jpdxpwZoOmoqKhQQECAWrRooaioKPtNbiWpQ4cOOnjwoKqrq1VeXi5/f38PVgrgfNXn89vl00xr167V6tWr9f3338vf319JSUnq3bu3SwUDgDPWr18v6fRk36KiIj3xxBMaM2aM3n77bYdLtdevX6++fft6sFIAF5JLYUY6fc76xhtv1I033ujOegDgjP79739LkmJjY7Vv3z69/PLLevnllyWdXmcmNjZW+fn59n4AmgeXw0xWVpaysrJ0+PBh2Ww2h23vvPPOeRcGAL925MgRSdJTTz2le++9VxkZGdq7d686deqk8ePHa9GiRRo3bpy9H4DmwaUwM2PGDM2cOVNXXnmlIiMjuVM2gAsiLCxMkpSZman77rtPU6ZMsW+z2WxaunSpQz8AzYNLYebNN9/UokWLdM8997i7HgA4o4svvljS6QU6U1NTlZaWpoSEBOXl5Sk9PV0rVqxw6AegeXApzFRVValXr17urgUAziolJUUxMTG66KKLtHXrVoe/Q7GxsUpOTtbRo0eVkpLiwSoBXGgurQB8//336/3333d3LQBwVt7e3po1a5Y2btyowsJCh20HDx7Uxo0b9dprr8nb29tDFQLwBJdGZk6ePKm33npL//jHP5SUlKSWLVs6bJ89e7ZbigOAM6msrDzr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",
+      "text/plain": [
+       "<Figure size 640x480 with 1 Axes>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%sqlplot boxplot --table taxi --column trip_distance"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 37,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<span style=\"None\">Removing NULLs, if there exists any from payment_type</span>"
+      ],
+      "text/plain": [
+       "Removing NULLs, if there exists any from payment_type"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "<Axes: title={'center': 'taxi'}, xlabel='payment_type', ylabel='Count'>"
+      ]
+     },
+     "execution_count": 37,
+     "metadata": {},
+     "output_type": "execute_result"
+    },
+    {
+     "data": {
+      "image/png": "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t6/VqFEja9KkSdahQ4esv//971aDBg2sV155xbIsy3r99det9957zzp69KiVkpJiORwOa/Dgwa7z/+d//seKjIx0m/Pxxx+37rjjDtdjSdZPfvITa/Xq1VZGRoY1dOhQKywszBowYIC1adMm68CBA1afPn2sO++803XOjh07LLvdbiUmJlpHjx61tmzZYoWFhVlz5sxxm7d169bWypUrrcOHD1uPP/641ahRI+u7776zLl68aP3jH/+wJFkZGRnWyZMnrby8vGv+LPLy8iyHw2E9+uij1smTJ62TJ09aFy9eLHOPzZo1s1599VUrIyPDmjlzpuXt7W0dOHDAsizLKioqsiIiIqxHHnnE+vLLL60DBw5YDzzwgNW+fXursLCwrMsF4CoIRABuWN++fa2IiAirpKTEte/JJ5+0IiIirjp+z549liTrzJkzlmVZ1jfffGN5e3tbu3fvtizrP3/4mzdvbiUmJrrOkWTNnDnT9TglJcWSZL3++uuufW+99Zbl7+/vejxw4EDrz3/+s9tz/+1vf7NatWr1o/OePXvWkmS9//77lmVZ1ocffmhJsr7//vty/Twu/Xbu8vQ4fvx4t/N69+5tTZgwwVV7+/bt3X7OhYWFVv369a3NmzeXuT4AV+IlMwCVok+fPrLZbK7HDodDhw8fVnFxsVJTU/WrX/1Kbdq0UePGjdW3b19JUlZWliQpJCREMTExeuONNyRJ69evV2FhoX7961+7PUfnzp1d/w4KCpIkderUyW1fQUGBnE6nJOmLL77QvHnz1KhRI9f26KOP6uTJk/rhhx+uOm/Dhg1lt9tdL+lVlrL26HA4rnh88OBBVz9HjhxR48aNXf00bdpUBQUFV7xUCKB86nm6AAB1W0FBgaKjoxUdHa0333xTLVq0UFZWlqKjo1VUVOQaN3bsWI0aNUoJCQlavny57rvvPjVo0MBtLh8fH9e/S8PX1faVlJRIks6ePau5c+dq2LBhV9Tl7+9/1XlL5ymdozKVpcdrOXv2rLp3764333zzimMtWrSozFIB4xCIAFSK3bt3uz3etWuXbr75Zh06dEjfffedFixYoNDQUEnSZ599dsX5Q4YMUcOGDbV06VJt2rRJO3bsuOGaunXrpoyMDLVr167Cc/j6+kqSiouLy3XO1caXpcddu3bpwQcfdHt86623SvpPP6tXr1bLli1lt9vL2wqAa+AlMwCVIisrS1OmTFFGRobeeustvfDCC5o0aZLatGkjX19fvfDCC/rqq6+0bt06PfXUU1ec7+3trYceekgzZszQzTfffMVLRxUxa9Ys/fWvf9XcuXO1f/9+HTx4UKtWrdLMmTPLPEfbtm1ls9m0YcMGnTp1SmfPnr3uOWFhYdq9e7eOHTumb7/91nW1qSw9rlmzRm+88Yb+9a9/afbs2fr0008VFxcnSRo5cqSaN2+uu+++Wx999JEyMzO1fft2Pf744/r666/L3BOAKxGIAFSKBx98UOfPn1evXr0UGxurSZMmady4cWrRooUSExO1Zs0aRUZGasGCBVe8/bzUmDFjVFRUpIcffrhSaoqOjtaGDRu0ZcsW9ezZU3369FFCQoLatm1b5jl+8pOfaO7cuZo+fbqCgoJc4eRannjiCXl7eysyMtL1EmGp6/U4d+5crVq1Sp07d9Zf//pXvfXWW4qMjJQkNWjQQDt27FCbNm00bNgwRUREaMyYMSooKOCKEXCDbJb1/z4oBAAqqF+/furatauee+65G5rno48+0sCBA3X8+HHXTdN1zbV6tNlsWrt2rYYOHeqZ4gCDcQ8RAI8rLCzUqVOnNGfOHP3617+uk2HIhB6B2oyXzAB43FtvvaW2bdsqLy9PCxcu9HQ515SVleX2Nv7Lt0tfHrtUbeoRMBEvmQFAOVy8ePGaX5URFhamevW4+A7UNgQiAABgPF4yAwAAxiMQAQAA4xGIAACA8QhEAADAeAQiAABgPAIRAAAwHoEIAAAYj0AEAACM939faPJBMq+8vAAAAABJRU5ErkJggg==",
+      "text/plain": [
+       "<Figure size 640x480 with 1 Axes>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%sqlplot bar --table taxi --column payment_type"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 38,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<span style=\"None\">Removing NULLs, if there exists any from payment_type</span>"
+      ],
+      "text/plain": [
+       "Removing NULLs, if there exists any from payment_type"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/plain": [
+       "<Axes: title={'center': 'taxi'}>"
+      ]
+     },
+     "execution_count": 38,
+     "metadata": {},
+     "output_type": "execute_result"
+    },
+    {
+     "data": {
+      "image/png": "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",
+      "text/plain": [
+       "<Figure size 640x480 with 1 Axes>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%sqlplot pie --table taxi --column payment_type"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 39,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from sql.ggplot import ggplot, aes, geom_histogram"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 40,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "<sql.ggplot.ggplot.ggplot at 0x14efcf7f0>"
+      ]
+     },
+     "execution_count": 40,
+     "metadata": {},
+     "output_type": "execute_result"
+    },
+    {
+     "data": {
+      "image/png": "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VtOmTTVkyBBt27ZNISEheuedd5Sdna2FCxeWehtt27ZVv3799PrrrysvL0+33367kpOTdfDgwSu+d9GiRXr99dfVu3dvNW7cWCdPntRbb70lu92ue+65R9Lvl4wiIyP1/vvvq2nTpqpdu7Zatmypli1bqkuXLpo5c6bOnTunG264QevWrVNGRsZVzYX0+z1VL7zwgl588UV17txZDz74oHx8fLRt2zaFhYVp+vTpstvtmj9/vgYMGKB27dqpb9++CgoKUmZmplatWqU77rhDr7766lX3UBoTJkzQe++9p549e2rMmDGqXbu2Fi1apIyMDH3wwQclbgivaOXxGb300ktKT09XcnKyatasqdatW2vy5MmaNGmSHnroIfPnAagy3PeAGwDD+P3x7tjYWKNmzZqGJPMR/OJH2i/2CPulHruPjY011q5da7Ru3drw8fExmjdvbixbtqzMPZ05c8YYM2aMUadOHaNGjRrGfffdZxw+fPiKj93v2LHD6Nevn9GwYUPDx8fHCA4ONu69915j+/btLtvfvHmzERUVZXh7e7ts86effjJ69+5tBAYGGgEBAcbDDz9sHDlypMR+L/VY+8XmxTAM45133jFuueUWw8fHx6hVq5bRtWtXIykpyaVmw4YNRkxMjBEQEGD4+voajRs3NgYNGlSi99K43GP3sbGxF33P999/bzz00ENGYGCg4evra9x2223GypUrS/QoqcRneqmflUv1URp/5jNKS0szPD09jdGjR7ts8/z588att95qhIWFGSdOnHDpEXA3m2GU4912ANwmPDxcLVu21MqVK93dCgBcc7iHCAAAWB73EAEWcqUvZ/Tz8+MJIACWRCACLKRevXqXHR84cKASExMrpxkAqEIIRMB1ojTfRJ2UlHTZ8bCwsHLqBgCuLdxUDQAALI+bqgEAgOVxyawUioqKdOTIEdWsWZM/TAgAwDXCMAydPHlSYWFhV/yCUwJRKRw5cqTEX5EGAADXhsOHD6t+/fqXrSEQlULNmjUl/T6hdrvdzd0AAIDScDqdatCggfl7/HIIRKVQfJnMbrcTiAAAuMaU5nYXbqoGAACWRyACAACWRyACAACWRyACAACWRyACAACWRyACAACWRyACAACWRyACAACWRyACAACWRyACAACWRyACAACWRyACAACWRyACAACWRyACAACWRyACAACW5+nu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FAzD0KhRo7R8+XKtX79eERERLuNRUVHy8vJymd/9+/crMzOT+f0TioqKlJ+fz/yWg+7du2vXrl1KT083l/bt26t///7mv5nj8nXq1Cl9//33qlevXvn+DP+JG79RRS1ZssTw8fExEhMTjb179xrDhw83AgMDjaysLHe3dk06efKk8fXXXxtff/21Icl45ZVXjK+//tr48ccfDcMwjBkzZhiBgYHGRx99ZOzcudN44IEHjIiICOPMmTNu7rzqGzlypBEQEGBs3LjROHr0qLn89ttvZs2IESOMhg0bGuvXrze2b99uOBwOw+FwuLHra8uECROMlJQUIyMjw9i5c6cxYcIEw2azGevWrTMMg/mtCBc+ZWYYzPGf9cwzzxgbN240MjIyjC+//NKIjo426tata+Tk5BiGUX7zSyC6Tv3zn/80GjZsaHh7exu33XabsWXLFne3dM3asGGDIanEMnDgQMMwfn/0/m9/+5sREhJi+Pj4GN27dzf279/v3qavERebV0nGwoULzZozZ84YTz31lFGrVi2jevXqRu/evY2jR4+6r+lrzODBg41GjRoZ3t7eRlBQkNG9e3czDBkG81sR/hiImOM/55FHHjHq1atneHt7GzfccIPxyCOPGAcPHjTHy2t+bYZhGOVwBgsAAOCaxT1EAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEAADA8ghEANwqISFBbdu2rdB93HnnnYqPjzdfh4eHa86cORW6TwDXFgIRgArxxxByKc8++6zL3yGqDNu2bdPw4cNLVUt4AqzB090NALAmwzBUWFgof39/+fv7V+q+g4KCKnV/AKo+zhABKHeDBg1SSkqK5s6dK5vNJpvNpsTERNlsNq1evVpRUVHy8fHRF198UeKS2aBBg9SrVy9NnTpVQUFBstvtGjFihAoKCkq179OnT+vxxx+Xv7+/6tWrp1mzZpWoufCsj2EYSkhIUMOGDeXj46OwsDCNGTNG0u9nuX788UeNHTvWPA5J+vXXX9WvXz/dcMMNql69ulq1aqX33nvPZR933nmnxowZo/Hjx6t27doKDQ1VQkKCS01ubq6efPJJhYSEyNfXVy1bttTKlSvN8S+++EKdO3eWn5+fGjRooDFjxuj06dOlmgcAZUMgAlDu5s6dK4fDoWHDhuno0aM6evSoGjRoIEmaMGGCZsyYoW+//VatW7e+6PuTk5P17bffauPGjXrvvff04YcfaurUqaXa93PPPaeUlBR99NFHWrdunTZu3KgdO3Zcsv6DDz7Q7Nmz9cYbb+jAgQNasWKFWrVqJUn68MMPVb9+fU2bNs08Dkk6e/asoqKitGrVKu3evVvDhw/XgAED9NVXX7lse9GiRapRo4a2bt2qmTNnatq0aUpKSpIkFRUVqWfPnvryyy/17rvvau/evZoxY4aqVasmSfr+++919913q0+fPtq5c6fef/99ffHFFxo1alSp5gFAGZXXX6MFgAv98S9+b9iwwZBkrFixwqVuypQpRps2bczXAwcONGrXrm2cPn3aXDd//nzD39/fKCwsvOw+T548aXh7extLly411/3666+Gn5+fSy+NGjUyZs+ebRiGYcyaNcto2rSpUVBQcNFtXlh7ObGxscYzzzxjvu7atavRqVMnl5pbb73VeP755w3DMIy1a9caHh4exv79+y+6vSFDhhjDhw93Wff5558bHh4expkzZ67YD4Cy4QwRgErVvn37K9a0adNG1atXN187HA6dOnVKhw8fvuz7vv/+exUUFKhDhw7mutq1a6tZs2aXfM/DDz+sM2fO6MYbb9SwYcO0fPlynT9//rL7KSws1IsvvqhWrVqpdu3a8vf319q1a5WZmelS98czYPXq1VNOTo4kKT09XfXr11fTpk0vuo9vvvlGiYmJ5j1W/v7+iomJUVFRkTIyMi7bH4Cy46ZqAJWqRo0a7m7BRYMGDbR//3599tlnSkpK0lNPPaWXX35ZKSkp8vLyuuh7Xn75Zc2dO1dz5sxRq1atVKNGDcXHx5e4z+mP77fZbCoqKpIk+fn5XbavU6dO6cknnzTvZ7pQw4YNy3KIAEqBQASgQnh7e6uwsPCq3vvNN9/ozJkzZmjYsmWL/P39zfuQLqVx48by8vLS1q1bzdBw4sQJfffdd+ratesl3+fn56f77rtP9913n+Li4tS8eXPt2rVL7dq1u+hxfPnll3rggQf02GOPSfr9fqDvvvtOkZGRpT7G1q1b66efftJ333130bNE7dq10969e9WkSZNSbxPA1eOSGYAKER4erq1bt+rQoUP65ZdfzDMjpVFQUKAhQ4Zo7969+vTTTzVlyhSNGjVKHh6X/0+Wv7+/hgwZoueee07r16/X7t27NWjQoMu+LzExUf/617+0e/du/fDDD3r33Xfl5+enRo0amcexadMm/fzzz/rll18kSTfddJOSkpK0efNmffvtt3ryySeVnZ1d6uOTpK5du6pLly7q06ePkpKSlJGRodWrV2vNmjWSpOeff16bN2/WqFGjlJ6ergMHDuijjz7ipmqgghCIAFSIZ599VtWqVVNkZKSCgoJK3F9zOd27d9dNN92kLl266JFHHtH9999f4pH1S3n55ZfVuXNn3XfffYqOjlanTp0UFRV1yfrAwEC99dZbuuOOO9S6dWt99tln+uSTT1SnTh1J0rRp03To0CE1btzY/P6iSZMmqV27doqJidGdd96p0NBQ9erVq9THV+yDDz7Qrbfeqn79+ikyMlLjx483z0a1bt1aKSkp+u6779S5c2fdcsstmjx5ssLCwsq8HwBXZjMMw3B3EwBQbNCgQcrNzdWKFSvc3QoAC+EMEQAAsDwCEYBrRmZmpstj6H9cynJZDgAuxCUzANeM8+fP69ChQ5ccDw8Pl6cnD88CKDsCEQAAsDwumQEAAMsjEAEAAMsjEAEAAMsjEAEAAMsjEAEAAMsjEAEAAMsjEAEAAMsjEAEAAMv7f+dZjQYV06HwAAAAAElFTkSuQmCC",
+      "text/plain": [
+       "<Figure size 640x480 with 1 Axes>"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "(ggplot(table=\"taxi\", mapping=aes(x=\"trip_distance\")) + geom_histogram(bins=10))"
+   ]
+  },
+  {
+   "attachments": {},
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "## Clean up\n",
+    "\n",
+    "To stop and remove the container:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 41,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "CONTAINER ID   IMAGE                                                      COMMAND                  CREATED              STATUS              PORTS                                              NAMES\n",
+      "12f699ee8e8e   wh1isper/sparglim-server                                   \"tini -- sparglim-se…\"   About a minute ago   Up About a minute   0.0.0.0:4040->4040/tcp, 0.0.0.0:15002->15002/tcp   spark\n",
+      "f019407c6426   docker.dev.slicelife.com/onelogin-aws-assume-role:stable   \"onelogin-aws-assume…\"   2 weeks ago          Up 2 weeks                                                             heuristic_tu\n"
+     ]
+    }
+   ],
+   "source": [
+    "! docker container ls"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 42,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "%%capture out\n",
+    "! docker container ls --filter ancestor=wh1isper/sparglim-server --quiet"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 43,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Container id: 12f699ee8e8e\n"
+     ]
+    }
+   ],
+   "source": [
+    "container_id = out.stdout.strip()\n",
+    "print(f\"Container id: {container_id}\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 44,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "12f699ee8e8e\n"
+     ]
+    }
+   ],
+   "source": [
+    "! docker container stop {container_id}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 45,
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "12f699ee8e8e\n"
+     ]
+    }
+   ],
+   "source": [
+    "! docker container rm {container_id}"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3 (ipykernel)",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.10.13"
+  },
+  "myst": {
+   "html_meta": {
+    "description lang=en": "Query using Spark SQL from Jupyter via JupySQL",
+    "keywords": "jupyter, sql, jupysql, spark",
+    "property=og:locale": "en_US"
+   }
+  },
+  "vscode": {
+   "interpreter": {
+    "hash": "8de7291ac4f217ed756f77e1d71d41823fff9c4ffb13df0a183e9309929ad9aa"
+   }
+  },
+  "widgets": {
+   "application/vnd.jupyter.widget-state+json": {
+    "state": {},
+    "version_major": 2,
+    "version_minor": 0
+   }
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/noxfile.py b/noxfile.py
index 92c2b8fb6..5a62c0f26 100644
--- a/noxfile.py
+++ b/noxfile.py
@@ -35,6 +35,8 @@
     "pyodbc==4.0.34",
     "sqlalchemy-pytds",
     "python-tds",
+    "pyspark>=3.4.1",
+    "grpcio-status",
 ]
 
 
diff --git a/setup.py b/setup.py
index e1ba5911a..1c03419f8 100644
--- a/setup.py
+++ b/setup.py
@@ -71,6 +71,9 @@
     "redshift-connector",
     "sqlalchemy-redshift",
     "clickhouse-sqlalchemy",
+    # following two dependencies required for spark
+    "pyspark",
+    "grpcio-status",
 ]
 
 setup(
diff --git a/src/sql/command.py b/src/sql/command.py
index 7b7bd168b..675420d74 100644
--- a/src/sql/command.py
+++ b/src/sql/command.py
@@ -5,7 +5,7 @@
 
 from sql import parse, exceptions
 from sql.store import store
-from sql.connection import ConnectionManager, is_pep249_compliant
+from sql.connection import ConnectionManager, is_pep249_compliant, is_spark
 from sql.util import validate_nonidentifier_connection
 
 
@@ -49,7 +49,11 @@ def __init__(self, magic, user_ns, line, cell) -> None:
         if (
             one_arg
             and self.args.line[0] in user_ns
-            and (isinstance(user_ns[self.args.line[0]], Engine) or is_dbapi_connection_)
+            and (
+                isinstance(user_ns[self.args.line[0]], Engine)
+                or is_dbapi_connection_
+                or is_spark(user_ns[self.args.line[0]])
+            )
         ):
             line_for_command = []
             add_conn = True
diff --git a/src/sql/connection/__init__.py b/src/sql/connection/__init__.py
index 7c48e624b..4d9dfb10a 100644
--- a/src/sql/connection/__init__.py
+++ b/src/sql/connection/__init__.py
@@ -2,7 +2,9 @@
     ConnectionManager,
     SQLAlchemyConnection,
     DBAPIConnection,
+    SparkConnectConnection,
     is_pep249_compliant,
+    is_spark,
     PLOOMBER_DOCS_LINK_STR,
     default_alias_for_engine,
     ResultSetCollection,
@@ -14,7 +16,9 @@
     "ConnectionManager",
     "SQLAlchemyConnection",
     "DBAPIConnection",
+    "SparkConnectConnection",
     "is_pep249_compliant",
+    "is_spark",
     "PLOOMBER_DOCS_LINK_STR",
     "default_alias_for_engine",
     "ResultSetCollection",
diff --git a/src/sql/connection/connection.py b/src/sql/connection/connection.py
index 678ca30de..fc4552aaa 100644
--- a/src/sql/connection/connection.py
+++ b/src/sql/connection/connection.py
@@ -16,6 +16,9 @@
     InternalError,
     ProgrammingError,
 )
+
+from sql.run.sparkdataframe import handle_spark_dataframe
+
 from IPython.core.error import UsageError
 import sqlglot
 import sqlparse
@@ -257,6 +260,10 @@ def set(
                 )
             elif is_pep249_compliant(descriptor):
                 cls.current = DBAPIConnection(descriptor, config=config, alias=alias)
+            elif is_spark(descriptor):
+                cls.current = SparkConnectConnection(
+                    descriptor, config=config, alias=alias
+                )
             else:
                 existing = rough_dict_get(cls.connections, descriptor)
                 if existing and existing.alias == alias:
@@ -1060,6 +1067,82 @@ def to_table(self, table_name, data_frame, if_exists, index, schema=None):
         )
 
 
+class SparkConnectConnection(AbstractConnection):
+    is_dbapi_connection = False
+
+    @telemetry.log_call("SparkConnectConnection", payload=True)
+    def __init__(self, payload, connection, alias=None, config=None):
+        try:
+            payload["engine"] = type(connection)
+        except Exception as e:
+            payload["engine_parsing_error"] = str(e)
+        self._driver = None
+
+        # TODO: implement the dialect blacklist and add unit tests
+        self._requires_manual_commit = True if config is None else config.autocommit
+
+        self._connection = connection
+        self._connection_class_name = type(connection).__name__
+
+        # calling init from AbstractConnection must be the last thing we do as it
+        # register the connection
+        super().__init__(alias=alias or self._connection_class_name)
+
+        self.name = self._connection_class_name
+
+    @property
+    def dialect(self):
+        """Returns a string with the SQL dialect name"""
+        return "spark2"
+
+    def raw_execute(self, query, parameters=None):
+        """Run the query without any pre-processing"""
+        return handle_spark_dataframe(self._connection.sql(query))
+
+    def _get_database_information(self):
+        """
+        Get the dialect, driver, and database server version info of current
+        connection
+        """
+        return {
+            "dialect": self.dialect,
+            "driver": self._connection_class_name,
+            "server_version_info": self._connection.version,
+        }
+
+    @property
+    def url(self):
+        """Returns None since Spark connections don't have a url"""
+        return None
+
+    @property
+    def connection_sqlalchemy(self):
+        """
+        Raises NotImplementedError since Spark connections don't have a SQLAlchemy
+        connection object
+        """
+        raise NotImplementedError(
+            "This feature is only available for SQLAlchemy connections"
+        )
+
+    def to_table(self, table_name, data_frame, if_exists, index, schema=None):
+        mode = (
+            "overwrite"
+            if if_exists == "replace"
+            else "append"
+            if if_exists == "append"
+            else "error"
+        )
+        self._connection.createDataFrame(data_frame).write.mode(mode).saveAsTable(
+            f"{schema}.{table_name}" if schema else table_name
+        )
+
+    def close(self):
+        """Override of the abstract close as SparkSession is usually
+        shared with pyspark"""
+        pass
+
+
 def _check_if_duckdb_dbapi_connection(conn):
     """Check if the connection is a native duckdb connection"""
     # NOTE: duckdb defines df and pl to efficiently convert results to
@@ -1154,6 +1237,26 @@ def is_pep249_compliant(conn):
     return True
 
 
+def is_spark(conn):
+    """Check if it is a SparkSession by checking for available methods"""
+
+    sparksession_methods = [
+        "table",
+        "read",
+        "createDataFrame",
+        "sql",
+        "stop",
+        "catalog",
+        "version",
+    ]
+    for method_name in sparksession_methods:
+        # Checking whether the connection object has the method
+        if not hasattr(conn, method_name):
+            return False
+
+    return True
+
+
 def default_alias_for_engine(engine):
     if not engine.url.username:
         # keeping this for compatibility
diff --git a/src/sql/error_handler.py b/src/sql/error_handler.py
index 0eac9292a..cd1dfb3cd 100644
--- a/src/sql/error_handler.py
+++ b/src/sql/error_handler.py
@@ -50,6 +50,7 @@ def _detailed_message_with_error_type(error, query):
         "error in your sql syntax",
         "incorrect syntax",
         "invalid sql",
+        "syntax_error",
     ]
     not_found_substrings = [
         r"(\btable with name\b).+(\bdoes not exist\b)",
diff --git a/src/sql/magic.py b/src/sql/magic.py
index d34d32e2c..17a2a2a49 100644
--- a/src/sql/magic.py
+++ b/src/sql/magic.py
@@ -147,6 +147,15 @@ class SqlMagic(Magics, Configurable):
         config=True,
         help="Verbosity level. 0=minimal, 1=normal, 2=all",
     )
+    lazy_execution = Bool(
+        default_value=False,
+        config=True,
+        help="Whether to evaluate using ResultSet which will "
+        "cause the plan to execute or just return a lazily "
+        "executed plan allowing validating schemas, "
+        "without expensive compute."
+        "Currently only supported for Spark Connection.",
+    )
     named_parameters = Bool(
         default_value=False,
         config=True,
diff --git a/src/sql/plot.py b/src/sql/plot.py
index 10e7e7895..d3cecb759 100644
--- a/src/sql/plot.py
+++ b/src/sql/plot.py
@@ -268,10 +268,9 @@ def _min_max(conn, table, column, with_=None, use_backticks=False):
 """
     if use_backticks:
         template_ = template_.replace('"', "`")
-
+        table = table.replace('"', "`")
     template = Template(template_)
     query = template.render(table=table, column=column)
-
     min_, max_ = conn.execute(query, with_).fetchone()
     return min_, max_
 
@@ -628,6 +627,7 @@ def _histogram(
 
             if use_backticks:
                 template_ = template_.replace('"', "`")
+                table = table.replace('"', "`")
 
             template = Template(template_)
 
@@ -663,6 +663,7 @@ def _histogram(
 
             if use_backticks:
                 template_ = template_.replace('"', "`")
+                table = table.replace('"', "`")
 
             template = Template(template_)
 
@@ -681,6 +682,7 @@ def _histogram(
 
         if use_backticks:
             template_ = template_.replace('"', "`")
+            table = table.replace('"', "`")
 
         template = Template(template_)
 
@@ -835,6 +837,7 @@ def _bar(table, column, with_=None, conn=None):
 
         if use_backticks:
             template_ = template_.replace('"', "`")
+            table = table.replace('"', "`")
 
         template = Template(template_)
         query = template.render(table=table, x_=x_, height_=height_)
@@ -854,6 +857,7 @@ def _bar(table, column, with_=None, conn=None):
 
         if use_backticks:
             template_ = template_.replace('"', "`")
+            table = table.replace('"', "`")
 
         template = Template(template_)
         query = template.render(table=table, column=column)
@@ -1022,6 +1026,7 @@ def _pie(table, column, with_=None, conn=None):
                 """
         if use_backticks:
             template_ = template_.replace('"', "`")
+            table = table.replace('"', "`")
 
         template = Template(template_)
         query = template.render(table=table, labels_=labels_, size_=size_)
@@ -1037,6 +1042,7 @@ def _pie(table, column, with_=None, conn=None):
                 """
         if use_backticks:
             template_ = template_.replace('"', "`")
+            table = table.replace('"', "`")
 
         template = Template(template_)
         query = template.render(table=table, column=column)
diff --git a/src/sql/run/resultset.py b/src/sql/run/resultset.py
index 8451150aa..4b977a8e2 100644
--- a/src/sql/run/resultset.py
+++ b/src/sql/run/resultset.py
@@ -434,7 +434,10 @@ def fetchmany(self, size):
                     raise RuntimeError(f"Error running the query: {str(e)}") from e
                 self.mark_fetching_as_done()
                 return
-
+            # spark doesn't support cursor
+            if hasattr(self._sqlaproxy, "dataframe"):
+                self._results = []
+                self._pretty_table.clear()
             self._extend_results(returned)
 
             if len(returned) < size:
@@ -458,6 +461,9 @@ def fetch_for_repr_if_needed(self):
 
     def fetchall(self):
         if not self._done_fetching():
+            if hasattr(self._sqlaproxy, "dataframe"):
+                self._results = []
+                self._pretty_table.clear()
             self._extend_results(self.sqlaproxy.fetchall())
             self.mark_fetching_as_done()
 
@@ -500,6 +506,8 @@ def _convert_to_data_frame(
     # maybe create accessors in the connection objects?
     if result_set._conn.is_dbapi_connection:
         native_connection = result_set.sqlaproxy
+    elif hasattr(result_set.sqlaproxy, "dataframe"):
+        return result_set.sqlaproxy.dataframe.toPandas()
     else:
         native_connection = result_set._conn._connection.connection
 
diff --git a/src/sql/run/run.py b/src/sql/run/run.py
index 11312c450..a1e34aa7d 100644
--- a/src/sql/run/run.py
+++ b/src/sql/run/run.py
@@ -52,6 +52,8 @@ def run_statements(conn, sql, config, parameters=None):
         # regular query
         else:
             result = conn.raw_execute(statement, parameters=parameters)
+            if is_spark(conn.dialect) and config.lazy_execution:
+                return result.dataframe
 
             if (
                 config.feedback >= 1
@@ -69,6 +71,10 @@ def is_postgres_or_redshift(dialect):
     return "postgres" in str(dialect) or "redshift" in str(dialect)
 
 
+def is_spark(dialect):
+    return "spark" in str(dialect)
+
+
 def select_df_type(resultset, config):
     """
     Converts the input resultset to either a Pandas DataFrame
diff --git a/src/sql/run/sparkdataframe.py b/src/sql/run/sparkdataframe.py
new file mode 100644
index 000000000..81644b1e2
--- /dev/null
+++ b/src/sql/run/sparkdataframe.py
@@ -0,0 +1,52 @@
+try:
+    from pyspark.sql import DataFrame
+    from pyspark.sql.connect.dataframe import DataFrame as CDataFrame
+except ModuleNotFoundError:
+    DataFrame = None
+    CDataFrame = None
+
+from sql import exceptions
+
+
+def handle_spark_dataframe(dataframe, should_cache=False):
+    """Execute a ResultSet sqlaproxy using pysark module."""
+    if not DataFrame and not CDataFrame:
+        raise exceptions.MissingPackageError("pysark not installed")
+
+    return SparkResultProxy(dataframe, dataframe.columns, should_cache)
+
+
+class SparkResultProxy(object):
+    """A fake class that pretends to behave like the ResultProxy from
+    SqlAlchemy.
+    """
+
+    dataframe = None
+
+    def __init__(self, dataframe, headers, should_cache):
+        self.dataframe = dataframe
+        self.fetchall = dataframe.collect
+        self.rowcount = dataframe.count()
+        self.keys = lambda: headers
+        self.cursor = SparkCursor(headers)
+        self.returns_rows = True
+        if should_cache:
+            self.dataframe.cache()
+
+    def fetchmany(self, size):
+        return self.dataframe.take(size)
+
+    def fetchone(self):
+        return self.dataframe.head()
+
+    def close(self):
+        self.dataframe.unpersist()
+
+
+class SparkCursor(object):
+    """Class to extend to give SqlAlchemy Cursor like behaviour"""
+
+    description = None
+
+    def __init__(self, headers) -> None:
+        self.description = headers
diff --git a/src/sql/stats.py b/src/sql/stats.py
index 0fc12e87f..b03252154 100644
--- a/src/sql/stats.py
+++ b/src/sql/stats.py
@@ -45,7 +45,6 @@ def _summary_stats_one_by_one(conn, table, column, with_=None):
     other = list(conn.execute(query, with_).fetchone())
 
     keys = ["q1", "med", "q3", "mean", "N"]
-
     return {k: float(v) for k, v in zip(keys, percentiles + other)}
 
 
diff --git a/src/sql/util.py b/src/sql/util.py
index b0d9c0c3b..4f7fd6d4f 100644
--- a/src/sql/util.py
+++ b/src/sql/util.py
@@ -543,6 +543,9 @@ def is_non_sqlalchemy_error(error):
         "pyodbc.ProgrammingError",
         # Clickhouse errors
         "DB::Exception:",
+        # Pyspark
+        "UNRESOLVED_ROUTINE",
+        "PARSE_SYNTAX_ERROR",
     ]
     return any(msg in str(error) for msg in specific_db_errors)
 


Test patch:
diff --git a/src/sql/_testing.py b/src/sql/_testing.py
index 14a5e9675..041994e28 100644
--- a/src/sql/_testing.py
+++ b/src/sql/_testing.py
@@ -210,6 +210,10 @@ def get_tmp_dir():
         "docker_ct": None,
         "query": {},
     },
+    "spark": {
+        "alias": "SparkSession",
+        "drivername": "SparkSession",
+    },
     "clickhouse": {
         "drivername": "clickhouse+native",
         "username": "username",
diff --git a/src/tests/integration/conftest.py b/src/tests/integration/conftest.py
index e0a0b5e7f..cad899583 100644
--- a/src/tests/integration/conftest.py
+++ b/src/tests/integration/conftest.py
@@ -2,6 +2,7 @@
 from pathlib import Path
 import shutil
 import pandas as pd
+from pyspark.sql import SparkSession
 import pytest
 from sqlalchemy import MetaData, Table, create_engine, text
 import uuid
@@ -288,6 +289,49 @@ def setup_duckDB_native(test_table_name_dict):
     conn.close()
 
 
+@pytest.fixture(scope="session")
+def setup_spark(test_table_name_dict):
+    import os
+    import shutil
+    import sys
+
+    os.environ["PYSPARK_PYTHON"] = sys.executable
+    os.environ["PYSPARK_DRIVER_PYTHON"] = sys.executable
+    spark = SparkSession.builder.master("local[1]").enableHiveSupport().getOrCreate()
+    load_generic_testing_data_spark(spark, test_table_name_dict)
+    yield spark
+    spark.stop()
+    shutil.rmtree("metastore_db", ignore_errors=True)
+    shutil.rmtree("spark-warehouse", ignore_errors=True)
+    os.remove("derby.log")
+
+
+def load_generic_testing_data_spark(spark: SparkSession, test_table_name_dict):
+    spark.createDataFrame(
+        pd.DataFrame(
+            {"taxi_driver_name": ["Eric Ken", "John Smith", "Kevin Kelly"] * 15}
+        )
+    ).createOrReplaceTempView(test_table_name_dict["taxi"])
+    spark.createDataFrame(
+        pd.DataFrame({"x": range(0, 5), "y": range(5, 10)})
+    ).createOrReplaceTempView(test_table_name_dict["plot_something"])
+    spark.createDataFrame(
+        pd.DataFrame({"numbers_elements": [1, 2, 3] * 20})
+    ).createOrReplaceTempView(test_table_name_dict["numbers"])
+
+
+@pytest.fixture
+def ip_with_spark(ip_empty, setup_spark):
+    alias = "SparkSession"
+
+    ip_empty.push({"conn": setup_spark})
+    # Select database engine, use different sqlite database endpoint
+    ip_empty.run_cell("%sql " + "conn" + " --alias " + alias)
+    yield ip_empty
+    # Disconnect database
+    ip_empty.run_cell("%sql -x " + alias)
+
+
 def load_generic_testing_data_duckdb_native(ip, test_table_name_dict):
     ip.run_cell("import pandas as pd")
     ip.run_cell(
diff --git a/src/tests/integration/test_connection.py b/src/tests/integration/test_connection.py
index 5d867b6e6..63dc71ac9 100644
--- a/src/tests/integration/test_connection.py
+++ b/src/tests/integration/test_connection.py
@@ -8,7 +8,12 @@
 import pytest
 
 
-from sql.connection import SQLAlchemyConnection, DBAPIConnection, ConnectionManager
+from sql.connection import (
+    SQLAlchemyConnection,
+    DBAPIConnection,
+    ConnectionManager,
+    SparkConnectConnection,
+)
 from sql import _testing
 from sql.connection import connection
 
@@ -92,6 +97,7 @@ def test_connection_properties(dynamic_db, request, Constructor, alias, dialect)
             partial(DBAPIConnection, alias="another-alias"),
             "another-alias",
         ],
+        ["setup_spark", SparkConnectConnection, "SparkSession"],
     ],
 )
 def test_connection_identifiers(
diff --git a/src/tests/integration/test_generic_db_operations.py b/src/tests/integration/test_generic_db_operations.py
index 47325ed16..95722758a 100644
--- a/src/tests/integration/test_generic_db_operations.py
+++ b/src/tests/integration/test_generic_db_operations.py
@@ -21,6 +21,7 @@
     "ip_with_Snowflake",
     "ip_with_oracle",
     "ip_with_clickhouse",
+    "ip_with_spark",
 ]
 
 
@@ -54,6 +55,7 @@ def mock_log_api(monkeypatch):
         ("ip_with_clickhouse", "", "LIMIT 3"),
         ("ip_with_oracle", "", "FETCH FIRST 3 ROWS ONLY"),
         ("ip_with_MSSQL", "TOP 3", ""),
+        ("ip_with_spark", "", "LIMIT 3"),
     ],
 )
 def test_run_query(
@@ -93,6 +95,7 @@ def test_run_query(
         "ip_with_Snowflake",
         "ip_with_redshift",
         "ip_with_clickhouse",
+        "ip_with_spark",
     ],
 )
 def test_handle_multiple_open_result_sets(
@@ -151,6 +154,7 @@ def test_handle_multiple_open_result_sets(
                 "No engine for table <table_name>"
             ),
         ),
+        ("ip_with_spark", "--no-index"),
     ],
 )
 def test_create_table_with_indexed_df(
@@ -218,6 +222,7 @@ def get_connection_count(ip_with_dynamic_db):
         ("ip_with_MSSQL", 1),
         ("ip_with_Snowflake", 1),
         ("ip_with_clickhouse", 1),
+        ("ip_with_spark", 1),
     ],
 )
 def test_active_connection_number(ip_with_dynamic_db, expected, request):
@@ -273,6 +278,7 @@ def test_close_and_connect(
         ("ip_with_Snowflake", "snowflake", "snowflake"),
         ("ip_with_oracle", "oracle", "oracledb"),
         ("ip_with_clickhouse", "clickhouse", "native"),
+        ("ip_with_spark", "spark2", "SparkSession"),
     ],
 )
 def test_telemetry_execute_command_has_connection_info(
@@ -337,6 +343,7 @@ def test_telemetry_execute_command_has_connection_info(
         ("ip_with_Snowflake"),
         ("ip_with_duckDB_native"),
         ("ip_with_redshift"),
+        ("ip_with_spark"),
         pytest.param(
             "ip_with_MSSQL",
             marks=pytest.mark.xfail(reason="sqlglot does not support SQL server"),
@@ -419,6 +426,9 @@ def test_sqlplot_histogram(ip_with_dynamic_db, cell, request, test_table_name_di
                 reason="Plotting from snippet not working in clickhouse"
             ),
         ),
+        pytest.param(
+            "ip_with_spark", marks=pytest.mark.xfail(reason=BOX_PLOT_FAIL_REASON)
+        ),
     ],
 )
 def test_sqlplot_boxplot(ip_with_dynamic_db, cell, request, test_table_name_dict):
@@ -442,6 +452,7 @@ def test_sqlplot_boxplot(ip_with_dynamic_db, cell, request, test_table_name_dict
         "ip_with_duckDB",
         "ip_with_redshift",
         "ip_with_MSSQL",
+        "ip_with_spark",
     ],
 )
 def test_sqlplot_bar(ip_with_dynamic_db, request, test_table_name_dict):
@@ -464,7 +475,13 @@ def test_sqlplot_bar(ip_with_dynamic_db, request, test_table_name_dict):
 
 @pytest.mark.parametrize(
     "ip_with_dynamic_db",
-    ["ip_with_postgreSQL", "ip_with_duckDB", "ip_with_redshift", "ip_with_MSSQL"],
+    [
+        "ip_with_postgreSQL",
+        "ip_with_duckDB",
+        "ip_with_redshift",
+        "ip_with_MSSQL",
+        "ip_with_spark",
+    ],
 )
 def test_sqlplot_pie(ip_with_dynamic_db, request, test_table_name_dict):
     plt.cla()
@@ -517,6 +534,7 @@ def test_sqlplot_pie(ip_with_dynamic_db, request, test_table_name_dict):
                 reason="Plotting from snippet not working in clickhouse"
             ),
         ),
+        "ip_with_spark",
     ],
 )
 def test_sqlplot_using_schema(ip_with_dynamic_db, request):
@@ -569,6 +587,7 @@ def test_sqlplot_using_schema(ip_with_dynamic_db, request):
         ("ip_with_Snowflake"),
         ("ip_with_oracle"),
         ("ip_with_clickhouse"),
+        ("ip_with_spark"),
     ],
 )
 def test_sqlcmd_test(ip_with_dynamic_db, request, test_table_name_dict):
@@ -604,6 +623,7 @@ def test_sqlcmd_test(ip_with_dynamic_db, request, test_table_name_dict):
         ),
         ("ip_with_oracle"),
         ("ip_with_clickhouse"),
+        ("ip_with_spark"),
     ],
 )
 def test_profile_data_mismatch(ip_with_dynamic_db, request, capsys):
@@ -786,6 +806,25 @@ def test_profile_data_mismatch(ip_with_dynamic_db, request, capsys):
             },
             "Following statistics are not available in",
         ),
+        (
+            "ip_with_spark",
+            "taxi",
+            ["taxi_driver_name"],
+            {
+                "count": [45],
+                "mean": [math.nan],
+                "min": ["Eric Ken"],
+                "max": ["Kevin Kelly"],
+                "unique": [3],
+                "freq": [15],
+                "top": ["Eric Ken"],
+                "std": [math.nan],
+                "25%": [math.nan],
+                "50%": [math.nan],
+                "75%": [math.nan],
+            },
+            None,
+        ),
     ],
 )
 def test_sqlcmd_profile(
@@ -847,6 +886,10 @@ def test_sqlcmd_profile(
         ("ip_with_MSSQL"),
         ("ip_with_Snowflake"),
         ("ip_with_clickhouse"),
+        pytest.param(
+            "ip_with_spark",
+            marks=pytest.mark.xfail(reason="Not Implemented"),
+        ),
     ],
 )
 def test_sqlcmd_columns(ip_with_dynamic_db, table, request, test_table_name_dict):
@@ -873,6 +916,10 @@ def test_sqlcmd_columns(ip_with_dynamic_db, table, request, test_table_name_dict
         ("ip_with_MSSQL"),
         ("ip_with_Snowflake"),
         ("ip_with_clickhouse"),
+        pytest.param(
+            "ip_with_spark",
+            marks=pytest.mark.xfail(reason="Not Implemented"),
+        ),
     ],
 )
 def test_sqlcmd_tables(ip_with_dynamic_db, request):
@@ -927,6 +974,7 @@ def test_sql_query(ip_with_dynamic_db, cell, request, test_table_name_dict):
         "ip_with_Snowflake",
         "ip_with_oracle",
         "ip_with_clickhouse",
+        "ip_with_spark",
     ],
 )
 def test_sql_query_cte(ip_with_dynamic_db, request, test_table_name_dict, cell):
@@ -957,6 +1005,7 @@ def test_sql_query_cte(ip_with_dynamic_db, request, test_table_name_dict, cell):
             "ip_with_clickhouse",
             marks=pytest.mark.xfail(reason="Not yet implemented"),
         ),
+        "ip_with_spark",
     ],
 )
 def test_sql_error_suggests_using_cte(ip_with_dynamic_db, request):
@@ -987,6 +1036,7 @@ def test_sql_error_suggests_using_cte(ip_with_dynamic_db, request):
         "ip_with_MSSQL",
         "ip_with_oracle",
         "ip_with_clickhouse",
+        "ip_with_spark",
     ],
 )
 def test_results_sets_are_closed(ip_with_dynamic_db, request, test_table_name_dict):
@@ -1024,6 +1074,7 @@ def test_results_sets_are_closed(ip_with_dynamic_db, request, test_table_name_di
         "ip_with_MSSQL",
         "ip_with_oracle",
         "ip_with_clickhouse",
+        "ip_with_spark",
     ],
 )
 @pytest.mark.parametrize(
@@ -1150,6 +1201,7 @@ def test_autocommit_retrieve_existing_resultssets_duckdb_from(
             CREATE_TABLE,
             marks=pytest.mark.xfail(reason="Not working yet"),
         ),
+        ("ip_with_spark", CREATE_TABLE),
     ],
 )
 def test_autocommit_create_table_single_cell(
@@ -1222,6 +1274,7 @@ def test_autocommit_create_table_single_cell(
             CREATE_TABLE,
             marks=pytest.mark.xfail(reason="Not working yet"),
         ),
+        ("ip_with_spark", CREATE_TABLE),
     ],
 )
 def test_autocommit_create_table_multiple_cells(
@@ -1408,6 +1461,20 @@ def test_autocommit_create_table_multiple_cells(
             ["Table with name mysnip does not exist!"],
             "RuntimeError",
         ),
+        (
+            "ip_with_spark",
+            "mysnippet",
+            [
+                "Cannot resolve function `not_a_function` on search path",
+            ],
+            "RuntimeError",
+        ),
+        (
+            "ip_with_spark",
+            "mysnip",
+            ["Cannot resolve function `not_a_function` on search path"],
+            "RuntimeError",
+        ),
     ],
     ids=[
         "no-typo-postgreSQL",
@@ -1428,6 +1495,8 @@ def test_autocommit_create_table_multiple_cells(
         "with-typo-redshift",
         "no-typo-duckDB-native",
         "with-typo-duckDB-native",
+        "no-typo-spark",
+        "with-typo-spark",
     ],
 )
 def test_query_snippet_invalid_function_error_message(
@@ -1456,7 +1525,7 @@ def test_query_snippet_invalid_function_error_message(
     # Save result and test error message
     result_error = excinfo.value.error_type
     result_msg = str(excinfo.value)
-
+    print(result_msg)
     assert error_type == result_error
     assert all(msg in result_msg for msg in error_msgs)
 
@@ -1502,6 +1571,7 @@ def test_query_snippet_invalid_function_error_message(
                 "No engine for table <table_name>"
             ),
         ),
+        ("ip_with_spark", "--no-index"),
     ],
 )
 def test_persist_in_schema(ip_with_dynamic_db, args, request, test_table_name_dict):
diff --git a/src/tests/integration/test_stats.py b/src/tests/integration/test_stats.py
index d8f93439d..fe33b18f5 100644
--- a/src/tests/integration/test_stats.py
+++ b/src/tests/integration/test_stats.py
@@ -1,7 +1,7 @@
 import pytest
 
 from sql.stats import _summary_stats
-from sql.connection import SQLAlchemyConnection
+from sql.connection import SQLAlchemyConnection, SparkConnectConnection
 
 
 @pytest.mark.parametrize(
@@ -26,3 +26,23 @@ def test_summary_stats(fixture_name, request, test_table_name_dict):
         "mean": 2.0,
         "N": 5.0,
     }
+
+
+@pytest.mark.parametrize(
+    "fixture_name",
+    [
+        "setup_spark",
+    ],
+)
+def test_summary_stats_spark(fixture_name, request, test_table_name_dict):
+    conn = SparkConnectConnection(request.getfixturevalue(fixture_name))
+    table = test_table_name_dict["plot_something"]
+    column = "x"
+
+    assert _summary_stats(conn, table, column) == {
+        "q1": 1.0,
+        "med": 2.0,
+        "q3": 3.0,
+        "mean": 2.0,
+        "N": 5.0,
+    }
diff --git a/src/tests/test_connection.py b/src/tests/test_connection.py
index 9a9a0a399..8369ff690 100644
--- a/src/tests/test_connection.py
+++ b/src/tests/test_connection.py
@@ -13,6 +13,7 @@
 from sqlalchemy.engine import Engine
 from sqlalchemy import exc
 
+
 from sql.connection import connection as connection_module
 import sql.connection
 from sql.connection import (
@@ -21,6 +22,7 @@
     ConnectionManager,
     is_pep249_compliant,
     default_alias_for_engine,
+    is_spark,
     ResultSetCollection,
     detect_duckdb_summarize_or_select,
 )
@@ -41,6 +43,34 @@ def mock_database(monkeypatch, cleanup):
     monkeypatch.setattr(sqlalchemy, "create_engine", Mock())
 
 
+def mock_sparksession():
+    mock = Mock(
+        spec=[
+            "table",
+            "read",
+            "createDataFrame",
+            "sql",
+            "stop",
+            "catalog",
+            "version",
+        ]
+    )
+    return mock
+
+
+def mock_not_sparksession():
+    mock = Mock(
+        spec=[
+            "read",
+            "readStream",
+            "createDataFrame",
+            "sql",
+            "version",
+        ]
+    )
+    return mock
+
+
 @pytest.fixture
 def mock_postgres(monkeypatch, cleanup):
     monkeypatch.setitem(sys.modules, "psycopg2", Mock())
@@ -457,6 +487,24 @@ def test_is_pep249_compliant(conn, expected):
     assert is_pep249_compliant(conn) is expected
 
 
+@pytest.mark.parametrize(
+    "descriptor, expected",
+    [
+        [sqlite3.connect(""), False],
+        [duckdb.connect(""), False],
+        [create_engine("sqlite://"), False],
+        [mock_sparksession(), True],
+        [mock_not_sparksession(), False],
+        [None, False],
+        [object(), False],
+        ["not_a_valid_connection", False],
+        [0, False],
+    ],
+)
+def test_is_spark(descriptor, expected):
+    assert is_spark(descriptor) is expected
+
+
 def test_close_all(ip_empty, monkeypatch):
     connections = {}
     monkeypatch.setattr(ConnectionManager, "connections", connections)
@@ -590,6 +638,22 @@ def test_set_dbapi(monkeypatch, callable_, key):
     assert ConnectionManager.current == conn
 
 
+@pytest.mark.parametrize(
+    "spark, key",
+    [
+        [mock_sparksession(), "Mock"],
+    ],
+)
+def test_set_spark(monkeypatch, spark, key):
+    connections = {}
+    monkeypatch.setattr(ConnectionManager, "connections", connections)
+
+    conn = ConnectionManager.set(spark, displaycon=False)
+
+    assert connections == {key: conn}
+    assert ConnectionManager.current == conn
+
+
 def test_set_with_alias(monkeypatch):
     connections = {}
     monkeypatch.setattr(ConnectionManager, "connections", connections)