AI & automation

Så använder jag Claude Code för att skriva SQL mot riktiga produktionsdata

Det är lätt att bli imponerad första gången en coding agent skriver en SQL-query från en mening som "visa bokningar per station jämfört med förra året". Det är också precis där man kan göra sig illa. SQL mot verkliga verksamhetsdata är inte ett autocomplete-problem.

Shadip Rahman 15 september 2026 16 min läsning
Dela
Flöde i artikelns ordning: En SQL-query är ofta bara sista steget, Jag ger agenten en datakarta, inte hela databasen, Affärsregler som kodbar specifikation, Jag separerar query-generation från query-godkännande.

Det är lätt att bli imponerad första gången en coding agent skriver en SQL-query från en mening som "visa bokningar per station jämfört med förra året". Det är också precis där man kan göra sig illa. SQL mot verkliga verksamhetsdata är inte ett autocomplete-problem. Det är en kombination av datamodell, affärsdefinitioner, tidslogik, datakvalitet och säkerhet.

Jag använder Claude Code mycket för SQL, men inte som en fristående analytiker som får titta på en databas och "hitta insikter". Jag försöker i stället göra den till en snabb implementatör av regler som redan är explicita. Ju mer exakt jag beskriver tabeller, joins, mätetal och valideringar, desto bättre blir den. Och när jag inte kan beskriva dem är problemet nästan alltid större än prompten.

En SQL-query är ofta bara sista steget

Ta en till synes enkel affärsfråga: "Hur många bokningar fick vi per dag?" Det kan kräva svar på frågor som:

  • räknar vi bokningshuvuden eller rader?
  • ska avbokningar bort?
  • vilken skapandetid gäller?
  • vilken tidszon använder vi?
  • vilka fordonsvikter ingår?
  • ska moms tas bort i intäkten?
  • jämför vi kalenderdatum eller veckodag mot veckodag?

Om jag skickar bara den svenska frågan till Claude kan jag få syntaktiskt korrekt SQL som svarar på fel fråga. Det farliga är att resultatet fortfarande ser professionellt ut. Därför har jag börjat behandla affärsregler som ett separat lager före SQL:n.

När det står så blir SQL-generation nästan mekanisk. Det är bra.

Jag ger agenten en datakarta, inte hela databasen

I en produktionsmiljö finns ofta tabeller med namn som är begripliga först efter flera års historik. Jag arbetar bland annat med externa tabeller, temporära speglingar, bokningslager, station master-data, produktdata och prissättning. Om modellen måste inferera relationerna från namn kommer den ibland träffa rätt och ibland skapa en join som ser rimlig ut men multiplicerar rader. Jag försöker därför hålla en kompakt datakatalog:

Detta behöver inte vara ett enterprise data catalog-projekt. En välskriven markdownfil kan räcka långt. Poängen är att Claude ska kunna läsa den innan den skriver queryn. Anthropic rekommenderar i sin aktuella prompting-guidance samma grundbeteende för agentiskt kodarbete: undersök relevanta filer och faktisk kod innan du spekulerar, och använd strukturerade format för state och krav. För SQL är det ännu viktigare eftersom ett felaktigt antagande kan ge ett trovärdigt men felaktigt resultat.

Affärsregler som kodbar specifikation

Ett av mina vanligaste användningsfall är prissättning. Där kan reglerna vara betydligt mer specifika än "höj priset med 90 kronor". Exempelvis kan olika produkter ha olika beroenden, vissa stationer ha tak, vissa tidslottskategorier hanteras annorlunda och slutpriset avrundas enligt en definierad regel. Jag skriver hellre:

än:

"Kan du fixa priserna enligt samma logik som tidigare?"

Skillnaden är inte bara att Claude får mer kontext. Jag får en artefakt som kan granskas av en människa före implementation.

Jag separerar query-generation från query-godkännande

För läsande analys kan Claude få skriva SQL ganska fritt i en lokal fil. Men jag vill ha ett tydligt steg mellan "query genererad" och "query körs mot produktion". Min mentala modell är:

Det som saknas i många AI-SQL-demos är de två sista stegen. En query kan köras utan syntaxfel och ändå vara logiskt fel. Jag validerar därför resultatet mot något jag känner till. Om en dagsbokning normalt ligger i ett visst storleksintervall och queryn visar tio gånger mer är det en signal. Om en join plötsligt ger flera rader per station där jag väntar mig en är det en signal. Om summan före och efter en dimensionsjoin ändras utan skäl är det en mycket stark signal.

Grain är den vanligaste dolda buggen

När AI skriver analytisk SQL är grain-problem värda en egen kontroll. Anta att en bokning har flera rader och jag joinar den mot en tabell med ytterligare flera matchningar. COUNT(*) och SUM(Price) kan explodera utan att något SQL-fel uppstår. Jag vill därför att queryn uttryckligen dokumenterar grain i kommentar eller CTE-namn:

Sedan lägger jag gärna en diagnostisk kontroll:

Det är inte alltid rätt kontroll, men principen är bra: gör queryns antaganden testbara.

Tidsjämförelser kräver affärsförståelse

Ett annat område där generisk SQL blir missvisande är YoY och trend. Om bokningsmönstret skiljer mycket mellan måndag och lördag kan "31 augusti mot 31 augusti" vara en dålig jämförelse när veckodagarna skiljer sig mellan åren. I analyser efter en prisförändring har jag därför velat se bland annat:

  • daglig stationsnivå,
  • veckodag mot samma veckodag,
  • YoY,
  • MoM där det är meningsfullt,
  • trend före och efter förändringsdatum,
  • säsongseffekt,
  • skillnad mellan pris- och volymeffekt.

Claude kan hjälpa mig skriva queryn snabbt, men den kan inte själv bestämma vilken jämförelse som är affärsmässigt korrekt utan kontext. Det är analytikerns jobb.

Prisanalys är ett eget systemproblem, inte en fråga om bättre SQL

Prissättning är det tydligaste exemplet på varför en query aldrig kan stå för sig själv. Innan en enda rad SQL skrivs måste jag ha bestämt vad "effekt" faktiskt betyder: mäter jag volym, intäkt, bokningsvärde, nyttjande eller marknadsandel? Samma prisförändring kan se bra och dålig ut samtidigt beroende på vilket av dem jag väljer.

Nästa steg är att skilja på förändring och orsak. En nedgång efter ett prislyft är inte automatiskt en priseffekt förrän jag har justerat för veckodag, säsong, marknad, station och andra samtidiga förändringar. Marginalen avgör dessutom hur mycket volymtapp som är acceptabelt: är marginalkostnaden låg kan en prisökning tåla ett visst tapp och ändå ge högre intäkt, men det antagandet och den formeln måste vara explicita, inte underförstådda.

Genomsnitt är den vanligaste fällan i den här typen av analys. De döljer att enskilda stationer kan reagera helt olika, så jag vill se distributionen och identifiera vilka stationer som driver totalen innan jag drar en generell slutsats. Och oavsett hur analysen presenteras kräver jag att den går att spåra tillbaka till query, perioddefinition och metric-kontrakt. En slutsats jag inte kan visa dataväg för är inte klar, hur välformulerad den än är.

Externa tabeller och "små" databasproblem

Verkliga databaser innehåller också saker som sällan syns i demos. Ett exempel är collation-konflikter mellan en extern tabell och den lokala databasen. En join på två textfält kan då fallera trots att värdena ser identiska ut. När jag beskriver problemet för Claude vill jag inte bara ha en snabb COLLATE inklistrad överallt. Jag vill först förstå:

  1. vilka kolumner har olika collation?
  2. är jämförelsen nödvändig på text?
  3. kan joinen göras på stabil ID i stället?
  4. om COLLATE krävs, var ska den appliceras minst invasivt?

Det är ett exempel på hur agenten kan vara en bra felsökningspartner när den får läsa faktisk schema- och felinformation, men en dålig gissare när den bara får ett felmeddelande utan kontext.

Jag låter aldrig modellen hitta på kolumner

En enkel regel har sparat mycket tid: om en kolumn inte är verifierad i schema eller tidigare query får Claude inte anta att den finns. Det låter självklart, men hallucinerade kolumnnamn är ett naturligt resultat när modellen försöker vara hjälpsam. Ett namn som StationName, IsDynamic eller Gender kan vara semantiskt rimligt och ändå saknas i just den tabellen eller miljön.

Jag använder därför instruktionen i praktiken:

Det ligger nära Anthropic-guiden för coding agents: läs relevant material innan du gör claims om kodbasen.

Read-only är standard för AI-assisterad analys

En annan gräns är permissions. För analys behöver agenten nästan aldrig UPDATE, DELETE, ALTER eller DROP. Om jag kan ge read-only access är det standard. Det handlar inte om att modellen "kommer vilja förstöra databasen". Det handlar om blast radius. En coding agent kan missförstå en instruktion eller använda ett destruktivt kommando som genväg. Anthropic rekommenderar uttryckligen att skilja på lokala/reversibla handlingar och sådant som är destruktivt, svårt att backa eller påverkar delade system.

För mig betyder det:

  • SQL genereras i fil först,
  • produktionsaccess är read-only för analys,
  • writes kräver separat workflow,
  • förändringar testas på begränsat urval,
  • destruktiva kommandon ligger utanför agentens normala behörighet.

Det ger bättre tempo, inte sämre. Jag kan låta agenten arbeta mer självständigt när konsekvensen av ett misstag är begränsad.

Ett praktiskt promptmönster jag använder

Jag ger hellre en agent ett litet kontrakt än en lång berättelse:

Det mönstret gör också review enklare. Jag kan kontrollera definitionerna utan att först läsa 100 rader SQL.

Claude är bäst när den får jobba nära artefakterna

Det som har gjort Claude Code mest användbart för mig är inte att modellen "kan SQL". Många modeller kan SQL. Det är att den kan arbeta i samma projekt som schemafiler, tidigare queries, business rules och tester. När en regel ändras kan jag uppdatera en referensfil och be agenten kontrollera vilka queries som påverkas. När en query ger fel kan den läsa både filen och relevant schema. När vi återanvänder en metrisk definition kan den ligga versionerad i repo:t.

Det flyttar arbetet från konversation till system.

När jag fortfarande skriver SQL själv

Jag använder inte agenten för allt. Vid särskilt känsliga analyser, ovanliga performance-problem eller query-plan-optimering vill jag ofta styra mer manuellt. Samma sak gäller när datamodellen är dåligt dokumenterad. Då är den snabbaste vägen ibland att själv utforska tabellerna och först därefter ge agenten en stabil karta. Jag är också försiktig när en fråga kräver kausal tolkning. SQL kan visa korrelation och förändringar. Det betyder inte automatiskt att prisförändringen, kampanjen eller en viss kanal orsakade dem.

AI:n kan hjälpa med beräkningen. Den ska inte smyga in kausalitet i analysen.

Min QA-checklista före jag litar på resultatet

Jag använder ungefär följande kontroll:

  • Är grain explicit?
  • Är alla tabeller och kolumner verifierade?
  • Finns någon many-to-many-join?
  • Ändras totalsummor efter dimensionsjoins?
  • Är tidszonen och datumfältet rätt?
  • Matchar filter affärsdefinitionen?
  • Är null-värden hanterade medvetet?
  • Finns DISTINCT som döljer ett joinproblem?
  • Har queryn testats på ett känt intervall?
  • Är resultatet rimligt mot en oberoende kontroll?

Detta är mer värdefullt än att försöka hitta den perfekta prompten för SQL.

Min viktigaste regel: AI ska minska implementationstid, inte äga definitionen

När det fungerar som bäst gör Claude Code mig snabbare från en tydlig affärsregel till testbar SQL. Den skriver boilerplate, bygger CTE:er, hjälper mig felsöka och kan hålla många schema-detaljer i arbetskontext. Men jag vill inte outsourca definitionerna. "Bokning", "intäkt", "kapacitet", "baspris", "lågt pris" och "YoY" är verksamhetsbegrepp innan de är kolumner. Det är därför mitt arbetssätt har blivit nästan omvänt jämfört med tidig AI-användning. Jag lägger mer energi på kontexten runt queryn och mindre på själva promptformuleringen. Resultatet blir paradoxalt nog mer automation, eftersom en agent som arbetar mot stabila kontrakt kan få större frihet utan att gissa vad företaget menar.

Jag låter Claude generera tester tillsammans med queryn

En av de bästa förbättringarna är att kräva validation SQL i samma leverans som huvudqueryn. Det tvingar modellen att tänka på vilka antaganden som går att falsifiera. Om huvudqueryn räknar bokningar per station kan valideringspaketet innehålla:

För en prisquery kan jag kontrollera constraints:

eller takregler, avrundning och relationer mellan produkter. Detta är mycket mer robust än att be Claude "dubbelkolla queryn". Dubbelkoll blir då konkret SQL som jag själv kan köra.

Golden queries är mina regressionstester

När jag har en metrisk definition som återkommer vill jag behålla en liten query med känt resultat eller åtminstone kända egenskaper. Det blir motsvarigheten till golden dataset för analytics. Exempel:

Jag behöver inte hårdkoda alla affärstal för evigt. Men några kontroller gör att en framtida ändring i schema eller join inte passerar bara för att SQL:n fortfarande körs. Det här är extra viktigt när AI:n får refaktorera gamla queries. Den kan göra koden snyggare och samtidigt subtilt ändra resultatet. Då ska testet vinna över estetiken.

Queryplan och prestanda är en separat review

En korrekt query kan fortfarande vara olämplig i produktion. Om agenten skapar en enorm cross join, använder funktioner på indexerade joinnycklar eller skannar mycket mer data än nödvändigt behöver jag en performance-review. Jag skiljer därför på två frågor:

  1. Returnerar queryn rätt data?
  2. Returnerar den datan på ett rimligt sätt?

Claude kan hjälpa till att läsa execution plan och föreslå index eller omstrukturering, men jag vill inte att den lägger index i produktion automatiskt. Ett index är inte "gratis prestanda"; det påverkar writes, lagring och maintenance. För större queries kan promptkontraktet därför kräva:

Jag använder CTE:er som kommunikationslager

CTE:er är inte alltid optimala av alla performance-skäl, men de är ofta bra för AI-assisted analytics eftersom de kan spegla affärslogik steg för steg.

Det blir enklare att reviewa än en monolitisk query med fem nested subqueries. Jag kan säga "felet finns i eligible_bookings" och Claude kan arbeta lokalt. Jag försöker namnge CTE:er efter semantik, inte teknik. t1, t2, cte3 sparar några tecken men förstör kontexten som agenten behöver.

Jag dokumenterar business rules nära koden

Ett problem med analytisk SQL är att samma definition kan finnas i flera dashboards och ad hoc-frågor. Om jag bara lär Claude regeln i en konversation försvinner kunskapen efter sessionen. Jag föredrar filer som:

bookings.md kan innehålla definition, grain, filters, owner och ändringshistorik. SQL-filen refererar till metric-kontraktet. Då får jag samma fördel som med Skills: återanvändbar, versionerad kontext i stället för promptminne.

AI kan hjälpa mig upptäcka motsägelser mellan regler

När business rules blir många kan Claude också göra något annat än att skriva SQL: jämföra dem. Anta att en fil säger:

och en annan senare regel säger att ett särskilt stationstak kan göra 1008 lägre. Då vill jag att agenten flaggar konfliktrisken innan queryn byggs. Samma sak med datum. En prisregel kan gälla från 1 september medan analysen hämtar priser från 26 augusti. SQL:n kan vara korrekt för fel regelversion. Det gör rule versioning viktigt:

Det är en typ av kontext som en coding agent kan använda mycket bra om den är strukturerad.

Jag skiljer observation från rekommendation i output

Efter SQL-körningen vill jag inte att agenten automatiskt går från "volym -12 %" till "sänk priset". Analysoutputen kan separeras:

Det minskar risken att en statistisk förändring blir ett beslut utan mellanled. För prissättning är detta särskilt viktigt. Om marknaden samtidigt blir svagare behöver modellen kunna hålla flera hypoteser öppna.

Privacy och data-minimering gäller även coding agents

När Claude Code används nära produktionsdata vill jag också minimera vad som hamnar i promptkontext. Agenten behöver ofta schema och aggregerade resultat, inte kunders personuppgifter. Jag försöker därför arbeta med:

  • schemafiler i stället för rå kunddata,
  • sampling som är anonymiserad när exempel behövs,
  • aggregerade outputs,
  • secrets utanför prompts,
  • tydlig separation mellan kodrepo och dataåtkomst.

Det är lätt att tänka "jag kör lokalt i terminalen, alltså är allt säkert". Men modellen och verktygskedjan är fortfarande en dataflödesfråga.

Ett exempel på full arbetsinstruktion

För en större analys kan min instruktion se ut mer som en ticket än en prompt:

Det är ungefär här Claude Code går från chatbot till produktivitetsverktyg för mig. Agenten kan själv läsa materialet, skriva två filer, köra lokala checks och rapportera unresolved i stället för att pressa fram ett svar.

Vad jag vill att agenten rapporterar efter körning

Efter en större query vill jag inte bara ha resultatet. Jag vill ha en kort execution note: vilken regelversion användes, vilka tabeller lästes, vilka antaganden var nödvändiga och vilka validation queries passerade. Om någon kontroll inte kunde köras ska det stå uttryckligen. Detta gör ad hoc-analys mer reproducerbar. När någon tre veckor senare frågar varför en siffra skiljer sig från Power BI kan jag börja med kontraktet och queryversionen i stället för att rekonstruera en terminalsession från minnet.

På sikt skulle jag även vilja lint:a analytics-repot för återkommande risker: SELECT * i produktionsqueries, joins utan dokumenterad grain, DISTINCT efter misstänkt many-to-many, hårdkodade datum som borde vara parametrar och business rules som finns i queryn men saknas i metric-dokumentationen. AI kan hjälpa hitta sådant, men reglerna går i stor utsträckning att göra deterministiska. Det är precis den kombinationen jag vill åt: modellen för semantisk förståelse, kod för det som kan kontrolleras exakt.

Relaterade artiklar

Claude CodeClaudeSQLAI-produktutvecklingSQLdataanalys och AI
Dela