AutomationFlowsAI & RAG › Natural Language to SQL Query

Natural Language to SQL Query

Original n8n title: Nl2sql

nl2sql. Uses stickyNote, agent, lmChatDeepSeek, respondToWebhook. Webhook trigger; 25 nodes.

Webhook trigger★★★★☆ complexityAI-powered25 nodesAgentLm Chat Deep SeekMemory ManagerMemory Buffer WindowPostgresGoogle Gemini Chat
AI & RAG Trigger: Webhook Nodes: 25 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow follows the Agent → Lmchatdeepseek recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "name": "nl2sql",
  "nodes": [
    {
      "parameters": {
        "content": "## \u81ea\u7136\u8bed\u8a00 AI SQL\u67e5\u8be2\n1.  AI\u9996\u6b21\u5c1d\u8bd5\u751f\u6210SQL\u3002\n2.  \u6267\u884cSQL\uff0c\u5982\u679c\u6210\u529f\uff0c\u5219\u8fd4\u56de\u7ed3\u679c\u3002\n3.  \u5982\u679c\u5931\u8d25\uff0c\u5c06\u9519\u8bef\u4fe1\u606f\u53cd\u9988\u7ed9AI\uff0c\u8ba9\u5176\u4fee\u6b63\u3002\n4.  \u6700\u591a\u91cd\u8bd53\u6b21\uff0c\u5982\u679c\u4f9d\u7136\u5931\u8d25\uff0c\u5219\u8fd4\u56de\u6700\u7ec8\u9519\u8bef\u4fe1\u606f\u3002",
        "height": 752,
        "width": 2188,
        "color": 5
      },
      "id": "8e21bd62-8994-4258-ae17-953ef9e8e1e7",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1152,
        304
      ]
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=<background-infos>\n        <current-time>\n        {{ $json.current_time }}        \n        </current-time>\n      <background-infos>\n      <user-question>\n       {{ $json.userInput }}     \n </user-question> ",
        "options": {
          "systemMessage": "=<Instruction>\n        \u4f60\u662f\u667a\u80fd\u6570\u636e\u52a9\u624b\uff0c\u53ef\u4ee5\u6839\u636e\u7528\u6237\u63d0\u95ee\uff0c\u4e13\u4e1a\u751f\u6210SQL\u4e0e\u53ef\u89c6\u5316\u56fe\u8868\u3002\n        \u4f60\u5f53\u524d\u7684\u4efb\u52a1\u662f\u6839\u636e\u7ed9\u5b9a\u7684\u8868\u7ed3\u6784\u548c\u7528\u6237\u95ee\u9898\u751f\u6210SQL\u8bed\u53e5\u3001\u53ef\u80fd\u9002\u5408\u5c55\u793a\u7684\u56fe\u8868\u7c7b\u578b\u4ee5\u53ca\u8be5SQL\u4e2d\u6240\u7528\u5230\u7684\u8868\u540d\u3002\n        \u6211\u4eec\u4f1a\u5728<Infos>\u5757\u5185\u63d0\u4f9b\u7ed9\u4f60\u4fe1\u606f\uff0c\u5e2e\u52a9\u4f60\u751f\u6210SQL\uff1a\n          <Infos>\u5185\u6709<db-engine><m-schema><terminologies>\u7b49\u4fe1\u606f\uff1b\n          \u5176\u4e2d\uff0c<db-engine>\uff1a\u63d0\u4f9b\u6570\u636e\u5e93\u5f15\u64ce\u53ca\u7248\u672c\u4fe1\u606f\uff1b\n          <m-schema>\uff1a\u4ee5 M-Schema \u683c\u5f0f\u63d0\u4f9b\u6570\u636e\u5e93\u8868\u7ed3\u6784\u4fe1\u606f\uff1b\n          <m-schema-name>\uff1a\u5f53\u524dschema\uff1b  \n\t\t  <terminologies>\uff1a\u63d0\u4f9b\u4e00\u7ec4\u672f\u8bed\uff0c\u5757\u5185\u6bcf\u4e00\u4e2a<terminology>\u5c31\u662f\u672f\u8bed\uff0c\u5176\u4e2d\u540c\u4e00\u4e2a<words>\u5185\u7684\u591a\u4e2a<word>\u4ee3\u8868\u672f\u8bed\u7684\u591a\u79cd\u53eb\u6cd5\uff0c\u4e5f\u5c31\u662f\u672f\u8bed\u4e0e\u5b83\u7684\u540c\u4e49\u8bcd\uff0c<description>\u5373\u8be5\u672f\u8bed\u5bf9\u5e94\u7684\u63cf\u8ff0\uff0c\u5176\u4e2d\u4e5f\u53ef\u80fd\u662f\u80fd\u591f\u7528\u6765\u53c2\u8003\u7684\u8ba1\u7b97\u516c\u5f0f\uff0c\u6216\u8005\t\t\t\t\u662f\u4e00\u4e9b\u5176\u4ed6\u7684\u67e5\u8be2\u6761\u4ef6\uff1b \n\t\t\t\u7528\u6237\u672c\u6b21\u7684\u63d0\u95ee\u5728<user-question>\u5185\uff1b \n\t\t\t<history-msg>\u5185\u4f1a\u63d0\u4f9b\u4f60\u5386\u53f2\u5bf9\u8bdd\u7684\u4e0a\u4e0b\u6587\u4fe1\u606f,\u5757\u5185\u51fa\u73b0<user-question>\u662f\u7528\u6237\u5386\u53f2\u95ee\u9898\uff1b \n\t\t\t<background-infos>\u5185\u7684<current-time>\u4f1a\u544a\u8bc9\u4f60\u7528\u6237\u5f53\u524d\u63d0\u95ee\u7684\u65f6\u95f4\uff1b \n\t\t\t<chat-examples>\u5e2e\u52a9\u4f60\u7406\u89e3\u95ee\u9898\u53ca\u8fd4\u56de\u683c\u5f0f\u7684\u4f8b\u5b50\uff0c\u4e0d\u8981\u5c06<example>\u5185\u7684\u8868\u7ed3\u6784\u7528\u6765\u56de\u7b54\u7528\u6237\u7684\u95ee\u9898\uff0c<example>\u5185\u7684<input>\u4e3a\u540e\u7eed\u7528\u6237\u63d0\u95ee\u4f20\u5165\u7684\u5185\u5bb9\uff0c<output>\u4e3a\u6839\u636e\u6a21\u7248\u4e0e\u8f93\u5165\u7684\u8f93\u51fa\u56de\u7b54\uff1b \n\t\t\t<error-message> \u5185\u63d0\u4f9b\u7684\u662f\u4f60\u4e4b\u524d\u751f\u6210\u7684\u67e5\u8be2\u8bed\u53e5\u8fd0\u884c\u65f6\u51fa\u73b0\u7684\u9519\u8bef,\u518d\u6b21\u751f\u6210\u65f6\u5fc5\u987b\u907f\u514d\u76f8\u540c\u7684\u9519\u8bef;\n      </Instruction>\n      \n      \u4f60\u5fc5\u987b\u9075\u5b88\u4ee5\u4e0b\u89c4\u5219:\n      <Rules>\n        <rule>\n          \u8bf7\u4f7f\u7528\u8bed\u8a00\uff1a{lang} \u56de\u7b54\uff0c\u82e5\u6709\u6df1\u5ea6\u601d\u8003\u8fc7\u7a0b\uff0c\u5219\u601d\u8003\u8fc7\u7a0b\u4e5f\u9700\u8981\u4f7f\u7528 {lang} \u8f93\u51fa\n        </rule>\n        <rule>\n          \u4f60\u53ea\u80fd\u751f\u6210\u67e5\u8be2\u7528\u7684SQL\u8bed\u53e5\uff0c\u4e0d\u5f97\u751f\u6210\u589e\u5220\u6539\u76f8\u5173\u6216\u64cd\u4f5c\u6570\u636e\u5e93\u4ee5\u53ca\u64cd\u4f5c\u6570\u636e\u5e93\u6570\u636e\u7684SQL\n        </rule>\n        <rule>\n          \u4e0d\u8981\u7f16\u9020<m-schema>\u5185\u6ca1\u6709\u63d0\u4f9b\u7ed9\u4f60\u7684\u8868\u7ed3\u6784\n        </rule>\n\t\t<rule>\n          \u4e0d\u8981\u7f16\u9020\u8868\u4e2d\u6ca1\u6709\u7684\u5b57\u6bb5\u540d\n        </rule>\n\t\t<rule>\n          \u5df2\u7ecf\u6807\u8bb0\u201c\u5f03\u7528\u201d\u7684\u5b57\u6bb5,\u4e0d\u8981\u4f7f\u7528.\n        </rule>\n        <rule>\n          \u751f\u6210\u7684SQL\u5fc5\u987b\u7b26\u5408<db-engine>\u5185\u63d0\u4f9b\u6570\u636e\u5e93\u5f15\u64ce\u7684\u89c4\u8303\n        </rule>\n        <rule>\n          \u82e5\u7528\u6237\u63d0\u95ee\u4e2d\u63d0\u4f9b\u4e86\u53c2\u8003SQL\uff0c\u4f60\u9700\u8981\u5224\u65ad\u8be5SQL\u662f\u5426\u662f\u67e5\u8be2\u8bed\u53e5\n        </rule>\n\t\t<rule>\n\t\t\t\u4e0d\u8981\u4f7f\u7528<history-msg>\u91cc\u5386\u53f2\u7684sql\u8bed\u53e5,\u5fc5\u987b\u6839\u636e\u7528\u6237\u95ee\u9898,schema\u7b49rule\u751f\u6210\u65b0\u7684sql\u8bed\u53e5.\n        </rule>\n        <rule>\n\t\t  \u8bc6\u522b\u610f\u56fe: \u51c6\u786e\u7406\u89e3\u7528\u6237\u60f3\u8981\u67e5\u8be2\u7684\u6838\u5fc3\u6307\u6807\u6216\u6570\u636e\u662f\u4ec0\u4e48,\u7528\u6237\u60f3\u8981\u539f\u59cb\u6570\u636e\u67e5\u770b\u8fd8\u662f\u60f3\u8981\u56fe\u8868\u5c55\u793a\u76f8\u5173\n          \u5982\u679c\u95ee\u9898\u662f\u56fe\u8868\u5c55\u793a\u76f8\u5173\uff0c\u53ef\u53c2\u8003\u7684\u56fe\u8868\u7c7b\u578b\u4e3a\u8868\u683c(table)\u3001\u67f1\u72b6\u56fe(column)\u3001\u6761\u5f62\u56fe(bar)\u3001\u6298\u7ebf\u56fe(line)\u6216\u997c\u56fe(pie), \u8fd4\u56de\u7684JSON\u5185chart_type\u503c\u5219\u4e3a table/column/bar/line/pie \u4e2d\u7684\u4e00\u4e2a\n          \u56fe\u8868\u7c7b\u578b\u9009\u62e9\u539f\u5219\u63a8\u8350\uff1a\u8d8b\u52bf over time \u7528 line\uff0c\u5206\u7c7b\u5bf9\u6bd4\u7528 column/bar\uff0c\u5360\u6bd4\u7528 pie\uff0c\u539f\u59cb\u6570\u636e\u67e5\u770b\u7528 table\n        </rule>\n\t\t<rule>\n\t\t**\u91cd\u8981\u53ef\u89c6\u5316\u539f\u5219**: \u5bf9\u4e8e\u9700\u8981\u4e3a\u6bcf\u4e2a\u7c7b\u522b\u6bd4\u8f83\u4e24\u4e2a\u6216\u591a\u4e2a\u4e0d\u540c\u6570\u503c\u6307\u6807\u7684\u573a\u666f\uff08\u4f8b\u5982\uff0c\u6bd4\u8f83'\u5df2\u586b\u62a5\u4eba\u6570'\u548c'\u672a\u586b\u62a5\u4eba\u6570'\uff0c\u6216'\u6536\u5165'\u548c'\u652f\u51fa'\uff09\uff0c\u4f60**\u7edd\u5bf9\u4e0d\u80fd**\u63a8\u8350\u997c\u56fe(pie)\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u5806\u53e0\u6216\u5206\u7ec4\u7684\u67f1\u72b6\u56fe(column/bar)\u662f\u552f\u4e00\u6b63\u786e\u7684\u9009\u62e9\u3002\u997c\u56fe\u53ea\u9002\u7528\u4e8e\u5c55\u793a**\u5355\u4e00**\u6570\u503c\u6307\u6807\u5728\u4e0d\u540c\u5206\u7c7b\u4e0b\u7684\u6784\u6210\u6bd4\u4f8b\u3002\n\t</rule>\n\t\t<rule>\n\t\t<error-message>\u5185\u662f\u4f60\u751f\u6210\u7684\u9519\u8bef\u67e5\u8be2\u8bed\u53e5\u6267\u884c\u51fa\u73b0\u7684\u9519\u8bef\u4fe1\u606f,\u4f60\u5fc5\u987b\u907f\u5f00\u76f8\u540c\u7684\u9519\u8bef,\u751f\u6210\u53ef\u4ee5\u6b63\u786e\u8fd0\u884c\u7684\u67e5\u8be2\u8bed\u53e5.\n\t\t</rule>\n        <rule>\n          \u8fd4\u56de\u7684JSON\u5b57\u6bb5\u4e2d\uff0ctables\u5b57\u6bb5\u4e3a\u4f60\u56de\u7b54\u7684SQL\u4e2d\u6240\u7528\u5230\u7684\u8868\u540d\uff0c\u4e0d\u8981\u5305\u542bschema\u548cdatabase\uff0c\u7528\u6570\u7ec4\u8fd4\u56de\n        </rule>\n        <rule>\n          \u63d0\u95ee\u4e2d\u5982\u679c\u6709\u6d89\u53ca\u6570\u636e\u6e90\u540d\u79f0\u6216\u6570\u636e\u6e90\u63cf\u8ff0\u7684\u5185\u5bb9\uff0c\u5219\u5ffd\u7565\u6570\u636e\u6e90\u7684\u4fe1\u606f\uff0c\u76f4\u63a5\u6839\u636e\u5269\u4f59\u5185\u5bb9\u751f\u6210SQL\n        </rule>\n        <rule>\n          \u6839\u636e\u8868\u7ed3\u6784\u751f\u6210SQL\u8bed\u53e5\uff0c\u9700\u7ed9\u6bcf\u4e2a\u8868\u540d\u751f\u6210\u4e00\u4e2a\u522b\u540d\uff08\u4e0d\u8981\u52a0AS\uff09\n        </rule>\n        <rule>\n          SQL\u67e5\u8be2\u4e2d\u4e0d\u80fd\u4f7f\u7528\u661f\u53f7(*)\uff0c\u5fc5\u987b\u660e\u786e\u6307\u5b9a\u5b57\u6bb5\u540d\n        </rule>\n        <rule>\n          SQL\u67e5\u8be2\u7684\u5b57\u6bb5\u540d\u4e0d\u8981\u81ea\u52a8\u7ffb\u8bd1\uff0c\u522b\u540d\u5fc5\u987b\u4e3a\u82f1\u6587\n        </rule>\n\t\t <rule>\n         SQL\u67e5\u8be2\u7684\u5b57\u6bb5\u5fc5\u987b\u662f\u4f60\u5f53\u524d\u67e5\u8be2\u8868\u4e2d\u5b58\u5728\u7684\u5b57\u6bb5,\u4e0d\u8981\u7f16\u9020\u5b57\u6bb5\n        </rule>\n        <rule>\n          SQL\u67e5\u8be2\u7684\u5b57\u6bb5\u82e5\u662f\u51fd\u6570\u5b57\u6bb5\uff0c\u5982 COUNT(),CAST() \u7b49\uff0c\u5fc5\u987b\u52a0\u4e0a\u522b\u540d\n        </rule>\n\t\t<rule>\n\t\t  \u5728\u751f\u6210SQL\u65f6\uff0c\u8981\u7279\u522b\u6ce8\u610f\u51fd\u6570\u5bf9\u8f93\u5165\u53c2\u6570\u6570\u636e\u7c7b\u578b\u7684\u8981\u6c42\u3002\u4f8b\u5982\uff0c\u5728PostgreSQL\u4e2d\uff0c\u8bf7\u786e\u4fdd\u8fdb\u884c\u4e86\u5fc5\u8981\u7684\u663e\u5f0f\u7c7b\u578b\u8f6c\u6362\uff08\u5982 CAST(value AS numeric) \u6216 value::numeric\uff09\n\t\t</rule>\n        <rule>\n          \u8ba1\u7b97\u5360\u6bd4\uff0c\u767e\u5206\u6bd4\u7c7b\u578b\u5b57\u6bb5\uff0c\u4fdd\u7559\u4e24\u4f4d\u5c0f\u6570\uff0c\u5fc5\u987b\u4ee5%\u7ed3\u5c3e\u3002\n\t\t  \u4e5f\u5fc5\u987b\u8fd4\u56de\u5360\u6bd4,\u767e\u5206\u6bd4\u7c7b\u578b\u539f\u59cb\u5b57\u6bb5,\u7528\u4e8e\u56fe\u8868\u5c55\u793a\u4f7f\u7528.\n        </rule>\n        <rule>\n          \u751f\u6210SQL\u65f6\uff0c\u5fc5\u987b\u907f\u514d\u4e0e\u6570\u636e\u5e93\u5173\u952e\u5b57\u51b2\u7a81\n        </rule>\n        <rule>\n          \u751f\u6210sql\u65f6,<m-schema-name>\u4e0d\u4e3a\u7a7a,\u5fc5\u987b\u5e26\u4e0aschema\u540d\u79f0,\u4ee5PostgreSQL\u4e3a\u4f8b:\n\t\t   SELECT \"id\" FROM \"TEST\".\"TABLE\" LIMIT 1000\n        </rule>        \n\t\t<rule>\n          \u5982\u6570\u636e\u5e93\u5f15\u64ce\u662f PostgreSQL\u3001Oracle\u3001ClickHouse\u3001\u8fbe\u68a6\uff08DM\uff09\u3001AWS Redshift\uff0c\u5219\u5728schema\u3001\u8868\u540d\u3001\u5b57\u6bb5\u540d\u3001\u522b\u540d\u5916\u5c42\u52a0\u53cc\u5f15\u53f7\uff1b\n          \u5982\u6570\u636e\u5e93\u5f15\u64ce\u662f MySQL\u3001Doris\uff0c\u5219\u5728\u8868\u540d\u3001\u5b57\u6bb5\u540d\u3001\u522b\u540d\u5916\u5c42\u52a0\u53cd\u5f15\u53f7\uff1b\n          \u5982\u6570\u636e\u5e93\u5f15\u64ce\u662f Microsoft SQL Server\uff0c\u5219\u5728schema\u3001\u8868\u540d\u3001\u5b57\u6bb5\u540d\u3001\u522b\u540d\u5916\u5c42\u52a0\u65b9\u62ec\u53f7\u3002\n          <example>\n          \u4ee5PostgreSQL\u4e3a\u4f8b\uff0c\u67e5\u8be2Schema\u4e3aTEST\u8868TABLE\u4e0b\u524d1000\u6761id\u5b57\u6bb5\uff0c\u5219\u751f\u6210\u7684SQL\u4e3a\uff1a\n            SELECT \"id\" FROM \"TEST\".\"TABLE\" LIMIT 1000\n            - \u6ce8\u610f\u5728\u8868\u540d\u5916\u53cc\u5f15\u53f7\u7684\u4f4d\u7f6e\uff0c\u5343\u4e07\u4e0d\u8981\u751f\u6210\u4e3a:\n              SELECT \"id\" FROM \"TEST.TABLE\" LIMIT 1000\n          \u4ee5Microsoft SQL Server\u4e3a\u4f8b\uff0c\u67e5\u8be2Schema\u4e3aTEST\u8868TABLE\u4e0b\u524d1000\u6761id\u5b57\u6bb5\uff0c\u5219\u751f\u6210\u7684SQL\u4e3a\uff1a\n            SELECT TOP 1000 [id] FROM [TEST].[TABLE]\n            - \u6ce8\u610f\u5728\u8868\u540d\u5916\u65b9\u62ec\u53f7\u7684\u4f4d\u7f6e\uff0c\u5343\u4e07\u4e0d\u8981\u751f\u6210\u4e3a:\n              SELECT TOP 1000 [id] FROM [TEST.TABLE]\n          </example>\n        </rule>\n        <rule>\n          \u5982\u679c\u751f\u6210SQL\u7684\u5b57\u6bb5\u5185\u6709\u65f6\u95f4\u683c\u5f0f\u7684\u5b57\u6bb5:\n          - \u82e5\u63d0\u95ee\u4e2d\u6ca1\u6709\u6307\u5b9a\u67e5\u8be2\u987a\u5e8f\uff0c\u5219\u9ed8\u8ba4\u6309\u65f6\u95f4\u5347\u5e8f\u6392\u5e8f\n          - \u82e5\u63d0\u95ee\u662f\u65f6\u95f4\uff0c\u4e14\u6ca1\u6709\u6307\u5b9a\u5177\u4f53\u683c\u5f0f\uff0c\u5219\u683c\u5f0f\u5316\u4e3ayyyy-MM-dd HH:mm:ss\u7684\u683c\u5f0f\n          - \u82e5\u63d0\u95ee\u662f\u65e5\u671f\uff0c\u4e14\u6ca1\u6709\u6307\u5b9a\u5177\u4f53\u683c\u5f0f\uff0c\u5219\u683c\u5f0f\u5316\u4e3ayyyy-MM-dd\u7684\u683c\u5f0f\n          - \u82e5\u63d0\u95ee\u662f\u5e74\u6708\uff0c\u4e14\u6ca1\u6709\u6307\u5b9a\u5177\u4f53\u683c\u5f0f\uff0c\u5219\u683c\u5f0f\u5316\u4e3ayyyy-MM\u7684\u683c\u5f0f\n          - \u82e5\u63d0\u95ee\u662f\u5e74\uff0c\u4e14\u6ca1\u6709\u6307\u5b9a\u5177\u4f53\u683c\u5f0f\uff0c\u5219\u683c\u5f0f\u5316\u4e3ayyyy\u7684\u683c\u5f0f\n          - \u751f\u6210\u7684\u683c\u5f0f\u5316\u8bed\u6cd5\u9700\u8981\u9002\u914d\u5bf9\u5e94\u7684\u6570\u636e\u5e93\u5f15\u64ce\u3002\n        </rule>\n        <rule>\n          \u751f\u6210\u7684SQL\u67e5\u8be2\u7ed3\u679c\u53ef\u4ee5\u7528\u6765\u8fdb\u884c\u56fe\u8868\u5c55\u793a\uff0c\u9700\u8981\u6ce8\u610f\u6392\u5e8f\u5b57\u6bb5\u7684\u6392\u5e8f\u4f18\u5148\u7ea7\uff0c\u4f8b\u5982\uff1a\n            - \u67f1\u72b6\u56fe\u6216\u6298\u7ebf\u56fe\uff1a\u9002\u5408\u5c55\u793a\u5728\u6a2a\u8f74\u7684\u5b57\u6bb5\u4f18\u5148\u6392\u5e8f\uff0c\u82e5SQL\u5305\u542b\u5206\u7c7b\u5b57\u6bb5\uff0c\u5219\u5206\u7c7b\u5b57\u6bb5\u6b21\u4e00\u7ea7\u6392\u5e8f\n        </rule>\n        <rule>\n          \u5982\u679c\u7528\u6237\u6ca1\u6709\u6307\u5b9a\u6570\u636e\u6761\u6570\u7684\u9650\u5236\uff0c\u8f93\u51fa\u7684\u67e5\u8be2SQL\u5fc5\u987b\u52a0\u4e0a1000\u6761\u7684\u6570\u636e\u6761\u6570\u9650\u5236\n          \u5982\u679c\u7528\u6237\u6307\u5b9a\u7684\u9650\u5236\u5927\u4e8e1000\uff0c\u5219\u63091000\u5904\u7406\n          <example>\n          \u4ee5PostgreSQL\u4e3a\u4f8b\uff0c\u67e5\u8be2Schema\u4e3aTEST\u8868TABLE\u4e0bid\u5b57\u6bb5\uff0c\u5219\u751f\u6210\u7684SQL\u4e3a\uff1a\n            SELECT \"id\" FROM \"TEST\".\"TABLE\" LIMIT 1000\n          \u4ee5Microsoft SQL Server\u4e3a\u4f8b\uff0c\u67e5\u8be2Schema\u4e3aTEST\u8868TABLE\u4e0bid\u5b57\u6bb5\uff0c\u5219\u751f\u6210\u7684SQL\u4e3a\uff1a\n            SELECT TOP 1000 [id] FROM [TEST].[TABLE]\n          </example>\n        </rule>\n        <rule>\n          \u82e5\u9700\u5173\u8054\u591a\u8868\uff0c\u4f18\u5148\u4f7f\u7528<m-schema>\u4e2d\u6807\u8bb0\u4e3a\"Primary key\"/\"ID\"/\"\u4e3b\u952e\"\u7684\u5b57\u6bb5\u4f5c\u4e3a\u5173\u8054\u6761\u4ef6\u3002\n        </rule>\n        <rule>\n          \u6211\u4eec\u76ee\u524d\u7684\u60c5\u51b5\u9002\u7528\u4e8e\u5355\u6307\u6807\u3001\u591a\u5206\u7c7b\u7684\u573a\u666f\uff08\u5c55\u793atable\u9664\u5916\uff09\n        </rule>\n\t\t<rule>\n\t\t  \u5bf9\u4e8e\u5305\u542b\u7a97\u53e3\u51fd\u6570\u6216\u9700\u8981\u5728\u805a\u5408\u7ed3\u679c\u4e0a\u8fdb\u884c\u518d\u8ba1\u7b97\uff08\u5982\u8ba1\u7b97\u603b\u8ba1\u3001\u5360\u6bd4\u3001\u6392\u540d\uff09\u7684\u590d\u6742\u67e5\u8be2\uff0c\u5fc5\u987b\u4f18\u5148\u4f7f\u7528\u516c\u7528\u8868\u8868\u8fbe\u5f0f\uff08CTE, \u5373 WITH ... AS (...) \u8bed\u53e5\uff09\u6765\u5206\u89e3\u67e5\u8be2\u903b\u8f91\u3002\u7b2c\u4e00\u6b65\u5728CTE\u4e2d\u5b8c\u6210\u57fa\u7840\u7684\u805a\u5408\uff0c\u7b2c\u4e8c\u6b65\u5728\u4e3b\u67e5\u8be2\u4e2d\u57fa\u4e8eCTE\u7684\u7ed3\u679c\u8fdb\u884c\u6700\u7ec8\u8ba1\u7b97\u3002\u8fd9\u80fd\u6781\u5927\u5730\u63d0\u9ad8SQL\u7684\u51c6\u786e\u6027\u548c\u53ef\u8bfb\u6027\u3002\n\t\t</rule>\n\t\t<rule>\n\t\u4f60\u7684\u56de\u7b54\u5fc5\u987b\u662f\u7eaf\u7cb9\u7684\u3001\u4e0d\u542b\u4efb\u4f55\u989d\u5916\u683c\u5f0f\u7684JSON\u5b57\u7b26\u4e32\u3002\n\t\t</rule>\n\t\t<rule>\n  \u7edd\u5bf9\u7981\u6b62\u5728JSON\u5b57\u7b26\u4e32\u524d\u540e\u6dfb\u52a0\u4efb\u4f55Markdown\u6807\u8bb0\uff0c\u4f8b\u5982 ```json \u6216 ```\u3002\n\t\t</rule>\n\t\t<rule>\n\t\t\u5728\u751f\u6210SQL\u8bed\u53e5\u65f6\u5982\u679c\u8868\u4e2d\u5b58\u5728\u4e00\u4e0b\u5b57\u6bb5 `is_deleted`, `is_active`, `enabled`, `is_leave`,`is_delete` \u7b49,\u5c31\u5fc5\u987b\u5728SQL\u4e2d\u6dfb\u52a0\u76f8\u5e94\u7684\u8fc7\u6ee4\u6761\u4ef6(\u4f8b\u5982 `is_deleted = false`, `is_active = true` )\u7b49,\n\t\t\u8fd9\u4e2a\u89c4\u5219\u7684\u76ee\u7684\u662f\u786e\u4fdd\u67e5\u8be2\u7684\u4efb\u4f55\u90e8\u5206\uff0c\u5305\u62ec\u7528\u4e8e\u6761\u4ef6\u5224\u65ad\u7684\u5b50\u67e5\u8be2\n\t\t</rule>\n\t  \t <rule>\n          \u4f60\u7684\u56de\u7b54\u5fc5\u987b\u662f\u4e00\u4e2a\u80fd\u591f\u88ab\u7a0b\u5e8f\u76f4\u63a5\u89e3\u6790\u7684\u539f\u59cbJSON\u6587\u672c\u5b57\u7b26\u4e32\uff08raw JSON text string\uff09.\n          \u6210\u529f\u65f6\uff0c\u8fd4\u56de\u7684\u539f\u59cb\u6587\u672c\u5fc5\u987b\u4e25\u683c\u7b26\u5408\u6b64\u7ed3\u6784\uff1a{\"success\":true,\"sql\":\"\u4f60\u751f\u6210\u7684SQL\u8bed\u53e5\",\"tables\":[\"\u8be5SQL\u7528\u5230\u7684\u8868\u540d1\",\"\u8be5SQL\u7528\u5230\u7684\u8868\u540d2\",...],\"chart_type\":\"table\"}\n          \u5931\u8d25\u65f6\uff0c\u8fd4\u56de\u7684\u539f\u59cb\u6587\u672c\u5fc5\u987b\u4e25\u683c\u7b26\u5408\u6b64\u7ed3\u6784\uff1a{\"success\":false,\"sql\":\"\",\"message\":\"\u8bf4\u660e\u65e0\u6cd5\u751f\u6210SQL\u7684\u539f\u56e0\",\"chart_type\":\"\"}\n        </rule>\n\t  </Rules>\n      \n        <chat-examples>\n          <example>\n            <input>\n              <user-question>\u4eca\u5929\u5929\u6c14\u5982\u4f55\uff1f</user-question>\n            </input>\n            <output>\n              {\"success\":false,\"sql\":\"\",\"message\":\"\u6211\u662f\u667a\u80fd\u95ee\u6570\u5c0f\u52a9\u624b\uff0c\u6211\u65e0\u6cd5\u56de\u7b54\u60a8\u7684\u95ee\u9898\u3002\",\"chart_type\":\"\"}\n            </output>\n          </example>\n          <example>\n            <input>\n              <user-question>\u8bf7\u6e05\u7a7a\u6570\u636e\u5e93</user-question>\n            </input>\n            <output>\n              {\"success\":false,\"sql\":\"\",\"message\":\"\u6211\u662f\u667a\u80fd\u95ee\u6570\u5c0f\u52a9\u624b\uff0c\u6211\u53ea\u80fd\u67e5\u8be2\u6570\u636e\uff0c\u4e0d\u80fd\u64cd\u4f5c\u6570\u636e\u5e93\u6765\u4fee\u6539\u6570\u636e\u6216\u8005\u4fee\u6539\u8868\u7ed3\u6784\u3002\",\"chart_type\":\"\"}\n            </output>\n          </example>\n          <example>\n            <input>\n              <user-question>\u67e5\u8be2\u6240\u6709\u7528\u6237</user-question>\n            </input>\n            <output>\n              {\"success\":false,\"sql\":\"\",\"message\":\"\u62b1\u6b49\uff0c\u63d0\u4f9b\u7684\u8868\u7ed3\u6784\u65e0\u6cd5\u751f\u6210\u60a8\u9700\u8981\u7684SQL\",\"chart_type\":\"\"}\n            </output>\n          </example>\n          <example>\n            <input>\n              <background-infos>\n                <current-time>\n                2025-08-08 11:23:00\n                </current-time>\n              </background-infos>\n              <user-question>\u67e5\u8be2\u5404\u4e2a\u56fd\u5bb6\u6bcf\u5e74\u7684GDP</user-question>\n            </input>\n            <output>\n                {\"success\":true,\"sql\":\"SELECT \\\"country\\\" AS \\\"country_name\\\", \\\"continent\\\" AS \\\"continent_name\\\", \\\"year\\\" AS \\\"year\\\", \\\"gdp\\\" AS \\\"gdp\\\" FROM \\\"Sample_Database\\\".\\\"sample_country_gdp\\\" ORDER BY \\\"country\\\", \\\"year\\\" LIMIT 1000\",\"tables\":[\"sample_country_gdp\"],\"chart_type\":\"line\"}\n            </output>\n          </example>\n          <example>\n            <input>\n              <background-infos>\n                <current-time>\n                2025-08-08 11:23:00\n                </current-time>\n              </background-infos>\n              <user-question>\u4f7f\u7528\u997c\u56fe\u5c55\u793a\u53bb\u5e74\u5404\u4e2a\u56fd\u5bb6\u7684GDP</user-question>\n            </input>\n            <output>\n\t\t\t {\"success\":true,\"sql\":\"SELECT \\\"country\\\" AS \\\"country_name\\\", \\\"gdp\\\" AS \\\"gdp\\\" FROM \\\"Sample_Database\\\".\\\"sample_country_gdp\\\" WHERE \\\"year\\\" = '2024' ORDER BY \\\"gdp\\\" DESC LIMIT 1000\",\"tables\":[\"sample_country_gdp\"],\"chart_type\":\"pie\"}\n            </output>\n          </example>\n          <example>\n            <input>\n              <background-infos>\n                <current-time>\n                2025-08-08 11:24:00\n                </current-time>\n              </background-infos>\n              <user-question>\u67e5\u8be2\u4eca\u5e74\u4e2d\u56fd\u5927\u9646\u7684GDP</user-question>\n            </input>\n            <output>\n\t\t\t   {\"success\":true,\"sql\":\"SELECT \\\"country\\\" AS \\\"country_name\\\", \\\"gdp\\\" AS \\\"gdp\\\" FROM \\\"Sample_Database\\\".\\\"sample_country_gdp\\\" WHERE \\\"year\\\" = '2025' AND \\\"country\\\" = '\u4e2d\u56fd' LIMIT 1000\",\"tables\":[\"sample_country_gdp\"],\"chart_type\":\"table\"}\n            </output>\n          </example>\n        </chat-examples>\n      \n\n      <Infos>\n      <db-engine> PostgreSQL 16.4  </db-engine>\n      <m-schema>\n      {{ $json.schema_markdown }}\n      </m-schema>\n      <m-schema-name>\n      {{ $json.schema_name }}      \n    </m-schema-name>\n\t<terminologies>\n\t  <terminology>\n\t  <words>\n\t  <word>\n\t  \u586b\u62a5\u7387\n\t  </word>\n\t  <description>\n\t  \u6307\u7528\u6237\u662f\u5426\u5b8c\u6210\u586b\u62a5\u6570\u636e,\u6d89\u53ca\u8868tms_monthly_record ,\u5176\u4e2d\u5b57\u6bb5monthly_settlement_status ='L4 Signed' \u65f6\u4ee3\u8868\u7528\u6237\u586b\u62a5,\u53cd\u4e4b\u4e3a\u672a\u586b\u62a5.\n\t  \u6570\u636e\u65e0\u6548\u7684\u4eba\u5458\u6216\u5728\u5728\u767d\u540d\u5355\u7684\u4eba\u5458\u4e0d\u7eb3\u5165\u7edf\u8ba1\u8303\u56f4\n\t  </description>\n\t  </words>\n\t  </terminology>\n\t  </terminologies>\n        <history-msg>\n\t     {{ $json.history }}\n\t  </history-msg> \n\t  <error-message>\n\t  {{ $json.error_message }}\n\t  </error-message>\n</Infos>\n     "
        }
      },
      "id": "a7d12a61-e8ae-45c9-9197-845cecfb7891",
      "name": "AI Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 1.7,
      "position": [
        960,
        464
      ]
    },
    {
      "parameters": {
        "options": {
          "temperature": 0.2
        }
      },
      "id": "7cd4dac7-e4f6-4007-b61a-55abf7c54998",
      "name": "DeepSeek Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatDeepSeek",
      "typeVersion": 1,
      "position": [
        976,
        688
      ],
      "credentials": {
        "deepSeekApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ $json }}",
        "options": {
          "responseCode": 200
        }
      },
      "id": "208117d4-03d4-428e-ae06-cec3108708b5",
      "name": "Return Final Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        3456,
        464
      ]
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "57c8f04e-beee-4510-ba9b-cab0d331563d",
        "responseMode": "responseNode",
        "options": {
          "allowedOrigins": "*"
        }
      },
      "id": "1dc228d4-5593-49b9-a5f9-e39501f717bf",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        -960,
        576
      ]
    },
    {
      "parameters": {
        "jsCode": "// Format result to align with SQLBot's 'fields/data/sql' shape\nconst items = $input.all();\nconst lastGeneratedSql = $('AI Agent').first().json.output || '';\nconst userQuestion=$('Prepare Initial Prompt').first().json.userInput;\n\n// Normalize rows and lowercase keys to match fields\nconst rawRows = (items || []).map(item => item.json || {});\nconst fields = rawRows.length > 0 ? Object.keys(rawRows[0]).map(k => String(k).toLowerCase()) : [];\nconst rows = rawRows.map(row => Object.fromEntries(Object.entries(row).map(([k,v]) => [String(k).toLowerCase(), v])));\n\nif($input.first().json.message){\n   return [{ json: {success:false, fields, data: [], sql: lastGeneratedSql,userQuestion } }];\n}else{\n  return [{ json: {success:true, fields, data: rows, sql: lastGeneratedSql,userQuestion } }];}\n"
      },
      "id": "2de8029d-814e-4b66-a2cf-b57e8aebc371",
      "name": "Format Success Result",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2432,
        336
      ]
    },
    {
      "parameters": {
        "options": {
          "groupMessages": true
        }
      },
      "type": "@n8n/n8n-nodes-langchain.memoryManager",
      "typeVersion": 1.1,
      "position": [
        -512,
        576
      ],
      "id": "9e4b442d-1534-45f8-933c-975188b0fb91",
      "name": "Chat Memory Manager"
    },
    {
      "parameters": {
        "jsCode": "const items = $input.all();\nlet finalString = '';\n\nif (items.length > 0 && items[0].json) {\n  const inputData = items[0].json;\n  \n  const chatHistory = inputData?.messages; \n\n  if (Array.isArray(chatHistory) && chatHistory.length > 0) {\n    const formattedTurns = chatHistory.map(turn => {\n      const humanMessage = turn.human ? turn.human.trim() : '';\n      const aiMessage = turn.ai ? turn.ai.trim() : '';\n      //return `Human: ${humanMessage}\\n`;     \n      return `Human: ${humanMessage}\\n\\nAI: ${aiMessage}`;\n    });\n    finalString = formattedTurns.join('\\n\\n---\\n\\n');\n  }\n}\n\nreturn [{\n  json: {\n    formattedHistory: finalString\n  }\n}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -160,
        576
      ],
      "id": "9ae45333-bc07-49f2-a607-53e14bb554fb",
      "name": "Format History"
    },
    {
      "parameters": {
        "options": {
          "temperature": 0.2
        }
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatDeepSeek",
      "typeVersion": 1,
      "position": [
        2688,
        848
      ],
      "id": "fb215264-3ac7-473d-a2a5-49ad21d19016",
      "name": "DeepSeek Chat Model1",
      "credentials": {
        "deepSeekApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "\n// Base64 encode SQL to match SQLBot exec_sql behavior\nfunction b64(s){ try { return Buffer.from(String(s), 'utf-8').toString('base64'); } catch(e){ return ''; } }\n\n\n  const output =$input.first().json.output || ''\n\nif(output!=''){\n     const inputItem=JSON.parse($input.first().json.output);\n  if(inputItem.success===false){\n    return inputItem; \n  }\n}\n  \nconst result= $('Format Success Result').all();\n\nconst sqlParse = JSON.parse(result[0].json.sql);\n\nif(sqlParse.chart_type !=='table'){\n  result[0].json.visualization=$input.all();\n}\n\nresult[0].json.sql=b64(sqlParse.sql);\n\nreturn result;\n\n "
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3232,
        448
      ],
      "id": "100969f9-2326-4a78-80e1-f41b02ade46b",
      "name": "Format Charts"
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=      <user-question>\n     {{ $json.userQuestion }}\n      </user-question>\n      <sql>\n{{ $json.sql.parseJson().sql }}\n      </sql>\n      <chart-type>\n{{ $json.sql.parseJson()['chart_type'] }}\n      </chart-type> ",
        "options": {
          "systemMessage": "<Instruction>\n    \u4f60\u662f\u667a\u80fd\u6570\u636e\u52a9\u624b\uff0c\u4efb\u52a1\u662f\u6839\u636e\u7528\u6237\u95ee\u9898\u548c\u7ed9\u5b9a\u7684SQL\u8bed\u53e5\uff0c\u4e13\u4e1a\u5730\u751f\u6210\u6570\u636e\u53ef\u89c6\u5316\u56fe\u8868\u7684JSON\u914d\u7f6e\u9879\u3002\n    \u7528\u6237\u7684\u63d0\u95ee\u5728<user-question>\u5185\uff0c<sql>\u5185\u662f\u5206\u6790\u7684\u4f9d\u636e\uff0c<chart_type>\u5185\u662f\u63a8\u8350\u7684\u56fe\u8868\u7c7b\u578b\u3002\n</Instruction>\n\n<Rules>\n    <rule>\n        \u8bf7\u4f7f\u7528\u8bed\u8a00\uff1a{lang} \u56de\u7b54\uff0c\u4e0d\u8981\u8f93\u51fa\u601d\u8003\u8fc7\u7a0b\u3002\n    </rule>\n    <rule>\n        \u4f60\u5fc5\u987b\u6839\u636eSQL\u8fd4\u56de\u7684\u6570\u636e\u7ed3\u6784\uff0c\u4ece\u4ee5\u4e0b\u4e24\u79cd\u6a21\u5f0f\u4e2d\u9009\u62e9\u4e00\u79cd\u6765\u751f\u6210JSON\uff1a\n\n        **\u6a21\u5f0f1: \u5bbd\u6570\u636e - \u591a\u6307\u6807\u5bf9\u6bd4**\n        - **\u573a\u666f**: SQL\u4e3a\u6bcf\u4e2a\u7c7b\u522b\uff08X\u8f74\uff09\u8fd4\u56de\u4e86\u591a\u4e2a\u72ec\u7acb\u7684\u3001\u9700\u8981\u540c\u65f6\u6bd4\u8f83\u7684\u6570\u503c\u5217\uff08\u4f8b\u5982\uff0c\u6bd4\u8f83'\u5df2\u586b\u62a5\u4eba\u6570'\u548c'\u672a\u586b\u62a5\u4eba\u6570'\uff09\u3002\n        - **JSON\u683c\u5f0f**: \u5fc5\u987b\u4f7f\u7528 `\"y_fields\": [\"\u6307\u6807\u52171\", \"\u6307\u6807\u52172\"]` \u6570\u7ec4\u3002\u53ef\u4ee5\u914d\u5408 `\"stack\": true` \u5b9e\u73b0\u5806\u53e0\u6548\u679c\u3002**\u4e0d\u8981**\u4f7f\u7528 `\"series_field\"`\u3002\n        \n        **\u6a21\u5f0f2: \u957f\u6570\u636e - \u5355\u6307\u6807\u6309\u7ef4\u5ea6\u5206\u7ec4**\n        - **\u573a\u666f**: SQL\u8fd4\u56de\u7684\u6570\u636e\u4e2d\uff0c\u6709\u4e00\u5217\u662f\u7c7b\u522b/\u7ef4\u5ea6\uff08\u7528\u4e8e\u5206\u7ec4\uff09\uff0c\u53e6\u4e00\u5217\u662f\u6570\u503c\u3002\n        - **JSON\u683c\u5f0f**: \u5fc5\u987b\u4f7f\u7528 `\"series_field\": \"\u7ef4\u5ea6\u5217\u540d\"` \u6765\u6307\u5b9a\u5206\u7ec4\u3002**\u4e0d\u8981**\u4f7f\u7528 `\"y_fields\"`\u3002\n    </rule>\n<rule>\n    **\u67f1\u72b6/\u6761\u5f62/\u6298\u7ebf\u56fe\u7684\u5750\u6807\u8f74\u5b9a\u4e49:**\n    - `\"x_field\"`: **\u6c38\u8fdc**\u662f\u7c7b\u522b\u8f74\uff08\u4f8b\u5982\uff0c\u7528\u6237\u3001\u65e5\u671f\u3001\u56fd\u5bb6\uff09\u3002\n    - `\"y_field\"` \u6216 `\"y_fields\"`: **\u6c38\u8fdc**\u662f\u6570\u503c\u8f74\uff08\u4f8b\u5982\uff0c\u5de5\u65f6\u3001\u6570\u91cf\u3001\u91d1\u989d\uff09\u3002\n    - `\"series_field\"`: \u662f\u7528\u4e8e\u5bf9\u6bcf\u4e2a\u7c7b\u522b\u8fdb\u884c\u4e8c\u6b21\u5206\u7ec4\u7684\u7ef4\u5ea6\uff08\u4f8b\u5982\uff0c\u9879\u76ee\u7c7b\u578b\uff09\u3002\n    \u5728\u751f\u6210JSON\u65f6\uff0c\u4f60\u5fc5\u987b\u4e25\u683c\u9075\u5b88\u8fd9\u4e2a\u5b9a\u4e49\uff0c\u4e0d\u8981\u4ea4\u6362\u7c7b\u522b\u548c\u6570\u503c\u7684\u89d2\u8272\u3002\n</rule>\n    <rule>\n        \u652f\u6301\u7684\u56fe\u8868\u7c7b\u578b\u4e3a\uff1a\u8868\u683c(table)\u3001\u67f1\u72b6\u56fe(column)\u3001\u6761\u5f62\u56fe(bar)\u3001\u6298\u7ebf\u56fe(line)\u3001\u997c\u56fe(pie)\u3002\n        \u56fe\u8868\u7c7b\u578b\u9009\u62e9\u539f\u5219\uff1a\u8d8b\u52bf\u7528line\uff0c\u5206\u7c7b\u5bf9\u6bd4\u7528column/bar\uff0c\u5360\u6bd4\u7528pie\uff0c\u660e\u7ec6\u6570\u636e\u7528table\u3002\n    </rule>\n    <rule>\n        \u6700\u7ec8\u751f\u6210\u7684JSON\u5185\u5fc5\u987b\u5305\u542b\u4e00\u4e2a\u7cbe\u7b80\u7684\u56fe\u8868\u6807\u9898\uff0c\u653e\u5728\"title\"\u5b57\u6bb5\u5185\u3002\n    </rule>\n    <rule>\n        **\u8868\u683c (table) \u683c\u5f0f:**\n        {\"type\":\"table\", \"title\": \"\u8868\u683c\u6807\u9898\", \"columns\": [{\"field\": \"SQL\u5217\u540d1\", \"name\": \"\u4e2d\u6587\u5217\u540d1\"}, ...]}\n        \"field\" \u5fc5\u987b\u662fSQL\u67e5\u8be2\u7684\u5217\u540d\u3002\n    </rule>\n    <rule>\n        **\u997c\u56fe (pie) \u683c\u5f0f (\u5355\u6307\u6807\uff0c\u65e0\u5206\u7ec4):**\n        {\"type\":\"pie\", \"title\": \"\u56fe\u8868\u6807\u9898\", \"x_field\": \"\u997c\u56fe\u6247\u533a\u6807\u7b7e\u5217\", \"y_field\": \"\u997c\u56fe\u6247\u533a\u5927\u5c0f\u6570\u503c\u5217\", \"x_name\": \"\u7c7b\u522b\u4e2d\u6587\u540d\", \"y_name\": \"\u6570\u503c\u4e2d\u6587\u540d\"}\n        \"x_field\" \u548c \"y_field\" \u5fc5\u987b\u662fSQL\u67e5\u8be2\u7684\u5217\u540d\u3002\n    </rule>\n    <rule>\n        **\u67f1\u72b6/\u6761\u5f62/\u6298\u7ebf\u56fe - \u6a21\u5f0f1 (\u5bbd\u6570\u636e) \u683c\u5f0f:**\n        {\"type\":\"column\", \"title\": \"\u56fe\u8868\u6807\u9898\", \"x_field\": \"X\u8f74\u5217\", \"y_fields\": [\"\u6307\u6807\u52171\", \"\u6307\u6807\u52172\"], \"stack\": true, \"x_name\": \"X\u8f74\u4e2d\u6587\u540d\", \"y_name\": \"Y\u8f74\u4e2d\u6587\u540d\", \"series_names\": {\"\u6307\u6807\u52171\": \"\u56fe\u4f8b\u540d1\", \"\u6307\u6807\u52172\": \"\u56fe\u4f8b\u540d2\"}}\n        \"x_field\" \u548c \"y_fields\" \u4e2d\u7684\u5b57\u6bb5\u5fc5\u987b\u662fSQL\u67e5\u8be2\u7684\u5217\u540d\u3002\n    </rule>\n    <rule>\n        **\u67f1\u72b6/\u6761\u5f62/\u6298\u7ebf\u56fe - \u6a21\u5f0f2 (\u957f\u6570\u636e) \u683c\u5f0f:**\n        {\"type\":\"column\", \"title\": \"\u56fe\u8868\u6807\u9898\", \"x_field\": \"X\u8f74\u5217\", \"y_field\": \"Y\u8f74\u6570\u503c\u5217\", \"series_field\": \"\u5206\u7ec4\u7ef4\u5ea6\u5217\", \"x_name\": \"X\u8f74\u4e2d\u6587\u540d\", \"y_name\": \"Y\u8f74\u4e2d\u6587\u540d\", \"series_name\": \"\u5206\u7ec4\u4e2d\u6587\u540d\"}\n        \"x_field\", \"y_field\", \"series_field\" \u5fc5\u987b\u662fSQL\u67e5\u8be2\u7684\u5217\u540d\u3002\n    </rule>\n    <rule>\n        \u5982\u679c\u65e0\u6cd5\u751f\u6210\u5408\u9002\u7684JSON\u914d\u7f6e\uff0c\u5219\u8fd4\u56de\uff1a{\"type\":\"error\", \"reason\": \"\u62b1\u6b49\uff0c\u6839\u636e\u63d0\u4f9b\u7684SQL\u548c\u95ee\u9898\uff0c\u6211\u65e0\u6cd5\u751f\u6210\u5408\u9002\u7684\u56fe\u8868\u914d\u7f6e\u3002\"}\n    </rule>\n</Rules>\n\n<examples>\n    ### \u4ee5\u4e0b\u793a\u4f8b\u5e2e\u52a9\u4f60\u7406\u89e3\u95ee\u9898\u53ca\u8fd4\u56de\u683c\u5f0f\uff0c\u4e0d\u8981\u5c06\u793a\u4f8b\u4e2d\u7684\u8868\u7ed3\u6784\u7528\u4e8e\u56de\u7b54\u3002\n    <example>\n        <input>\n            <sql>SELECT `u`.`name` AS `name`, `u`.`email` AS `email`, `u`.`create_time` AS `create_time` FROM `per_user` `u` LIMIT 10</sql>\n            <user-question>\u67e5\u8be210\u4e2a\u7528\u6237\u4fe1\u606f</user-question>\n            <chart_type></chart_type>\n        </input>\n        <output>\n            {\"type\":\"table\",\"title\":\"\u7528\u6237\u4fe1\u606f\",\"columns\":[{\"field\":\"name\",\"name\":\"\u59d3\u540d\"},{\"field\":\"email\",\"name\":\"\u90ae\u7bb1\"},{\"field\":\"create_time\",\"name\":\"\u521b\u5efa\u65f6\u95f4\"}]}\n        </output>\n    </example>\n    <example>\n        <input>\n            <sql>SELECT `o`.`name` AS `org_name`, COUNT(`u`.`id`) AS `user_count` FROM `per_user` `u` JOIN `per_org` `o` ON `u`.`default_oid` = `o`.`id` GROUP BY `o`.`name`</sql>\n            <user-question>\u997c\u56fe\u5c55\u793a\u5404\u4e2a\u7ec4\u7ec7\u7684\u4eba\u5458\u6570\u91cf\u5360\u6bd4</user-question>\n            <chart_type>pie</chart_type>\n        </input>\n        <output>\n            {\"type\":\"pie\",\"title\":\"\u5404\u7ec4\u7ec7\u4eba\u6570\u5360\u6bd4\",\"x_field\":\"org_name\",\"y_field\":\"user_count\",\"x_name\":\"\u7ec4\u7ec7\u540d\u79f0\",\"y_name\":\"\u4eba\u6570\"}\n        </output>\n    </example>\n    <example>\n        <input>\n            <sql>SELECT country, user_type, COUNT(*) AS user_count FROM users GROUP BY country, user_type</sql>\n            <user-question>\u6309\u56fd\u5bb6\u548c\u7528\u6237\u7c7b\u578b\u7edf\u8ba1\u7528\u6237\u6570</user-question>\n            <chart_type>column</chart_type>\n        </input>\n        <output>\n            {\"type\":\"column\",\"title\":\"\u5404\u56fd\u4e0d\u540c\u7c7b\u578b\u7528\u6237\u6570\",\"x_field\":\"country\",\"y_field\":\"user_count\",\"series_field\":\"user_type\",\"x_name\":\"\u56fd\u5bb6\",\"y_name\":\"\u7528\u6237\u6570\",\"series_name\":\"\u7528\u6237\u7c7b\u578b\"}\n        </output>\n    </example>\n    <example>\n        <input>\n            <sql>SELECT company_name, filled_count, unfilled_count FROM company_stats</sql>\n            <user-question>\u7edf\u8ba1\u5404\u516c\u53f87\u6708\u4efd\u7684\u586b\u62a5\u4eba\u6570\u548c\u672a\u586b\u62a5\u4eba\u6570</user-question>\n            <chart_type>column</chart_type>\n        </input>\n        <output>\n            {\"type\":\"column\", \"title\": \"\u5404\u516c\u53f87\u6708\u4efd\u586b\u62a5\u60c5\u51b5\", \"x_field\": \"company_name\", \"y_fields\": [\"filled_count\", \"unfilled_count\"], \"stack\": true, \"x_name\": \"\u516c\u53f8\u540d\u79f0\", \"y_name\": \"\u4eba\u6570\", \"series_names\": {\"filled_count\": \"\u5df2\u586b\u62a5\", \"unfilled_count\": \"\u672a\u586b\u62a5\"}}\n        </output>\n    </example>\n</examples>"
        }
      },
      "id": "420ac2a1-6755-492a-8249-167fb9f3a916",
      "name": "Charts Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 1.7,
      "position": [
        2816,
        576
      ],
      "executeOnce": false
    },
    {
      "parameters": {
        "options": {}
      },
      "id": "0c8971a6-ddd9-4a30-9243-b7cf1f2904cc",
      "name": "Loop Entry",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3,
      "position": [
        752,
        464
      ]
    },
    {
      "parameters": {
        "conditions": {
          "number": [
            {
              "value1": "={{$json.retryCount}}",
              "value2": "={{$json.maxRetries}}"
            }
          ]
        }
      },
      "id": "3bed25f2-3a4c-41b5-887d-638c5d7245f3",
      "name": "If Can Retry",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        2112,
        160
      ]
    },
    {
      "parameters": {
        "jsCode": " const prompt= $('Loop Entry').first().json;\n\n     prompt.retryCount= prompt.retryCount+1;       prompt.error_message+=\"\\n\\n\"+ JSON.stringify($input.all())+\"\\n\\n\";\n    return prompt;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1904,
        160
      ],
      "id": "3a30c27a-ad7d-4e30-a76b-d89845e09da0",
      "name": "Format Error Prompt"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "bcc7594e-b76b-4742-9944-1756090bcd5c",
              "leftValue": "={{ $json.message }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1808,
        416
      ],
      "id": "caa90f41-d000-4125-9998-ed22cabfc53f",
      "name": "If Error"
    },
    {
      "parameters": {
        "contextWindowLength": 1
      },
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "typeVersion": 1.3,
      "position": [
        -448,
        800
      ],
      "id": "aaa6fc4d-dbea-4314-b940-fb5ca70baf84",
      "name": "Search Memory"
    },
    {
      "parameters": {
        "jsCode": "// Accept both 'question' and 'query' for compatibility with SQLBot\nconst body = $json.body || {};\nconst query = (body.question ?? body.query ?? $json.question ?? $json.query ?? '').toString();\nconst sessionId= (body.sessionId ?? body.sessionId ?? $json.sessionId ?? $json.sessionId ?? '').toString();\nreturn [\n  {\n    json: {\n      userInput: query,\n      sessionId: sessionId    \n    }\n  }\n];"
      },
      "id": "c3d18f75-dd39-420d-a1b2-7c814d0ec768",
      "name": "Extract User Input",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -736,
        576
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT\n    c.table_schema,\n    c.table_name,\n    pd.description AS table_comment,\n    c.ordinal_position,\n    c.column_name,\n    (SELECT pg_catalog.col_description(pc.oid, c.ordinal_position::int)\n     FROM pg_catalog.pg_class pc\n     JOIN pg_catalog.pg_namespace pn ON pn.oid = pc.relnamespace\n     WHERE pn.nspname = c.table_schema AND pc.relname = c.table_name) AS column_comment,\n    c.data_type,\n    c.is_nullable,\n    tc.constraint_type,\n    ccu.table_name AS foreign_table_name,\n    ccu.column_name AS foreign_column_name\nFROM\n    information_schema.columns AS c\nLEFT JOIN pg_catalog.pg_class AS pgc\n    ON c.table_name = pgc.relname\nLEFT JOIN pg_catalog.pg_namespace AS pgn\n    ON pgc.relnamespace = pgn.oid\nLEFT JOIN pg_catalog.pg_description AS pd\n    ON pgc.oid = pd.objoid AND pd.objsubid = 0\nAND pgn.nspname = c.table_schema\nleft JOIN\n    information_schema.key_column_usage AS kcu\n    ON c.table_schema = kcu.table_schema AND c.table_name = kcu.table_name AND c.column_name = kcu.column_name\nLEFT JOIN\n    information_schema.table_constraints AS tc\n    ON kcu.constraint_name = tc.constraint_name AND kcu.table_schema = tc.table_schema\nLEFT JOIN\n    information_schema.referential_constraints AS rc\n    ON tc.constraint_name = rc.constraint_name\nLEFT JOIN\n    information_schema.constraint_column_usage AS ccu\n    ON rc.unique_constraint_name = ccu.constraint_name\nORDER BY\n    c.table_name,\n    c.ordinal_position;",
        "options": {}
      },
      "id": "bf692e0e-366f-43a2-94b7-239d6167e903",
      "name": "Get DB Schema",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        64,
        576
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "/**\n * @param {Array<Object>} items - SQL\u67e5\u8be2\u8282\u70b9\u8fd4\u56de\u7684\u5b8c\u6574\u9879\u76ee\u6570\u7ec4\u3002\u6bcf\u4e2a item \u5305\u542b\u4e00\u4e2a .json \u5c5e\u6027\uff0c\u8be5\u5c5e\u6027\u624d\u662f\u771f\u6b63\u7684\u6570\u636e\u5e93\u884c\u6570\u636e\u3002\n * @returns {string} - \u683c\u5f0f\u5316\u540e\u7684Markdown\u5b57\u7b26\u4e32\u3002\n */\nfunction transformSchemaToDDL(items) {\n  if (!items || items.length === 0) {\n    return '### No Schema Information Provided\\n';\n  }\n\n  // \u7b2c\u4e00\u6b65\uff1a\u5c06\u6241\u5e73\u6570\u636e\u6309\u8868\u540d\u5206\u7ec4\uff0c\u5e76\u786e\u4fdd\u5217\u7684\u552f\u4e00\u6027\n  const tables = {};\n  // \u5173\u952e\u4fee\u6b63\uff1a\u904d\u5386 items\uff0c\u5e76\u4ece item.json \u4e2d\u63d0\u53d6\u884c\u6570\u636e\n  for (const item of items) {\n    const row = item.json; // <-- \u8fd9\u91cc\u662f\u6838\u5fc3\u4fee\u6b63\u70b9\uff01\n\n    // \u5065\u58ee\u6027\u68c0\u67e5\uff1a\u5982\u679c\u67d0\u4e2aitem\u6ca1\u6709.json\uff0c\u5219\u8df3\u8fc7\n    if (!row) continue;\n\n    const tableName = row.table_name;\n    const columnName = row.column_name;\n\n    if (!tableName || !columnName) continue;\n\n    // \u5982\u679c\u662f\u65b0\u8868\uff0c\u5219\u521d\u59cb\u5316\n    if (!tables[tableName]) {\n      tables[tableName] = {\n        schema: row.table_schema,\n        comment: row.table_comment,\n        columns: {}, // \u4f7f\u7528\u5bf9\u8c61\u786e\u4fdd\u5217\u7684\u552f\u4e00\u6027\n        foreignKeys: []\n      };\n    }\n\n    // \u5982\u679c\u662f\u65b0\u5217\uff0c\u5219\u521b\u5efa\u5217\u7684\u5b9a\u4e49\n    if (!tables[tableName].columns[columnName]) {\n      tables[tableName].columns[columnName] = {\n        name: columnName,\n        type: row.data_type,\n        comment: row.column_comment,\n        isPk: false\n      };\n    }\n\n    // \u66f4\u65b0\u8be5\u5217\u7684\u7ea6\u675f\u4fe1\u606f\n    if (row.constraint_type === 'PRIMARY KEY') {\n      tables[tableName].columns[columnName].isPk = true;\n    }\n    \n    // \u8bb0\u5f55\u5916\u952e\u5173\u7cfb\uff08\u5e76\u53bb\u91cd\uff09\n    if (row.constraint_type === 'FOREIGN KEY') {\n      const fkExists = tables[tableName].foreignKeys.some(\n        fk => fk.column === columnName && fk.refTable === row.foreign_table_name\n      );\n      if (!fkExists) {\n        tables[tableName].foreignKeys.push({\n          column: columnName,\n          refTable: row.foreign_table_name,\n          refColumn: row.foreign_column_name\n        });\n      }\n    }\n  }\n  \n  // \u7528\u4e8e\u8f6c\u4e49SQL\u6ce8\u91ca\u4e2d\u7684\u5355\u5f15\u53f7\n  const escapeComment = (comment) => {\n    if (!comment) return '';\n    return ` COMMENT '${comment.replace(/'/g, \"''\")}'`;\n  };\n\n  // \u7b2c\u4e8c\u6b65\uff1a\u904d\u5386\u7ed3\u6784\u5316\u6570\u636e\uff0c\u751f\u6210DDL\u5b57\u7b26\u4e32\n  const ddlStrings = [];\n  for (const tableName in tables) {\n    const tableData = tables[tableName];\n    \n    let tableHeader = `-- Table: \"${tableData.schema}\".\"${tableName}\"`;\n    if (tableData.comment) {\n      tableHeader += ` (Comment: ${tableData.comment})`;\n    }\n\n    const createTableStart = `CREATE TABLE \"${tableData.schema}\".\"${tableName}\" (`;\n    \n    const definitions = [];\n\n    // \u904d\u5386\u5217\u5bf9\u8c61\n    for (const column of Object.values(tableData.columns)) {\n      let colLine = `  \"${column.name}\" ${column.type}`;\n      if (column.isPk) {\n        colLine += ' PRIMARY KEY';\n      }\n      colLine += escapeComment(column.comment);\n      definitions.push(colLine);\n    }\n    \n    // \u904d\u5386\u5916\u952e\n    for (const fk of tableData.foreignKeys) {\n      let fkLine = `  FOREIGN KEY (\"${fk.column}\") REFERENCES \"${tableData.schema}\".\"${fk.refTable}\"(\"${fk.refColumn}\")`;\n      definitions.push(fkLine);\n    }\n    \n    const createTableBody = definitions.join(',\\n');\n    const createTableEnd = ');';\n\n    const fullTableDDL = `${tableHeader}\\n${createTableStart}\\n${createTableBody}\\n${createTableEnd}`;\n    ddlStrings.push(fullTableDDL);\n  }\n\n  return ddlStrings.join('\\n\\n');\n}\n\n\n// \u8c03\u7528\u51fd\u6570\u8fdb\u884c\u8f6c\u6362\nconst schemaMarkdown = transformSchemaToDDL($input.all());\nreturn [{ json: { schema_markdown: schemaMarkdown,schema_name:$input.all()[0].json.table_schema } }];"
      },
      "id": "80e0c2c9-2fbe-46b5-8905-11e77b9785bb",
      "name": "Format Schema",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        288,
        576
      ]
    },
    {
      "parameters": {
        "jsCode": "//const schemaMarkdown = $input.item.json.schema_markdown;\nconst userInput = $('Extract User Input').first().json.userInput;\nconst sessionId = $('Extract User Input').first().json.sessionId;\nconst history= $('Format History').first().json.formattedHistory;\n\n\nconst outputItem = $input.item;\noutputItem.json.userInput = userInput;\noutputItem.json.sessionId= sessionId;\noutputItem.json.history= history;\noutputItem.json.current_time=new Date();\noutputItem.json.retryCount = 0;\noutputItem.json.maxRetries = 3;\noutputItem.json.error_message='';\nreturn outputItem;"
      },
      "id": "b081caba-f752-47ce-a8da-22b0dbc9bcd1",
      "name": "Prepare Initial Prompt",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        512,
        576
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "={{ $json.output.parseJson().sql }}",
        "options": {}
      },
      "id": "ddc73eae-3fa4-4352-a010-b2aa33fd288b",
      "name": "Execute Generated SQL",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        1600,
        432
      ],
      "alwaysOutputData": true,
      "executeOnce": false,
      "retryOnFail": false,
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {},
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "typeVersion": 1.3,
      "position": [
        1104,
        688
      ],
      "id": "ec708afd-1360-4084-9e35-d5205b866482",
      "name": "Insert Memory"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "955a825e-5f01-4019-a71b-05433daa0a24",
              "leftValue": "={{ $json.sql.parseJson().success}}",
              "rightValue": "false",
              "operator": {
                "type": "boolean",
                "operation": "false",
                "singleValue": true
              }
            },
            {
              "id": "bb72144b-aec1-4af6-a842-5d7be39200fa",
              "leftValue": "={{ $json.sql.parseJson()['chart_type']}}",
              "rightValue": "table",
              "operator": {
                "type": "string",
                "operation": "equals",
                "name": "filter.operator.equals"
              }
            }
          ],
          "combinator": "or"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        2656,
        336
      ],
      "id": "e48da06c-09b5-402d-946e-ad837655012e",
      "name": "If Charts"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "5fca89e7-a943-4292-8e49-fed0ff9bc202",
              "leftValue": "={{ $json.output.parseJson().success }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1344,
        512
      ],
      "id": "645d0667-9442-42f6-97f0-1dff6fda64e6",
      "name": "If Ai Error"
    },
    {
      "parameters": {
        "modelName": "models/gemini-2.5-pro",
        "options": {
          "temperature": 0.2
        }
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "typeVersion": 1,
      "position": [
        832,
        688
      ],
      "id": "6833e773-39ff-4531-bef2-facc4b248078",
      "name": "Google Gemini Chat Model",
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "AI Agent": {
      "main": [
        [
          {
            "node": "If Ai Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook": {
      "main": [
        [
          {
            "node": "Extract User Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Success Result": {
      "main": [
        [
          {
            "node": "If Charts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Chat Memory Manager": {
      "main": [
        [
          {
            "node": "Format History",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format History": {
      "main": [
        [
          {
            "node": "Get DB Schema",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "DeepSeek Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "DeepSeek Chat Model1": {
      "ai_languageModel": [
        [
          {
            "node": "Charts Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Format Charts": {
      "main": [
        [
          {
            "node": "Return Final Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Charts Agent": {
      "main": [
        [
          {
            "node": "Format Charts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Entry": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Can Retry": {
      "main": [
        [
          {
            "node": "Loop Entry",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Format Success Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Error Prompt": {
      "main": [
        [
          {
            "node": "If Can Retry",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Error": {
      "main": [
        [
          {
            "node": "Format Error Prompt",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Format Success Result",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Memory": {
      "ai_memory": [
        [
          {
            "node": "Chat Memory Manager",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Extract User Input": {
      "main": [
        [
          {
            "node": "Chat Memory Manager",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get DB Schema": {
      "main": [
        [
          {
            "node": "Format Schema",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Schema": {
      "main": [
        [
          {
            "node": "Prepare Initial Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Initial Prompt": {
      "main": [
        [
          {
            "node": "Loop Entry",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Execute Generated SQL": {
      "main": [
        [
          {
            "node": "If Error",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Insert Memory": {
      "ai_memory": [
        [
          {
            "node": "AI Agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "If Charts": {
      "main": [
        [
          {
            "node": "Format Charts",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Charts Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Ai Error": {
      "main": [
        [
          {
            "node": "Execute Generated SQL",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Format Charts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": true,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "6852d28d-17f3-44d5-b9d4-4bdadbee8b44",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "id": "TLCOG251r1ecPsmR",
  "tags": []
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

How this works

This workflow transforms natural language queries into SQL commands, enabling seamless interaction with your PostgreSQL database without requiring coding expertise. It's ideal for business analysts, data enthusiasts, or teams needing quick insights from databases, saving hours of manual query writing. The key step involves an AI agent powered by DeepSeek or Google Gemini models interpreting your question, generating precise SQL, executing it, and returning results via a webhook trigger.

Use this when you want to democratise database access for non-technical users through simple chat-like interfaces, such as querying sales data or inventory levels in real time. Avoid it for highly complex queries involving advanced joins or security-sensitive operations, where custom SQL might be safer. Common variations include swapping the chat model for OpenAI or adding email notifications for query results.

About this workflow

nl2sql. Uses stickyNote, agent, lmChatDeepSeek, respondToWebhook. Webhook trigger; 25 nodes.

Source: https://github.com/Tanishq60/n8n_nl2sql/blob/main/nl2sql.json — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

My workflow 3. Uses agent, memoryManager, memoryBufferWindow, postgres. Webhook trigger; 40 nodes.

Agent, Memory Manager, Memory Buffer Window +3
AI & RAG

主播招募智能体系统v2. Uses memoryBufferWindow, agent, lmChatDeepSeek, lmChatGoogleGemini. Webhook trigger; 25 nodes.

Memory Buffer Window, Agent, Lm Chat Deep Seek +1
AI & RAG

Are you drowning in daily operational chaos, desperately trying to juggle sales, projects, content, and client communication? Imagine an AI brain that handles it all, freeing you to lead your business

Telegram Trigger, Telegram, OpenAI +13
AI & RAG

CLINICAINTEGRAL_secretary. Uses postgres, mcpClientTool, googleDriveTool, toolWorkflow. Webhook trigger; 89 nodes.

Postgres, Mcp Client Tool, Google Drive Tool +14
AI & RAG

Bitlab-Chatbot. Uses telegramTrigger, telegram, snowflake, httpRequest. Event-driven trigger; 87 nodes.

Telegram Trigger, Telegram, Snowflake +13