AI kan skriva SQL snabbt. Men upprensningen när det blir fel är plågsamt långsam, särskilt när en ”snabb fråga” i det tysta skickar fel siffror in i en dashboard.
AI SQL-verifiering är en livräddare för dataanalytiker med tajta deadlines, men gör också vardagen enklare för teknikledare och drift/ops som är trötta på att bli pingade när mätetal ser ”fel” ut. Du får SQL som är testad innan den hamnar någonstans viktigt.
Det här arbetsflödet kör AI-genererad SQL i en säker Postgres-testmiljö, loopar igenom korrigeringar vid behov och håller rätt personer uppdaterade i Slack. Du får se vad det automatiserar, vad som förändras operativt och vad du behöver för att köra det.
Så fungerar den här automatiseringen
Hela n8n-flödet, från trigger till slutligt resultat:
n8n Workflow Template: Postgres + Slack: verifierad AI-SQL att lita på
flowchart LR
subgraph sg0["When chat message received Flow"]
direction LR
n0@{ icon: "mdi:play-circle", form: "rounded", label: "When chat message received", pos: "b", h: 48 }
n1["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>GenerateErrorPrompt"]
n2@{ icon: "mdi:memory", form: "rounded", label: "Simple Memory", pos: "b", h: 48 }
n3@{ icon: "mdi:swap-horizontal", form: "rounded", label: "AutoErrorFixing", pos: "b", h: 48 }
n4@{ icon: "mdi:swap-horizontal", form: "rounded", label: "IfError", pos: "b", h: 48 }
n5["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/postgres.svg' width='40' height='40' /></div><br/>Execute_AI_result"]
n6@{ icon: "mdi:swap-horizontal", form: "rounded", label: "isAssistantExists", pos: "b", h: 48 }
n7["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>isAssistantExistsCode"]
n8@{ icon: "mdi:swap-horizontal", form: "rounded", label: "isOpenAI", pos: "b", h: 48 }
n9@{ icon: "mdi:swap-vertical", form: "rounded", label: "assistant", pos: "b", h: 48 }
n10@{ icon: "mdi:swap-horizontal", form: "rounded", label: "IfOpenAI", pos: "b", h: 48 }
n11@{ icon: "mdi:swap-horizontal", form: "rounded", label: "IsMaxAutoErrorReached", pos: "b", h: 48 }
n12@{ icon: "mdi:brain", form: "rounded", label: "OpenRouter Chat Model", pos: "b", h: 48 }
n13@{ icon: "mdi:swap-vertical", form: "rounded", label: "AgentName", pos: "b", h: 48 }
n14@{ icon: "mdi:swap-vertical", form: "rounded", label: "setOutputByProvider", pos: "b", h: 48 }
n15@{ icon: "mdi:robot", form: "rounded", label: "OpenAIMainBrain", pos: "b", h: 48 }
n16@{ icon: "mdi:swap-vertical", form: "rounded", label: "askUserHowToHandleError", pos: "b", h: 48 }
n17@{ icon: "mdi:swap-vertical", form: "rounded", label: "maxAutoErrorLimitReached", pos: "b", h: 48 }
n18@{ icon: "mdi:swap-horizontal", form: "rounded", label: "If", pos: "b", h: 48 }
n19@{ icon: "mdi:swap-vertical", form: "rounded", label: "wordsForUser1", pos: "b", h: 48 }
n20@{ icon: "mdi:swap-horizontal", form: "rounded", label: "isExecutable", pos: "b", h: 48 }
n21@{ icon: "mdi:robot", form: "rounded", label: "getAssistantsList", pos: "b", h: 48 }
n22@{ icon: "mdi:robot", form: "rounded", label: "OpenRouterAgent", pos: "b", h: 48 }
n23@{ icon: "mdi:robot", form: "rounded", label: "createOpenAiAssistant", pos: "b", h: 48 }
n24@{ icon: "mdi:swap-vertical", form: "rounded", label: "localVariables", pos: "b", h: 48 }
n25@{ icon: "mdi:swap-vertical", form: "rounded", label: "executedSQLQuery", pos: "b", h: 48 }
n26@{ icon: "mdi:swap-vertical", form: "rounded", label: "issueOnOpenAiSide", pos: "b", h: 48 }
n27["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>mergeExecutionsResult"]
n28["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>collectErrorLoopDetails"]
n29@{ icon: "mdi:swap-vertical", form: "rounded", label: "setThreadId", pos: "b", h: 48 }
n30["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>collectErrorLoopDetails1"]
n31["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/mysql.dark.svg' width='40' height='40' /></div><br/>Execute a SQL query"]
n32@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Switch", pos: "b", h: 48 }
n18 --> n7
n18 --> n26
n32 --> n5
n32 --> n31
n4 --> n3
n4 --> n32
n10 --> n13
n10 --> n22
n8 --> n15
n8 --> n22
n13 --> n21
n9 --> n15
n29 --> n20
n20 --> n14
n20 --> n19
n2 -.-> n22
n24 --> n10
n3 --> n11
n3 --> n16
n15 --> n29
n22 --> n20
n5 --> n27
n5 --> n1
n21 --> n18
n6 --> n9
n6 --> n23
n31 --> n27
n31 --> n1
n1 --> n8
n14 --> n4
n11 --> n30
n11 --> n32
n12 -.-> n22
n23 --> n9
n7 --> n6
n27 --> n28
n28 --> n25
n30 --> n17
n0 --> n24
end
%% Styling
classDef trigger fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
classDef ai fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
classDef aiModel fill:#e8eaf6,stroke:#3f51b5,stroke-width:2px
classDef decision fill:#fff8e1,stroke:#f9a825,stroke-width:2px
classDef database fill:#fce4ec,stroke:#c2185b,stroke-width:2px
classDef api fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef code fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef disabled stroke-dasharray: 5 5,opacity: 0.5
class n0 trigger
class n15,n21,n22,n23 ai
class n12 aiModel
class n2 ai
class n3,n4,n6,n8,n10,n11,n18,n20,n32 decision
class n5,n31 database
class n1,n7,n27,n28,n30 code
classDef customIcon fill:none,stroke:none
class n1,n5,n7,n27,n28,n30,n31 customIcon
Problemet: AI-SQL som bryter förtroende (och dashboards)
Om du någon gång har klistrat in AI-skriven SQL i en SQL-editor och tryckt på Kör med fingrarna i kors, så känner du redan till den verkliga kostnaden. Det handlar inte bara om syntaxfel. Det är logikfel som fortfarande returnerar ”rimligt” utseende rader, fel join som dubblar antal, eller ett datumfilter som i det tysta exkluderar halva veckan. Sedan jagar du det hela eftermiddagen: läser om schemaanteckningar, justerar frågor, kör igen och förklarar för någon i Slack varför gårdagens rapport ändrades. Den mentala belastningen är värst, för du känner dig aldrig säker på att du är klar.
Det blir snabbt mycket. Här är var det fallerar.
- Testning sker för sent, så trasig SQL når dashboards innan någon märker det.
- Folk kopierar och klistrar frågor mellan verktyg, vilket bjuder in små misstag och stora missförstånd.
- När fel väl händer stjäl ”debug-loopen” ungefär en timme åt gången och avbryter allas arbete.
- Utan en standardiserad verifieringsväg slutar team lita på siffrorna och börjar dubbelkolla allt manuellt.
Lösningen: testa AI-SQL i Postgres och rapportera sedan till Slack
Det här arbetsflödet gör om ”AI skrev lite SQL” till ”AI skrev SQL som klarade en riktig testkörning”. Det startar när en chatförfrågan når ditt n8n-flöde (samma logik kan byggas in i en webbchatt eller triggas från ert interna verktyg). Flödet lagrar inkommande kontext (som session ID, leverantör, modell, schemasample-data), ber en AI-agent generera SQL och kör sedan den SQL:en mot en testdatabas via Postgres. Om frågan misslyckas eller returnerar något oväntat bygger flödet en hjälpsam felprompt, skickar den tillbaka till AI:t och försöker igen. Om du aktiverar auto-fix loopar det igenom korrigeringar självt upp till en säker gräns så att det inte fastnar för alltid.
Arbetsflödet börjar med en inkommande chat-trigger och mappar förfrågan till ”lokala variabler” för konsekvent hantering. Sedan routar det till rätt modellspår (OpenAI-hanterad chathistorik eller OpenRouter med lokalt minne), kör den genererade SQL:en i Postgres och svarar till sist med verifierat resultat plus detaljer om vad som hände under körningen.
Det här får du: automatisering vs. resultat
| Vad det här arbetsflödet automatiserar | Resultat du får |
|---|---|
|
|
Exempel: så här ser det ut
Säg att ditt team skapar 10 nya eller reviderade frågor under en vecka för dashboards och ad hoc-analys. Manuellt är det vanligt att lägga cirka 20 minuter per fråga på att generera, klistra in, köra, fixa och köra igen (alltså ungefär 3 timmar per vecka). Med det här flödet skickar du prompten en gång, väntar en minut på agenten och testkörningen och får sedan ett verifierat resultat eller ett tydligt fel med ett föreslaget fix. I praktiken brukar det göra om ”20 minuter fram och tillbaka” till cirka 5 minuters granskning.
Det här behöver du
- n8n-instans (prova n8n Cloud gratis)
- Alternativ för self-hosting om du föredrar det (Hostinger fungerar bra)
- PostgreSQL för säker testkörning av SQL
- Slack för att notifiera teamet vid fel/fixar
- OpenAI- eller OpenRouter-API-nyckel (hämtas i leverantörens dashboard)
Kunskapsnivå: Medel. Du kopplar in autentiseringsuppgifter, matar in schema/sample-data och är bekväm med att definiera vad ”verifierad” ska betyda för ditt use case.
Vill du inte sätta upp det här själv? Prata med en automatiseringsexpert (gratis 15-minuters konsultation).
Så fungerar det
En chatförfrågan triggar körningen. En webhook-liknande chat-trigger tar emot din prompt plus kontext som sessionId, val av leverantör, modell och auto-fix-preferens.
Kontext normaliseras och routas. Flödet mappar input till ett objekt med lokala variabler och använder sedan villkorslogik för att routa till OpenAI (assistant/thread-hantering) eller OpenRouter (lokalt minne via ett bufferfönster).
AI genererar SQL och Postgres kör den. Agenten producerar körbar utdata och flödet kör den mot din Postgres-testdatabas. Om du använder en annan databas finns det också en database switch i flödesstrukturen för att stödja alternativa körvägar.
Fel triggar en kontrollerad fix-loop och ett tydligt svar. När körningen misslyckas bygger flödet en felprompt, avgör om det ska auto-fixa eller be om tillstånd och försöker igen tills det lyckas eller når maxgränsen för loopen. Slutsvaret innehåller körningsdetaljer så att du kan lita på vad som hände.
Du kan enkelt ändra databasmålet (Postgres vs MySQL) för att matcha din miljö utifrån dina behov. Se den fullständiga implementationsguiden nedan för anpassningsalternativ.
Steg-för-steg-guide för implementering
Steg 1: konfigurera webhook-triggern
Det här arbetsflödet startar med en inkommande chatt-webhook som tar emot användarprompter och sessionsdata.
- Lägg till och öppna Incoming Chat Trigger.
- Ställ in Mode på
webhook. - Aktivera Public till
trueså att externa klienter kan anropa triggern. - Kopiera webhook-URL:en som genereras av Incoming Chat Trigger för er integration med chattklienten.
Steg 2: mappa indata från request och sätt databasroutning
Mappa lokala variabler och avgör vilken databasmotor som ska köras mot.
- Öppna Map Local Variables och behåll Include Other Fields aktiverat.
- Säkerställ att den långa tilldelningen av instruction förblir intakt (den använder dynamiska platshållare som
{{$json['selectedDatabaseType']}}och en villkorsstyrd citeringsregel för PostgreSQL jämfört med MySQL). - Öppna OpenAI Route Check och bekräfta att den utvärderar att
{{$json.aiProvider}}är lika medopenai. - Öppna Database Switch och bekräfta reglerna:
{{$('Map Local Variables').last().json.selectedDatabaseType}}är lika medpostgresqlför PostgreSQL, och är lika medmysqlför MySQL.
selectedDatabaseType, aiProvider, model, sessionId och chatInput i inkommande data.Steg 3: konfigurera identifiering och skapande av OpenAI-assistent
Den här sektionen bygger ett assistentnamn, listar assistenter och skapar en vid behov.
- Öppna Build Agent Name och sätt uttrycket för agentName till
{{$('Map Local Variables').last().json.selectedDatabaseType + '_AiDoubleCheck_' + $('Map Local Variables').last().json.model}}. - Öppna Retrieve Assistants och behåll Resource som
assistantoch Operation somlist. Credential Required: anslut era openAiApi-uppgifter. - Öppna OpenAI Error Gate för att säkerställa att den kontrollerar att
{{$json.error}}inte finns innan den fortsätter. - Öppna Check Assistant List och bekräfta att JS-koden jämför namn från Retrieve Assistants med utdata från Build Agent Name.
- Öppna Create OpenAI Assistant, sätt Name till
{{$('Build Agent Name').last().json.agentName}}och behåll Operation somcreate. Credential Required: anslut era openAiApi-uppgifter. - Öppna Set Assistant Id och bekräfta att den mappar id till
{{$json.id}}.
Steg 4: konfigurera LLM-bearbetning och minne
Arbetsflödet routar mellan OpenAI och OpenRouter, med minnes- och trådhantering.
- Öppna OpenAI Core Brain och bekräfta att Text använder uttrycket med flera grenar (felläge vs normalläge) och att Thread ID använder
{{$ifEmpty($('Map Local Variables').last().json.threadId, null)}}när den inte är i felläge. Credential Required: anslut era openAiApi-uppgifter. - Öppna Provider Is OpenAI och verifiera att den kontrollerar att
{{$('Map Local Variables').last().json.aiProvider}}är lika medopenai. - Öppna OpenRouter Agent och behåll Text i linje med samma uttryck för fel-/normalprompt som används i OpenAI Core Brain.
- Öppna Router Chat Model och anslut den som språkmodell för OpenRouter Agent. Credential Required: anslut era OpenRouter-uppgifter (lmChatOpenRouter). Detta är den överordnade modellnoden—lägg inte till credentials i OpenRouter Agent själv.
- Öppna Buffer Memory Store och sätt Session Key till
{{$('Map Local Variables').last().json.sessionId}}och Context Window Length till7. Lägg till detta minne till OpenRouter Agent.
Steg 5: konfigurera SQL-exekvering och val av utdata
Genererad SQL körs på vald databas och utdata normaliseras.
- Öppna Run AI SQL (Postgres) och sätt Query till
{{ $json.output }}med Operation somexecuteQuery. Credential Required: anslut era postgres-uppgifter. - Öppna Run SQL (MySQL) och sätt Query till
{{ $json.output }}med Operation somexecuteQuery. Credential Required: anslut era mySql-uppgifter. - Öppna Executable Output Check och verifiera att den exkluderar utdata som innehåller
words_for_user. - Öppna Select Provider Output och sätt output till
{{$if ( $('Map Local Variables').last().json.aiProvider === 'openai', $('OpenAI Core Brain').last().json.output, $('OpenRouter Agent').last().json.output )}}.
Steg 6: konfigurera fel-loopning och auto-fix-logik
Felutdata detekteras, omvandlas till prompter och loopas för automatisk fix upp till en gräns.
- Öppna Compose Error Prompt och behåll den medföljande JS-koden som bygger en prompt med antingen auto-fix- eller användarvägledande formulering.
- Öppna Error Presence Check och säkerställ att den kontrollerar att
{{$('Compose Error Prompt').isExecuted}}är lika medtrue. - Öppna Auto Fix Decision och verifiera att den kontrollerar att
{{$('Map Local Variables').last().json.autoErrorFixing}}är lika medtrue. - Öppna Auto Fix Limit Check och bekräfta att den använder
{{$node['Compose Error Prompt'].runIndex}}större än eller lika med4som gräns. - Öppna Collect Loop Info 2 och Collect Error Loop Info och behåll JS-koden som sammanställer fel-loophistoriken.
- Öppna Auto Fix Limit Reached och säkerställ att fälten mappas från Select Provider Output och Collect Loop Info 2.
Steg 7: konfigurera slutliga svarsutdata
Svara med SQL-resultat, användarmeddelanden eller auto-fix-status beroende på gren.
- Öppna Executed SQL Result och mappa query till
{{$('Select Provider Output').last().json.output}}och executionResult till{{$('Merge Execution Results').last().json.mergedExecutionsResult}}. - Öppna User Message Reply och sätt type till
wordsForUseroch message till{{$json.output}}. - Öppna Request User Error Action för att mappa type som
autoErrorFixingFalseoch inkludera{{$('Run AI SQL (Postgres)').last().json.message}}för felmeddelandet. - Behåll JS-koden i Merge Execution Results intakt för att aggregera svar från noderna som exekverar databasen.
Steg 8: testa och aktivera ert arbetsflöde
Validera hela loopen från request till response innan ni använder den i produktion.
- Klicka på Execute Workflow och skicka en test-payload till Incoming Chat Trigger med
selectedDatabaseType,aiProviderochchatInput. - Bekräfta flödet: Incoming Chat Trigger → Map Local Variables → OpenAI Route Check → LLM-nod → Select Provider Output → Error Presence Check → Database Switch.
- Verifiera att lyckade körningar avslutas vid Executed SQL Result med type satt till
successoch ifylld executionResult. - Om fel uppstår, verifiera att Compose Error Prompt körs och att auto-fix-loopen avslutas vid Auto Fix Limit Reached när gränsen nås.
- När allt är validerat, växla arbetsflödet till Active för användning i produktion.
Vanliga fallgropar
- OpenAI- eller OpenRouter-autentiseringsuppgifter kan löpa ut eller kräva specifika behörigheter. Om saker slutar fungera, kolla först leverantörens dashboard och n8n:s credential-test.
- Om du använder Wait-noder eller extern rendering varierar processtiderna. Öka väntetiden om noder längre ned i flödet fallerar på tomma svar.
- Postgres-körningar kan fallera av skäl som ”inte är SQL”, som saknade tabeller i testschemat. Bekräfta att flödet tar emot currentDbSchemaWithData (även exempelrader), annars kommer agenten att gissa och fortsätta gissa.
Vanliga frågor
Cirka en timme om din Postgres-testdatabas och API-nyckel är redo.
Nej. Du kommer främst att koppla in autentiseringsuppgifter och klistra in ditt schema/sample-data.
Ja. n8n har ett gratis self-hosted-alternativ och en gratis provperiod på n8n Cloud. Cloud-planer börjar på 20 USD/månad för högre volym. Du behöver också räkna in kostnader för OpenAI- eller OpenRouter-API-användning, som beror på modell och promptstorlek.
Två alternativ: n8n Cloud (hanterat, enklast att komma igång) eller self-hosting på en VPS. För self-hosting är Hostinger VPS prisvärd och hanterar n8n bra. Self-hosting ger obegränsade körningar men kräver grundläggande serveradministration.
Ja, men testa noggrant. Det här flödet innehåller redan en Database Switch och en väg för ”Run SQL (MySQL)”, så du kan routa körningen bort från Postgres när din förfrågan kräver det. Vanliga anpassningar är att byta körningsnod, justera felprompten så att den refererar till MySQL-syntax och strama åt gränsen för ”max auto-fix” av säkerhetsskäl.
Oftast handlar det om autentiseringsuppgifter eller nätverksåtkomst till testdatabasen. Bekräfta att Postgres-användaren kan ansluta från din n8n-instans och verifiera sedan att databasnamn och schema finns i testmiljön. Om den ansluter men frågor fallerar kan ditt schema/sample-JSON inte matcha det som faktiskt finns i databasen, så agenten genererar SQL för tabeller som inte finns. Kolla även rate limits eller leverantörsfel om AI-steget aldrig returnerar körbar SQL.
Om du kör n8n self-hosted finns ingen körningsbegränsning (det beror främst på din server och databas). I n8n Cloud beror din månatliga körningskvot på din plan, så team med hög volym går normalt upp en nivå. I praktiken är flödet designat för att hantera en chatförfrågan per körning, och auto-fix-loopen kan lägga till några extra varv när fel uppstår.
Ofta, ja. n8n är helt enkelt byggt för flöden som detta där du behöver förgreningslogik, loopar med gränser och beteendet ”kör, kontrollera, fixa, försök igen”. Zapier och Make kan fungera för enkel routing och notifieringar, men blir klumpiga när du hanterar konversationskontext (thread IDs), retry-gates och databaskörning i ett och samma flöde. Self-hosting-alternativet spelar också roll, eftersom tung användning kan bli dyrt med prissättning per task. Om du är osäker, prata med en automatiseringsexpert och beskriv ert nuvarande query-flöde.
Verifierad SQL förändrar läget: färre brandkårsutryckningar, färre ”kan någon dubbelkolla det här” och mer trygghet i siffrorna. Sätt upp det en gång och låt sedan arbetsflödet hantera den repetitiva osäkerheten.
Kontakta oss
Hör av dig, så diskuterar vi hur just din verksamhet kan dra nytta av alla fantastiska möjligheter som AI skapar.