1"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2119],{1294:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>i,default:()=>p,frontMatter:()=>o,metadata:()=>s,toc:()=>c});const s=JSON.parse('{"id":"reflex/tables/tables_read","title":"Read a Delta table","description":"This recipe reads a Unity Catalog table using the Databricks SQL Connector.","source":"@site/docs/reflex/tables/tables_read.mdx","sourceDirName":"reflex/tables","slug":"/reflex/tables/tables_read","permalink":"/docs/reflex/tables/tables_read","draft":false,"unlisted":false,"editUrl":"https://github.com/databricks-solutions/databricks-apps-cookbook/edit/main/docs/docs/reflex/tables/tables_read.mdx","tags":[],"version":"current","sidebarPosition":2,"frontMatter":{"sidebar_position":2},"sidebar":"tutorialSidebar","previous":{"title":"Connect an OLTP database","permalink":"/docs/reflex/tables/oltp_database_connect"},"next":{"title":"Edit a Delta table","permalink":"/docs/reflex/tables/tables_edit"}}');var a=t(4848),r=t(8453);const o={sidebar_position:2},i="Read a Delta table",l={},c=[{value:"Code snippet",id:"code-snippet",level:2},{value:"Resources",id:"resources",level:2},{value:"Permissions",id:"permissions",level:2},{value:"Dependencies",id:"dependencies",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.header,{children:(0,a.jsx)(n.h1,{id:"read-a-delta-table",children:"Read a Delta table"})}),"\n",(0,a.jsxs)(n.p,{children:["This recipe reads a ",(0,a.jsx)(n.a,{href:"https://docs.databricks.com/aws/en/tables/",children:"Unity Catalog table"})," using the ",(0,a.jsx)(n.a,{href:"https://docs.databricks.com/en/dev-tools/python-sql-connector.html",children:"Databricks SQL Connector"}),"."]}),"\n",(0,a.jsx)(n.h2,{id:"code-snippet",children:"Code snippet"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-python",metastring:'title="app.py"',children:'import reflex as rx\nfrom databricks import sql\nfrom databricks.sdk.core import Config\nimport logging\nimport pandas as pd\nfrom typing import Any\n\n_connection = None\n\n\ndef get_connection(http_path: str):\n global _connection\n if _connection:\n return _connection\n cfg = Config()\n connection = sql.connect(\n server_hostname=cfg.host,\n http_path=http_path,\n credentials_provider=cfg.authenticate,\n )\n _connection = connection\n return connection\n\n\ndef read_table(table_name: str, conn) -> pd.DataFrame:\n with conn.cursor() as cursor:\n cursor.execute(f"SELECT * FROM {table_name}")\n return cursor.fetchall_arrow().to_pandas()\n\n\ndef pandas_to_editor_format(\n df: pd.DataFrame,\n) -> tuple[list[list[Any]], list[dict[str, str]]]:\n """Convert a pandas DataFrame to the format required by rx.data_editor."""\n if df.empty:\n return ([], [])\n data = df.values.tolist()\n columns = [{"title": col, "id": col, "type": "str"} for col in df.columns]\n return (data, columns)\n\n\nclass ReadTableState(rx.State):\n http_path_input: str = ""\n table_name: str = "samples.nyctaxi.trips"\n df_data: list[list[Any]] = []\n df_columns: list[dict] = []\n is_loading: bool = False\n error_message: str = ""\n\n @rx.var\n def columns_for_editor(self) -> list[dict]:\n return self.df_columns\n\n @rx.var\n def data_for_editor(self) -> list[list[str]]:\n """Return data directly as it is already formatted for the editor."""\n return self.df_data\n\n @rx.event(background=True)\n async def load_table(self):\n async with self:\n self.is_loading = True\n self.error_message = ""\n self.df_data = []\n self.df_columns = []\n http_path = self.http_path_input\n table_name = self.table_name\n if not http_path:\n async with self:\n self.error_message = "Please enter an HTTP Path."\n self.is_loading = False\n return\n try:\n conn = get_connection(http_path)\n df = read_table(table_name, conn)\n data, cols = pandas_to_editor_format(df)\n async with self:\n self.df_data = data\n self.df_columns = cols\n except Exception as e:\n logging.exception(f"Error loading Delta table: {e}")\n async with self:\n self.error_message = f"Error: {e}"\n finally:\n async with self:\n self.is_loading = False\n'})}),"\n",(0,a.jsx)(n.admonition,{type:"info",children:(0,a.jsxs)(n.p,{children:["This sample caches the SQL connection in a module-level ",(0,a.jsx)(n.code,{children:"_connection"})," variable so it can be reused within the same app process. For multi-worker deployments, consider a proper pooling strategy or per-request connections depending on your workload."]})}),"\n",(0,a.jsx)(n.h2,{id:"resources",children:"Resources"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"https://docs.databricks.
1com/aws/en/compute/sql-warehouse/",children:"SQL warehouse"})}),"\n",(0,a.jsx)(n.li,{children:(0,a.jsx)(n.a,{href:"https://docs.databricks.com/aws/en/tables/",children:"Unity Catalog table"})}),"\n"]}),"\n",(0,a.jsx)(n.h2,{id:"permissions",children:"Permissions"}),"\n",(0,a.jsxs)(n.p,{children:["Your ",(0,a.jsx)(n.a,{href:"https://docs.databricks.com/aws/en/dev-tools/databricks-apps/#how-does-databricks-apps-manage-authorization",children:"app service principal"})," needs the following permissions:"]}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"SELECT"})," on the Unity Catalog table"]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.code,{children:"CAN USE"})," on the SQL warehouse"]}),"\n"]}),"\n",(0,a.jsxs)(n.p,{children:["See Unity ",(0,a.jsx)(n.a,{href:"https://docs.databricks.com/aws/en/data-governance/unity-catalog/manage-privileges/privileges",children:"Catalog privileges and securable objects"})," for more information."]}),"\n",(0,a.jsx)(n.h2,{id:"dependencies",children:"Dependencies"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.a,{href:"https://pypi.org/project/databricks-sdk/",children:"Databricks SDK"})," - ",(0,a.jsx)(n.code,{children:"databricks-sdk"})]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.a,{href:"https://pypi.org/project/databricks-sql-connector/",children:"Databricks SQL Connector"})," - ",(0,a.jsx)(n.code,{children:"databricks-sql-connector"})]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.a,{href:"https://pypi.org/project/pandas/",children:"Pandas"})," - ",(0,a.jsx)(n.code,{children:"pandas"})]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.a,{href:"https://pypi.org/project/reflex/",children:"Reflex"})," - ",(0,a.jsx)(n.code,{children:"reflex"})]}),"\n"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-python",metastring:'title="requirements.txt"',children:"databricks-sdk\ndatabricks-sql-connector\npandas\nreflex\n"})})]})}function p(e={}){const{wrapper:n}={...(0,r.R)(),...e.components};return n?(0,a.jsx)(n,{...e,children:(0,a.jsx)(d,{...e})}):d(e)}},8453:(e,n,t)=>{t.d(n,{R:()=>o,x:()=>i});var s=t(6540);const a={},r=s.createContext(a);function o(e){const n=s.useContext(r);return s.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function i(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(a):e.components||a:o(e.components),s.createElement(r.Provider,{value:n},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.