{"id":1984,"date":"2026-02-18T10:00:40","date_gmt":"2026-02-18T04:30:40","guid":{"rendered":"https:\/\/sharanamshah.com\/mymusings\/?p=1984"},"modified":"2026-02-18T10:00:50","modified_gmt":"2026-02-18T04:30:50","slug":"how-to-automate-oracle-sql-query-exports-to-csv-with-python","status":"publish","type":"post","link":"https:\/\/sharanamshah.com\/mymusings\/blog\/2026\/02\/18\/how-to-automate-oracle-sql-query-exports-to-csv-with-python\/","title":{"rendered":"How to Automate Oracle SQL Query Exports to CSV with Python"},"content":{"rendered":"<h1>How to Automate Oracle SQL Query Exports to CSV with Python<\/h1>\n<h2>The real-world scenario<\/h2>\n<p>Imagine you are a Data Analyst or Database Administrator who needs to generate a massive audit report every Monday morning at 8:00 AM. Instead of logging into **SQL Developer**, manually running a query, and clicking **Export** while waiting for the UI to freeze, you can delegate this task to a script. It is like setting up a conveyor belt in a factory: once you pull the lever, the data flows from the **Oracle Database** directly into a neatly labeled **CSV file** without any human intervention.<\/p>\n<h2>The solution<\/h2>\n<p>We use the modern **python-oracledb** driver, which is the successor to **cx_Oracle**. This script connects to your **Oracle instance**, executes a provided SQL statement, and uses the **csv** module to stream the results into a file. By utilizing **pathlib**, we ensure the script works seamlessly across **Windows**, **macOS**, and **Linux** environments.<\/p>\n<h2>Prerequisites<\/h2>\n<ul>\n<li>Install the Oracle Python driver: <code>pip install oracledb<\/code><\/li>\n<li>Ensure you have the **Database Credentials** (host, port, service name, username, and password).<\/li>\n<li>The script uses **Thin Mode**, meaning you do not need the **Oracle Instant Client** installed for basic connections.<\/li>\n<\/ul>\n<h2>The code<\/h2>\n<pre><code>\n\"\"\"\n-----------------------------------------------------------------------\nAuthors: Sharanam & Vaishali Shah\nRecipe: Oracle Data Porter\nIntent: Automate the extraction of SQL query results to a CSV file.\n-----------------------------------------------------------------------\n\"\"\"\nimport oracledb\nimport csv\nfrom pathlib import Path\n\ndef export_oracle_to_csv(user, password, dsn, sql_query, output_file):\n    # Define the output path using pathlib\n    target_path = Path(output_file)\n    \n    try:\n        # Establish connection in Thin Mode\n        conn = oracledb.connect(user=user, password=password, dsn=dsn)\n        cursor = conn.cursor()\n        \n        # Execute the query\n        cursor.execute(sql_query)\n        \n        # Fetch metadata for headers\n        headers = [col[0] for col in cursor.description]\n        \n        # Open file and write data\n        with target_path.open(mode='w', newline='', encoding='utf-8') as f:\n            writer = csv.writer(f)\n            \n            # Write the header row\n            writer.writerow(headers)\n            \n            # Fetch and write data in batches to save memory\n            while True:\n                rows = cursor.fetchmany(numRows=1000)\n                if not rows:\n                    break\n                writer.writerows(rows)\n                \n        print(f\"Success: Data exported to {target_path.absolute()}\")\n\n    except oracledb.Error as e:\n        print(f\"Database error: {e}\")\n    except Exception as e:\n        print(f\"An unexpected error occurred: {e}\")\n    finally:\n        if 'conn' in locals():\n            conn.close()\n\nif __name__ == \"__main__\":\n    # Configuration - Replace with your actual credentials\n    DB_USER = **MY_DB_USER**\n    DB_PASS = **MY_DB_PASSWORD**\n    DB_DSN = **localhost:1521\/xe**\n    \n    QUERY = **SELECT * FROM HR.EMPLOYEES**\n    FILENAME = **employee_report.csv**\n    \n    export_oracle_to_csv(DB_USER, DB_PASS, DB_DSN, QUERY, FILENAME)\n<\/code><\/pre>\n<h2>Code walkthrough<\/h2>\n<p>The script begins by importing **oracledb** for database connectivity and **pathlib** for robust file path handling. The function **export_oracle_to_csv** takes your credentials and the **SQL query** as input. <\/p>\n<p>First, it creates a **Path** object for the **output_file**, which ensures the file path logic is consistent across operating systems. When **oracledb.connect** is called, it defaults to **Thin Mode**, which is lightweight and fast. Once the query is executed, we access **cursor.description** to grab the column names; these become the first row in our **CSV**.<\/p>\n<p>To handle large datasets without crashing your computer&#8217;s memory, we use **cursor.fetchmany** in a loop. This processes the data in chunks of 1,000 rows at a time. Finally, the **finally** block ensures that the database connection is closed properly, even if the script encounters an error.<\/p>\n<h2>Sample output<\/h2>\n<p>When you run the script in your **Terminal** or **PowerShell**, you will see the following confirmation:<\/p>\n<pre><code>\nSuccess: Data exported to \/Users\/sharanam\/projects\/reports\/employee_report.csv\n<\/code><\/pre>\n<h2>Conclusion<\/h2>\n<p>Automating data extraction is a foundational skill for any modern engineer. By replacing manual exports with this Python script, you reduce the risk of human error and free up your time for more complex architectural tasks. You can now wrap this script in a **Cron job** or a **Windows Task Scheduler** to fully automate your reporting pipeline.<\/p>\n<hr style=\"margin: 50px 0; border: 0; border-top: 1px solid #eaeaea;\">\n<div style=\"background-color: #fcfcfc; padding: 35px; border-left: 5px solid #d63638; border-radius: 6px; box-shadow: 0 4px 12px rgba(0,0,0,0.05);\">\n<h3 style=\"margin-top: 0; color: #23282d; font-size: 24px; font-weight: 700;\">\ud83d\ude80 Don&#8217;t Just Learn Oracle \u2014 Master It.<\/h3>\n<p style=\"font-size: 17px; line-height: 1.6; color: #444; margin-bottom: 20px;\">\n            This tutorial was just the tip of the iceberg. To truly advance your career and build <strong>professional-grade systems<\/strong>, you need the full architectural blueprint.\n        <\/p>\n<p style=\"font-size: 17px; line-height: 1.6; color: #444; margin-bottom: 25px;\">\n            My book, <strong><a href=\"https:\/\/sharanamshah.com\/mymusings\/home\/books-ive-authored\/oracle-for-beginners-2nd-edition-covers-oracle-23ai\/\" target=\"_blank\" style=\"color: #d63638; text-decoration: underline;\">Oracle for Beginners (23ai Edition)<\/a><\/strong>, takes you from &#8220;making it work&#8221; to &#8220;making it scale.&#8221; I cover advanced patterns, real-world case studies, and the industry best practices that senior engineers use daily.\n        <\/p>\n<p style=\"margin-bottom: 0;\">\n            <a href=\"https:\/\/sharanamshah.com\/mymusings\/home\/books-ive-authored\/oracle-for-beginners-2nd-edition-covers-oracle-23ai\/\" target=\"_blank\" style=\"background-color: #d63638; color: white; padding: 15px 30px; text-decoration: none; border-radius: 5px; font-weight: bold; font-size: 18px; display: inline-block; box-shadow: 0 4px 6px rgba(214, 54, 56, 0.3);\"><br \/>\n                \ud83d\udcd6 Grab Your Copy Now &rarr;<br \/>\n            <\/a>\n        <\/p>\n<\/p><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Learn how to automate Oracle database exports to CSV using Python and the oracledb library. A complete guide for DBAs and Data Analysts.<\/p>\n","protected":false},"author":1,"featured_media":1989,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_themeisle_gutenberg_block_has_review":false,"footnotes":""},"categories":[94],"tags":[],"class_list":["post-1984","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-everyday-automation-hacks"],"_links":{"self":[{"href":"https:\/\/sharanamshah.com\/mymusings\/wp-json\/wp\/v2\/posts\/1984","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sharanamshah.com\/mymusings\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sharanamshah.com\/mymusings\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sharanamshah.com\/mymusings\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sharanamshah.com\/mymusings\/wp-json\/wp\/v2\/comments?post=1984"}],"version-history":[{"count":0,"href":"https:\/\/sharanamshah.com\/mymusings\/wp-json\/wp\/v2\/posts\/1984\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sharanamshah.com\/mymusings\/wp-json\/wp\/v2\/media\/1989"}],"wp:attachment":[{"href":"https:\/\/sharanamshah.com\/mymusings\/wp-json\/wp\/v2\/media?parent=1984"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sharanamshah.com\/mymusings\/wp-json\/wp\/v2\/categories?post=1984"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sharanamshah.com\/mymusings\/wp-json\/wp\/v2\/tags?post=1984"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}