<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:media="http://search.yahoo.com/mrss/">
  <channel>
    <title>Jelks.nu - Blogg om digitalt skapande på webben och marknadsföring</title>
    <link>https://jelks.nu</link>
    <description>Vill du få bättre flyt i ditt digitala skapande, bygga en webbplats som känns rätt och nå fler med din marknadsföring? Här får du idéer att testa.</description>
    <language>pl</language>
    <pubDate>Thu, 12 Nov 2026 12:19:00 +0100</pubDate>
    <lastBuildDate>Thu, 12 Nov 2026 12:19:00 +0100</lastBuildDate>
    <item>
      <title>Kopiera filer i Python med shutil utan att skriva över fel fil</title>
      <link>https://jelks.nu/kopiera-filer-i-python-med-shutil-utan-att-skriva-over-fel-fil</link>
      <description>Lär dig kopiera filer i Python med shutil. Jämför copy(), copy2() och copytree(), hantera metadata och undvik oavsiktlig överskrivning. Läs guiden.</description>
      <content:encoded><![CDATA[<?xml encoding="utf-8" ?><p>

</p><p><img src="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/post_image/a6c64efe0017396ad45f147f980aa15c/python-shutil-copy-file-code-editor-example.webp" class="image article-image" loading="lazy" alt="Python-kod som f&ouml;rs&ouml;ker kopiera en fil med `copyfile`, men misslyckas d&aring; filen inte hittas."></p><p>Du ska kopiera en bild, konfigurationsfil eller export fr&aring;n ett <a href="https://jelks.nu/python-enum-strenum-och-flag-sa-valjer-du-ratt">Python</a>-skript, men en enda felvald funktion kan skriva &ouml;ver fel fil eller l&auml;mna r&auml;ttigheter bakom sig. F&ouml;r en vanlig fil fungerar oftast <code>shutil.copy2()</code> bra, &auml;ven om den inte kan bevara all metadata p&aring; varje system.</p><div class="short-summary">
  <h2 id="valj-kopieringsfunktion-efter-vad-malet-behover">V&auml;lj kopieringsfunktion efter vad m&aring;let beh&ouml;ver</h2>
  <ul>
    <li><strong><code>copyfile()</code></strong> kopierar inneh&aring;llet till ett angivet filnamn.</li>
    <li><strong><code>copy()</code></strong> kopierar inneh&aring;ll och beh&ouml;righetsl&auml;ge och kan ta emot en m&aring;lmapp.</li>
    <li><strong><code>copy2()</code></strong> f&ouml;rs&ouml;ker &auml;ven bevara filmetadata, till exempel &auml;ndringstid.</li>
    <li><strong><code>copytree()</code></strong> &auml;r funktionen f&ouml;r hela mappar och deras inneh&aring;ll.</li>
    <li><strong>Kontrollera m&aring;let</strong> om en befintlig fil inte f&aring;r skrivas &ouml;ver.</li>
  </ul>
</div><h2 id="en-rad-med-shutil-racker-for-en-vanlig-fil">En rad med shutil r&auml;cker f&ouml;r en vanlig fil</h2><p>Om en fil ska f&aring; en kopia med samma namn i en annan mapp &auml;r <code>shutil.copy2()</code> en smidig start. Modulens funktioner ing&aring;r i <a href="https://jelks.nu/sa-fungerar-pass-i-python-och-nar-du-ska-anvanda-det">Python</a>s standardbibliotek, s&aring; ingen separat installation beh&ouml;vs.</p><pre><code>from pathlib import Path
import shutil

source = Path("bilder/original.png")
destination = Path("public/kopia.png")

shutil.copy2(source, destination)</code></pre><p><code>Path</code> g&ouml;r s&ouml;kv&auml;garna tydligare, medan <code>copy2()</code> utf&ouml;r sj&auml;lva kopieringen. M&aring;lkatalogen m&aring;ste redan finnas; om den saknas kan du skapa den f&ouml;rst med <code>destination.parent.mkdir(parents=True, exist_ok=True)</code>. Det &auml;r en liten f&ouml;rberedelse som ofta f&ouml;rebygger ett vanligt k&ouml;rfel.</p><h2 id="copyfile-copy-och-copy2-lamnar-olika-resultat">copyfile, copy och copy2 l&auml;mnar olika resultat</h2><p>Tv&aring; kopior kan ha identiskt inneh&aring;ll men &auml;nd&aring; skilja sig i beh&ouml;righeter och tidsst&auml;mplar. D&auml;rf&ouml;r tycker jag att valet ska styras av vad kopian faktiskt anv&auml;nds till, inte av vilken funktion som r&aring;kar vara kortast.</p><table>
  <tbody>
    <tr><th>Funktion</th><th>Kopierar</th><th>Passar n&auml;r</th></tr>
    <tr><td><code>shutil.copyfile(src, dst)</code></td><td>Filinneh&aring;ll</td><td>Du anger hela m&aring;lfilens s&ouml;kv&auml;g och bara inneh&aring;llet beh&ouml;ver kopieras.</td></tr>
    <tr><td><code>shutil.copy(src, dst)</code></td><td>Filinneh&aring;ll och beh&ouml;righetsl&auml;ge</td><td>M&aring;let kan vara en mapp eller ett filnamn.</td></tr>
    <tr><td><code>shutil.copy2(src, dst)</code></td><td>Som <code>copy()</code>, med f&ouml;rs&ouml;k att bevara mer metadata</td><td>&Auml;ndringstid och annan tillg&auml;nglig filmetadata b&ouml;r f&ouml;lja med.</td></tr>
  </tbody>
</table><p>En viktig detalj g&ouml;mmer sig i ordet &rdquo;f&ouml;rs&ouml;ker&rdquo;: <code>copy2()</code> kan inte bevara all metadata, och vad som g&aring;r att kopiera beror p&aring; operativsystemet. <a href="https://jelks.nu/ta-bort-element-ur-en-lista-i-python-utan-att-missa-nagot">Python</a>s dokumentation f&ouml;r <a href="https://docs.python.org/3/library/shutil.html" target="_blank" rel="noopener noreferrer nofollow">shutil</a> beskriver skillnaderna; exempelvis f&ouml;ljer &auml;gare och grupp inte med p&aring; POSIX-system. Om kopian ska anv&auml;ndas som fullst&auml;ndig systembackup beh&ouml;ver du allts&aring; kontrollera vilka metadata som faktiskt kr&auml;vs.</p><h2 id="valj-funktion-efter-mal-och-metadata">V&auml;lj funktion efter m&aring;l och metadata</h2><p>Det g&aring;r att fatta beslutet utan att gissa: b&ouml;rja med m&aring;ltypen och avg&ouml;r sedan om filens metadata m&aring;ste f&ouml;lja med. Tabellen visar vad du kan g&ouml;ra i de vanligaste l&auml;gena.</p><table>
  <tbody>
    <tr><th>Situation</th><th>Trolig orsak eller f&ouml;ljd</th><th>G&ouml;r s&aring; h&auml;r</th></tr>
    <tr><td>Du anger en m&aring;lmapp</td><td><code>copy()</code> och <code>copy2()</code> kan kopiera dit med k&auml;llans filnamn.</td><td>Anv&auml;nd n&aring;gon av dem och kontrollera om metadata beh&ouml;vs.</td></tr>
    <tr><td>Du anger ett nytt fullst&auml;ndigt filnamn</td><td><code>copyfile()</code> kopierar inneh&aring;llet dit, men inte filens beh&ouml;righetsl&auml;ge.</td><td>V&auml;lj <code>copyfile()</code> om inneh&aring;llet r&auml;cker.</td></tr>
    <tr><td>&Auml;ndringstid och beh&ouml;righetsl&auml;ge ska f&ouml;lja med</td><td><code>copy2()</code> bevarar mer metadata &auml;n <code>copyfile()</code>, men st&ouml;det varierar.</td><td>V&auml;lj <code>copy2()</code> och verifiera metadata om programmet &auml;r beroende av dem.</td></tr>
    <tr><td>Destinationen kan redan inneh&aring;lla en fil med samma namn</td><td>Kopieringsfunktionerna kan skriva &ouml;ver den befintliga filen.</td><td>Kontrollera m&aring;let f&ouml;re kopieringen eller v&auml;lj ett nytt filnamn.</td></tr>
    <tr><td>K&auml;lla och m&aring;l pekar p&aring; samma fil</td><td>Kopieringen avbryts med <code>SameFileError</code>.</td><td>J&auml;mf&ouml;r s&ouml;kv&auml;garna eller hantera undantaget.</td></tr>
  </tbody>
</table><p>Om ett fel ska stoppa programmet kan kopieringen ligga i ett <code>try</code>-block som f&aring;ngar exempelvis <code>FileNotFoundError</code> och <code>PermissionError</code>. Undvik att f&aring;nga alla fel utan &aring;tskillnad: d&aring; riskerar ett verkligt problem att se ut som en lyckad kopiering.</p><h2 id="en-malmapp-ar-inte-samma-sak-som-en-fullstandig-backup">En m&aring;lmapp &auml;r inte samma sak som en fullst&auml;ndig backup</h2><p>Om uppgiften g&auml;ller m&aring;nga filer i en katalog &auml;r <code>shutil.copytree()</code> den s&auml;rskilda funktionen f&ouml;r att kopiera en hel mappstruktur. Den kopierar undermappar rekursivt och anv&auml;nder som standard <code>copy2()</code> f&ouml;r enskilda filer.</p><pre><code>import shutil

shutil.copytree("projekt", "projekt_kopia")</code></pre><p>Som standard m&aring;ste m&aring;lmappen inte redan finnas. Med <code>dirs_exist_ok=True</code> kan en befintlig m&aring;lmapp anv&auml;ndas, men motsvarande filer i den kan d&aring; skrivas &ouml;ver. Jag skulle bara sl&aring; p&aring; det n&auml;r det &auml;r avsikten; f&ouml;r en s&auml;kerhetskopia &auml;r en ny, tydligt namngiven m&aring;lmapp ofta l&auml;ttare att granska i efterhand.</p><p>F&ouml;r filer som kommer fr&aring;n en extern k&auml;lla ska s&ouml;kv&auml;gen dessutom valideras innan den anv&auml;nds. En fil som ov&auml;ntat hamnar utanf&ouml;r den avsedda m&aring;lmappen &auml;r ett st&ouml;rre problem &auml;n ett kopieringsfel.</p><h2 id="gor-kopian-sparbar-innan-skriptet-kors-automatiskt">G&ouml;r kopian sp&aring;rbar innan skriptet k&ouml;rs automatiskt</h2><p>N&auml;r ett skript kopierar filer regelbundet &auml;r det l&auml;tt att missa att en k&ouml;rning skrev &ouml;ver g&aring;rdagens resultat. B&ouml;rja med att best&auml;mma om befintliga filer f&aring;r ers&auml;ttas, och l&auml;gg sedan till en enkel kontroll f&ouml;re anropet.</p><pre><code>if not source.is_file():
    raise FileNotFoundError(f"K&auml;llfilen saknas: {source}")

if destination.exists():
    raise FileExistsError(f"M&aring;lfilen finns redan: {destination}")

shutil.copy2(source, destination)</code></pre><p>Den kontrollen g&ouml;r utfallet tydligt, men den garanterar inte att filen blir en komplett backup med alla systemmetadata. F&ouml;r en vanlig kopia mellan projektmappar r&auml;cker <code>copy2()</code> ofta l&aring;ngt; f&ouml;r &aring;terst&auml;llning av ett system b&ouml;r kopieringskraven &auml;ven omfatta beh&ouml;righeter, &auml;garskap och andra attribut som Python inte alltid kan f&ouml;ra &ouml;ver.</p>]]></content:encoded>
      
      <category>Programmering och AI</category>
      <media:thumbnail url="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/thumbnail/e397e70fa6a748985a911cd6516b54e2/kopiera-filer-i-python-med-shutil-utan-att-skriva-over-fel-fil.webp"/>
      <pubDate>Thu, 12 Nov 2026 12:19:00 +0100</pubDate>
    </item>
    <item>
      <title>Så initierar du ett Git-arkiv med git init</title>
      <link>https://jelks.nu/sa-initierar-du-ett-git-arkiv-med-git-init</link>
      <description>Lär dig initiera ett Git-arkiv med git init, spåra rätt filer och undvika problem med fjärrarkiv. Se stegen för en trygg första commit.</description>
      <content:encoded><![CDATA[<head></head><p>Du har en projektmapp med filer till en webbplats, men Git visar ingen versionshistorik. Kör <code>git init</code> i projektets rotmapp för att skapa ett lokalt Git-arkiv, men kommandot börjar inte spåra filerna automatiskt.</p>

<p><img src="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/post_image/1070b3fbed8d9edbecb997f7b3257554/terminal-med-git-init-i-en-projektmapp-kodredigerare-och-webbplatsfiler.webp" class="image article-image" loading="lazy" alt="Kod i filstruktur i en kodredigerare. En fil som heter `faq.tsx` är öppen och visar kod för en FAQ-sektion. `git init` är en kommando för att starta ett nytt Git-repo."></p>

<div class="short-summary">
  <h2 id="git-arkivet-borjar-tomt-tills-du-lagger-till-och-committar-filer">Git-arkivet börjar tomt tills du lägger till och committar filer</h2>
  <ul>
    <li><strong>Initiera:</strong> kör <code>git init -b main</code> i projektets rotmapp.</li>
    <li><strong>Spåra filer:</strong> välj innehåll med <code>git add</code> och spara en första version med <code>git commit</code>.</li>
    <li><strong>Välj rätt kommando:</strong> använd <code>git clone</code> när arkivet redan finns på en server.</li>
    <li><strong>Kontrollera platsen:</strong> <code>git status</code> visar om du är i rätt arkiv och vad Git ser.</li>
  </ul>
</div>

<h2 id="initiera-i-projektets-rotmapp-inte-i-en-mapp-bredvid">Initiera i projektets rotmapp, inte i en mapp bredvid</h2>
<p>Stå i mappen där webbplatsens filer och projektinställningar hör hemma. Kör du kommandot en nivå för högt kan Git börja behandla flera projekt som ett enda arkiv, vilket gör statuslistan svår att tolka.</p>
<pre><code>cd sökväg/till/projektet
git init -b main
git status</code></pre>
<p>Flaggan <code>-b main</code> anger namnet på den första grenen, så du slipper förlita dig på vilken standardinställning som gäller på datorn. Enligt <a href="https://git-scm.com/docs/git-init" target="_blank" rel="noopener noreferrer nofollow">Git-dokumentationen för git init</a> skapar kommandot arkivets interna struktur; det lägger inte till projektfilerna i historiken.</p>
<p><strong>Kontrollera platsen innan du går vidare.</strong> Om terminalen visar oväntat många filer eller projekt, kör <code>pwd</code> för att se aktuell mapp och <code>git status</code> för att kontrollera vilket arkiv Git använder.</p>

<h2 id="den-forsta-versionen-kraver-bade-staging-och-commit">Den första versionen kräver både staging och commit</h2>
Ett nytt arkiv är tomt på historik även när projektmappen redan innehåller en färdig webbplats. Första gången behöver du välja vilka filer som ska ingå, <a href="https://jelks.nu/git-kommandon-for-sakrare-andringar-i-projektet">granska urvalet</a> och sedan skapa en commit, alltså en sparad ögonblicksbild.
<pre><code>git status
git add .
git status
git commit -m "Första versionen"</code></pre>
<p><code>git add .</code> lägger till filer från den aktuella mappen och dess undermappar i staging-området, där du förbereder nästa commit. Jag tycker att en extra <code>git status</code> före commit är en enkel försäkring: den kan avslöja att en uppladdningsmapp, en loggfil eller en lokal konfigurationsfil råkat följa med.</p>
<p>Om projektet innehåller filer som inte ska versionshanteras, skapa först en <code>.gitignore</code>-fil och ange mönster för dem, till exempel byggfiler eller lokala miljöinställningar. Kontrollera sedan status igen; ignorering påverkar inte filer som redan har lagts till i Git.</p>

<h2 id="valj-git-clone-nar-projektets-arkiv-redan-finns">Välj git clone när projektets arkiv redan finns</h2>
<p>Skillnaden märks tydligast när du ska börja arbeta med ett befintligt projekt. <code>git init</code> skapar ett nytt lokalt arkiv, medan <code>git clone</code> hämtar ett arkiv som redan finns, inklusive dess historik.</p>
<table>
  <tbody>
    <tr>
      <th scope="col">Situation</th>
      <th scope="col">Vad det betyder</th>
      <th scope="col">Gör så här</th>
    </tr>
    <tr>
      <td>Projektet finns bara på din dator</td>
      <td>Det finns ingen fjärrhistorik att hämta.</td>
      <td>Kör <code>git init</code> i projektmappen.</td>
    </tr>
    <tr>
      <td>Arkivet finns redan på GitHub eller en annan server</td>
      <td>En ny lokal kopia behöver den befintliga historiken.</td>
      <td>Kör <code>git clone</code> med arkivets adress.</td>
    </tr>
    <tr>
      <td>Fjärrarkivet är tomt och du har en lokal projektmapp</td>
      <td>Det finns ingen befintlig historik att bevara på servern.</td>
      <td>Initiera lokalt, skapa en commit och koppla sedan in fjärrarkivet.</td>
    </tr>
  </tbody>
</table>
<p><a href="https://github.com/git-guides/git-init" target="_blank" rel="noopener noreferrer nofollow">GitHubs guide till git init</a> beskriver samma praktiska uppdelning: börja lokalt med <code>git init</code> när projektet ännu saknar ett arkiv, och välj <code>git clone</code> när ett arkiv redan finns. Att använda båda utan att tänka på ordningen kan skapa två separata historiker som senare måste fogas ihop.</p>

<h2 id="ett-readme-pa-servern-kan-skapa-en-ovantad-konflikt">Ett README på servern kan skapa en oväntad konflikt</h2>
<p>Du har committat webbplatsen lokalt och skapat ett tomt fjärrarkiv. Då kan du koppla ihop dem så här:</p>
<pre><code>git remote add origin fjärrarkivets-adress
git push -u origin main</code></pre>
<p>Problemet uppstår om fjärrarkivet inte längre är tomt, till exempel för att en README-fil skapades där från början. Då har den lokala och fjärranslutna historiken olika startpunkter, och en vanlig push kan nekas. GitHub beskriver flödet för befintlig lokal kod i <a href="https://docs.github.com/en/migrations/importing-source-code/using-the-command-line-to-import-source-code/adding-locally-hosted-code-to-github" target="_blank" rel="noopener noreferrer nofollow">dokumentationen om att lägga till lokalt lagrad kod</a>.</p>
<p><strong>Om fjärrarkivet redan har filer</strong>, klona det först och flytta sedan in projektfilerna i den klonade mappen. Om du redan har committat lokalt, kontrollera fjärrarkivets innehåll och historik innan du försöker slå ihop dem; undvik att tvinga igenom en push som skriver över andras arbete.</p>

<h2 id="git-status-pekar-ut-var-initieringen-gick-snett">Git status pekar ut var initieringen gick snett</h2>
<p>När Git verkar se fel filer är orsaken ofta att terminalen står i fel mapp eller att ett annat arkiv finns högre upp i mappstrukturen. Börja med statusmeddelandet och jämför det med projektets faktiska plats.</p>
<table>
  <tbody>
    <tr>
      <th scope="col">Situation</th>
      <th scope="col">Trolig orsak</th>
      <th scope="col">Nästa steg</th>
    </tr>
    <tr>
      <td><code>git status</code> visar filer från flera projekt</td>
      <td>Arkivet kan ha initierats i en överordnad mapp.</td>
      <td>Kontrollera sökvägen med <code>pwd</code> och leta efter en oavsiktlig <code>.git</code>-mapp.</td>
    </tr>
    <tr>
      <td>Filerna listas som untracked</td>
      <td>Arkivet finns, men filerna har inte lagts till i staging.</td>
      <td>Granska <code>git status</code>, välj filer med <code>git add</code> och committa dem.</td>
    </tr>
    <tr>
      <td>Git säger att det inte finns något att committa</td>
      <td>Inga nya ändringar har lagts till, eller så ligger filerna utanför arkivet.</td>
      <td>Kontrollera aktuell mapp och kör <code>git status --short</code>.</td>
    </tr>
  </tbody>
</table>
<p>Ta inte bort en <code>.git</code>-mapp förrän du har bekräftat vilket arkiv den tillhör. Den innehåller projektets Git-historik, och om den raderas försvinner den lokala historiken även om webbplatsens vanliga filer ligger kvar.</p>

<h2 id="lat-den-forsta-commiten-bli-en-tydlig-startpunkt">Låt den första commiten bli en tydlig startpunkt</h2>
<p>När rätt filer ligger i rätt arkiv blir den första commiten en ren bas för fortsatt arbete. Kontrollera status, uteslut privata inställningar och välj <code>main</code> som startgren om det passar projektets arbetsflöde.</p>
<p>Om fjärrarkivet redan innehåller historik, klona det i stället för att skapa ett parallellt arkiv med <code>git init</code>. Då slipper du börja med att reda ut varför två versioner av samma projekt inte går att skicka ihop.</p>]]></content:encoded>
      
      <category>Utvecklingsverktyg och arbetsflöden</category>
      <media:thumbnail url="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/thumbnail/119448f9d8f6f063dd47fa6ecb8675d6/sa-initierar-du-ett-git-arkiv-med-git-init.webp"/>
      <pubDate>Wed, 11 Nov 2026 18:31:00 +0100</pubDate>
    </item>
    <item>
      <title>PostgreSQL i Docker Compose med beständig lagring</title>
      <link>https://jelks.nu/postgresql-i-docker-compose-med-bestandig-lagring</link>
      <description>Få PostgreSQL i Docker Compose att behålla data och ansluta rätt. Se rätt volymsökväg för version 18 och äldre, och felsök steg för steg.</description>
      <content:encoded><![CDATA[<?xml encoding="utf-8" ?><p>Din webbapp f&ouml;rs&ouml;ker ansluta till PostgreSQL, men databasen svarar inte efter att containern startats om. En PostgreSQL-container fungerar oftast smidigt med <a href="https://jelks.nu/sa-installerar-du-docker-pa-debian-och-verifierar-installationen">Docker Compose</a> och en namngiven volym, men lagringsv&auml;gen beror p&aring; vilken huvudversion av PostgreSQL du k&ouml;r.

</p><p><img src="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/post_image/a776111baa96f296300f1801f96c623a/docker-compose-postgresql-container-architecture-named-volume-app-database-diagram.webp" class="image article-image" loading="lazy" alt="Databasmodell f&ouml;r en e-handel med tabeller som users, sale, product, store, city, country och order_status. Perfekt f&ouml;r en docker postgres-l&ouml;sning."></p><div class="short-summary">
  <h2 id="en-stabil-postgresql-container-borjar-med-ratt-volym-och-natverk">En stabil PostgreSQL-container b&ouml;rjar med r&auml;tt volym och n&auml;tverk</h2>
  <ul>
    <li><strong>Compose:</strong> Anv&auml;nd en namngiven volym s&aring; att databasfilerna &ouml;verlever n&auml;r containern &aring;terskapas.</li>
    <li><strong>PostgreSQL 18:</strong> Montera volymen p&aring; <code>/var/lib/postgresql</code>.</li>
    <li><strong>PostgreSQL 17 och &auml;ldre:</strong> Anv&auml;nd <code>/var/lib/postgresql/data</code> som monteringspunkt.</li>
    <li><strong>App i en annan container:</strong> Anslut till tj&auml;nstens namn, till exempel <code>db</code>, i st&auml;llet f&ouml;r <code>localhost</code>.</li>
    <li><strong>Viktig f&auml;lla:</strong> Variabler som <code>POSTGRES_PASSWORD</code> anv&auml;nds vid f&ouml;rsta initieringen, inte f&ouml;r att &auml;ndra uppgifter i en redan skapad databas.</li>
  </ul>
</div><h2 id="starta-databasen-med-compose-och-en-namngiven-volym">Starta databasen med Compose och en namngiven volym</h2><p>En databas utan best&auml;ndig lagring kan verka fungera utm&auml;rkt tills containern tas bort. Jag tycker att en namngiven volym &auml;r ett klokt standardval f&ouml;r lokal utveckling, eftersom Docker hanterar lagringen utan att du beh&ouml;ver &ouml;ppna databasens interna filer p&aring; v&auml;rddatorn.</p><p>Skapa en fil med namnet <code>compose.yaml</code>. Exemplet anv&auml;nder PostgreSQL 18 och binder porten till den egna datorn, inte till alla n&auml;tverksgr&auml;nssnitt.</p><pre><code>services:
  db:
    image: postgres:18
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?S&auml;tt POSTGRES_PASSWORD i .env}
      POSTGRES_DB: appdb
    ports:
      - "127.0.0.1:5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app -d appdb"]
      interval: 5s
      timeout: 3s
      retries: 10

volumes:
  postgres_data:</code></pre><p>L&auml;gg l&ouml;senordet i en lokal <code>.env</code>-fil och l&auml;mna inte in den i versionshantering. F&ouml;r en driftsmilj&ouml; b&ouml;r hemligheter hanteras med en l&auml;mplig secrets-l&ouml;sning i st&auml;llet f&ouml;r att b&auml;ddas in i Compose-filen. Starta tj&auml;nsten med <code>docker compose up -d</code> och kontrollera loggen med <code>docker compose logs -f db</code>.</p><p>H&auml;lsokontrollen anv&auml;nder <code>pg_isready</code>, ett verktyg som kontrollerar om servern kan ta emot anslutningar. Den hj&auml;lper Compose att skilja en startad container fr&aring;n en databas som faktiskt &auml;r redo.</p><h2 id="valj-monteringspunkt-efter-postgresql-version">V&auml;lj monteringspunkt efter PostgreSQL-version</h2><p>En volym kan finnas kvar och &auml;nd&aring; se tom ut f&ouml;r PostgreSQL om den monteras p&aring; fel s&ouml;kv&auml;g. F&ouml;r PostgreSQL 18 &auml;ndrades standardplaceringen av data j&auml;mf&ouml;rt med &auml;ldre huvudversioner, s&aring; kopiera inte en gammal Compose-fil utan att kontrollera dess monteringspunkt.</p><table>
  <tbody>
    <tr>
      <th scope="col">PostgreSQL-version</th>
      <th scope="col">Monteringspunkt i containern</th>
      <th scope="col">Praktisk f&ouml;ljd</th>
    </tr>
    <tr>
      <td>18</td>
      <td><code>/var/lib/postgresql</code></td>
      <td>Det &auml;r s&ouml;kv&auml;gen i Compose-exemplet ovan.</td>
    </tr>
    <tr>
      <td>17 och &auml;ldre</td>
      <td><code>/var/lib/postgresql/data</code></td>
      <td>En volym monterad endast p&aring; <code>/var/lib/postgresql</code> kan missa katalogen d&auml;r databasen faktiskt skriver data.</td>
    </tr>
  </tbody>
</table><p>Den officiella <a href="https://hub.docker.com/_/postgres" target="_blank" rel="noopener noreferrer nofollow">PostgreSQL-avbildningens dokumentation</a> beskriver b&aring;de den versionsspecifika s&ouml;kv&auml;gen f&ouml;r PostgreSQL 18 och monteringspunkten f&ouml;r version 17 och &auml;ldre. H&aring;ll d&auml;rf&ouml;r ihop avbildningens huvudversion och volymens s&ouml;kv&auml;g n&auml;r du &auml;ndrar konfigurationen.</p><p>Var s&auml;rskilt f&ouml;rsiktig vid uppgradering mellan huvudversioner. &Auml;ndra inte bara <code>image:</code>-taggen och anta att den gamla datakatalogen kan anv&auml;ndas direkt; planera en uppgradering eller migrering och ta en s&auml;kerhetskopia f&ouml;rst.</p><h2 id="andrade-miljovariabler-aterstaller-inte-en-befintlig-databas">&Auml;ndrade milj&ouml;variabler &aring;terst&auml;ller inte en befintlig databas</h2><p>Byter du l&ouml;senord i Compose men f&aring;r &auml;nd&aring; ett autentiseringsfel? Det beror ofta p&aring; att variabeln bara anv&auml;nds n&auml;r datakatalogen initieras f&ouml;r f&ouml;rsta g&aring;ngen. Om volymen redan inneh&aring;ller en databas l&auml;mnas befintliga anv&auml;ndare och uppgifter i fred.</p><p>Det g&auml;ller ocks&aring; <code>POSTGRES_USER</code>, <code>POSTGRES_DB</code> och initieringsfilerna i <code>/docker-entrypoint-initdb.d</code>. De &auml;r praktiska vid en ny installation, men de k&ouml;rs inte om fr&aring;n b&ouml;rjan bara f&ouml;r att containern startas om. En omstart &auml;r allts&aring; ingen genv&auml;g f&ouml;r att &auml;ndra databasens ursprungliga inst&auml;llningar.</p><ul>
  <li><strong>Utvecklingsdatabas med data du vill beh&aring;lla:</strong> &auml;ndra l&ouml;senordet via en PostgreSQL-klient och beh&aring;ll volymen.</li>
  <li><strong>Testdatabas som f&aring;r raderas:</strong> ta bort volymen med <code>docker compose down -v</code> och starta sedan tj&auml;nsten p&aring; nytt. Kommandot raderar databasinneh&aring;llet.</li>
  <li><strong>Initieringsskript k&ouml;rs inte:</strong> kontrollera om datakatalogen redan inneh&aring;ller en databas. Skripten k&ouml;rs vid initiering, inte vid varje start.</li>
</ul><p>Den officiella <a href="https://docs.docker.com/guides/postgresql/" target="_blank" rel="noopener noreferrer nofollow">Docker-guiden f&ouml;r PostgreSQL</a> beskriver b&aring;de best&auml;ndig lagring och initieringsskript. I praktiken &auml;r den s&auml;kra skiljelinjen enkel: beh&aring;ll volymen om data ska finnas kvar, och radera den bara n&auml;r inneh&aring;llet verkligen kan f&ouml;rsvinna.</p><h2 id="valj-anslutning-efter-var-appen-kors">V&auml;lj anslutning efter var appen k&ouml;rs</h2><p>Adressen <code>localhost</code> betyder den egna milj&ouml;n. Fr&aring;n en appcontainer pekar den d&auml;rf&ouml;r p&aring; appcontainern sj&auml;lv, inte p&aring; databastj&auml;nsten bredvid. Anv&auml;nd i st&auml;llet Compose-tj&auml;nstens namn som v&auml;rdnamn.</p><table>
  <tbody>
    <tr>
      <th scope="col">Situation</th>
      <th scope="col">Trolig orsak</th>
      <th scope="col">G&ouml;r s&aring; h&auml;r</th>
    </tr>
    <tr>
      <td>Appen k&ouml;rs i en annan Compose-tj&auml;nst</td>
      <td><code>localhost</code> pekar p&aring; appcontainern.</td>
      <td>Anv&auml;nd exempelvis <code>db:5432</code> som v&auml;rd och port.</td>
    </tr>
    <tr>
      <td>Databasverktyg k&ouml;rs p&aring; din dator</td>
      <td>Porten har inte publicerats till v&auml;rddatorn.</td>
      <td>Publicera porten och anslut till <code>127.0.0.1:5432</code>.</td>
    </tr>
    <tr>
      <td>Containern startar om med fel om beh&ouml;righet</td>
      <td>En bind mount kan ha <a href="https://jelks.nu/linuxkommandon-for-felsokning-filer-och-tjanster">filr&auml;ttigheter</a> som inte fungerar med PostgreSQL-processen.</td>
      <td>Kontrollera loggarna och &ouml;verv&auml;g en namngiven volym.</td>
    </tr>
    <tr>
      <td>Nya milj&ouml;variabler verkar ignoreras</td>
      <td>Volymen inneh&aring;ller redan en initialiserad databas.</td>
      <td>&Auml;ndra kontot inne i PostgreSQL eller &aring;terskapa databasen f&ouml;rst efter s&auml;kerhetskopiering.</td>
    </tr>
  </tbody>
</table><p>Om appen och databasen ligger i samma Compose-projekt kan anslutningsstr&auml;ngen exempelvis vara <code>postgresql://app:DITT_L&Ouml;SENORD@db:5432/appdb</code>. Fr&aring;n ett verktyg p&aring; datorn anv&auml;nder du i st&auml;llet <code>localhost</code> eller <code>127.0.0.1</code>, f&ouml;rutsatt att porten har publicerats.</p><p>Beh&ouml;ver ingen ansluta fr&aring;n v&auml;rddatorn? Ta bort <code>ports</code> helt. D&aring; kan andra tj&auml;nster i Docker-n&auml;tverket n&aring; databasen, medan PostgreSQL inte exponeras genom en publicerad v&auml;rdport. Jag skulle v&auml;lja den l&ouml;sningen f&ouml;r en app som ocks&aring; k&ouml;rs i containrar.</p><h2 id="felsok-anslutningen-innan-du-ror-volymen">Fels&ouml;k anslutningen innan du r&ouml;r volymen</h2><p>N&auml;r anslutningen fallerar &auml;r det lockande att radera volymen och b&ouml;rja om. V&auml;nta med det. B&ouml;rja med att kontrollera om containern k&ouml;rs och vad databasen skriver i loggen.</p><ol>
  <li>K&ouml;r <code>docker compose ps</code> f&ouml;r att kontrollera tj&auml;nstens status.</li>
  <li>K&ouml;r <code>docker compose logs db</code> och leta efter initieringsfel, beh&ouml;righetsproblem eller meddelanden om att servern &auml;r redo.</li>
  <li>Kontrollera att appens v&auml;rdnamn passar dess milj&ouml;: <code>db</code> mellan containrar, <code>localhost</code> fr&aring;n v&auml;rddatorn.</li>
  <li>J&auml;mf&ouml;r PostgreSQL-huvudversionen med volymens monteringspunkt.</li>
  <li>Ta en s&auml;kerhetskopia innan du tar bort eller byter volym.</li>
</ol><p>F&ouml;r lokal utveckling kan en SQL-dump skapas med <code>docker compose exec -T db pg_dump -U app appdb &gt; backup.sql</code>. En dump &auml;r anv&auml;ndbar n&auml;r databasen ska flyttas eller &aring;terskapas, men kontrollera att filen skapats och g&aring;r att l&auml;sa innan du behandlar den som enda kopia.</p><h2 id="lat-volymen-skydda-arbetet-inte-forvirra-det">L&aring;t volymen skydda arbetet, inte f&ouml;rvirra det</h2><p>Den vanligaste stabila grundl&ouml;sningen &auml;r r&auml;tt versionss&ouml;kv&auml;g, en namngiven volym och en anslutning som anv&auml;nder r&auml;tt v&auml;rdnamn f&ouml;r klientens milj&ouml;. N&auml;r n&aring;got g&aring;r fel ger loggarna och volymens monteringspunkt oftast b&auml;ttre ledtr&aring;dar &auml;n att b&ouml;rja om fr&aring;n noll.</p><p>Se volymen som databasens best&auml;ndiga hem och containern som processen som &ouml;ppnar d&ouml;rren dit. D&aring; blir det l&auml;ttare att uppdatera eller &aring;terskapa containern utan att f&ouml;rv&auml;xla det med att radera sj&auml;lva databasen.</p>]]></content:encoded>
      
      <category>DevOps och systemadministration</category>
      <media:thumbnail url="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/thumbnail/84fae82389d48c4293d3d6096196cb69/postgresql-i-docker-compose-med-bestandig-lagring.webp"/>
      <pubDate>Tue, 10 Nov 2026 15:14:00 +0100</pubDate>
    </item>
    <item>
      <title>Font Awesome eller SVG? Välj rätt ikoner för webbplatsen</title>
      <link>https://jelks.nu/font-awesome-eller-svg-valj-ratt-ikoner-for-webbplatsen</link>
      <description>Font Awesome, SVG eller ikonfont? Se vad som passar få eller många ikoner och få tips om laddning, tillgänglighet och felsökning.</description>
      <content:encoded><![CDATA[<p>När en menyknapp bara visar en liten symbol kan det kännas snabbare att klistra in en Font Awesome-klass och gå vidare. Det fungerar ofta, men valet mellan ikonfont och SVG påverkar både laddning och tillgänglighet, särskilt när samma symbol återkommer på många ställen.</p>

<p><img src="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/post_image/fc5a31e0d2c15688f8e236ceecafba70/font-awesome-icons-in-web-development-html-css-svg-code-example.webp" class="image article-image" loading="lazy" alt="Jämförelse av ikoner: Font Awesome och Hugeicons visar liknande symboler som förstoringsglas, stjärna, ryggsäck, pil, kundvagn, pokal, nedladdning, väska, pappersflygplan, hjärta, pratbubbla, portfölj, länk, lås och present."></p>

<div class="short-summary">
  <h2 id="valj-ikonmetod-efter-hur-granssnittet-faktiskt-anvands">Välj ikonmetod efter hur gränssnittet faktiskt används</h2>
  <ul>
    <li><strong>En snabb start:</strong> lägg till en ikon med en stilklass och ikonens namn, till exempel <code>fa-solid fa-house</code>.</li>
    <li><strong>Få ikoner:</strong> SVG med JavaScript passar ofta bra när du vill välja ut en liten mängd ikoner.</li>
    <li><strong>Många ikoner på en sida:</strong> jämför web fonts eller SVG-symboler och mät laddningen i din egen app.</li>
    <li><strong>Tillgänglighet:</strong> dekorativa ikoner kan döljas för skärmläsare, medan en ikon som bär information behöver ett textalternativ.</li>
    <li><strong>Underhåll:</strong> håll version, stil och ikonklass konsekventa för att undvika saknade eller felrenderade symboler.</li>
  </ul>
</div>
<h2 id="en-ikon-visas-med-en-stilklass-och-ett-namn">En ikon visas med en stilklass och ett namn</h2>
<p>En meny med hus, sök och kundvagn behöver sällan en egen bildfil för varje symbol. Med Font Awesome anger du ikonens <strong>familj, stil och namn</strong> i klasslistan, exempelvis <code><i class="fa-solid fa-house"></i></code>.</p>
<p>Klassen <code>fa-solid</code> väljer stilen och <code>fa-house</code> pekar ut ikonen. Du behöver också ha lagt till Font Awesome i projektet, via ett Kit, ett paket eller filer som du själv hostar. Utan den installationen blir HTML-koden bara en tom behållare.</p>
<p>Dokumentationen rekommenderar ett konsekvent inline-element, till exempel <code><i></i></code> eller <code><span></span></code>. Jag tycker att tydliga klassnamn och en konsekvent metod gör det enklare att felsöka när en symbol plötsligt saknas.</p>
<h2 id="fa-ikoner-och-stora-ikonlistor-behover-olika-losningar">Få ikoner och stora ikonlistor behöver olika lösningar</h2>
<p>En ikon i en knapp och hundratals ikoner i en produktkatalog ställer inte samma krav. Font Awesome har flera sätt att visa ikoner, och det finns ingen metod som är bäst för varje sida.</p>
<p>Enligt Font Awesomes dokumentation kan SVG med JavaScript passa när sidan visar ett begränsat antal ikoner och du kan välja ut de ikoner som ska ingå. Web fonts med CSS kan vara ett alternativ när många ikoner ska visas eller när du behöver en etablerad lösning utan JavaScript för själva ikonvisningen. SVG-symboler kan passa när du vill återanvända symboler utan att förlita dig på JavaScript.</p>
<p>En användbar tumregel är därför: <strong>få symboler och behov av precis kontroll talar för SVG</strong>; många återkommande symboler motiverar att du testar en fontlösning eller SVG-symboler. Font Awesome rekommenderar själv att du begränsar vilka ikoner och stilar som laddas, i stället för att ta in allt av bara farten. <a href="https://docs.fontawesome.com/web/dig-deeper/performance/" target="_blank" rel="noopener noreferrer nofollow">Font Awesomes prestandaguide</a> beskriver skillnaderna mellan metoderna.</p>
<p>Det är en tumregel, inte ett resultat du kan anta i förväg. Kontrollera sidans faktiska nätverksladdning och renderingsbeteende, eftersom tema, cache och andra bibliotek kan påverka utfallet.</p>
<h2 id="font-awesome-ar-fortfarande-vanligt-men-ikonfont-ar-inte-automatiskt-snabbast">Font Awesome är fortfarande vanligt, men ikonfont är inte automatiskt snabbast</h2>
<p>Ikonfonter har länge varit ett smidigt standardval, men popularitet säger inte i sig hur väl en metod passar din webbplats. I <a href="https://almanac.httparchive.org/en/2025/fonts" target="_blank" rel="noopener noreferrer nofollow">HTTP Archives Web Almanac för 2025</a> uppskattas Font Awesome finnas på ungefär <strong>en av 25 webbplatser</strong> i den analyserade datan.</p>
<p>Det visar att verktyget fortfarande har stor spridning, inte att en fontlösning alltid laddar snabbast eller fungerar bäst i varje app. Den skillnaden är lätt att missa när ett välkänt verktyg också är enkelt att komma igång med.</p>
<p>För ett litet gränssnitt med några få symboler skulle jag välja SVG om projektets verktygskedja redan hanterar det smidigt. Om en sida behöver många ikoner skulle jag först testa en begränsad fontuppsättning eller återanvändbara SVG-symboler, i stället för att välja en metod efter vana.</p>
<h2 id="decorativa-ikoner-och-meningsbarande-ikoner-behover-olika-markning">Decorativa ikoner och meningsbärande ikoner behöver olika märkning</h2>
<p>En förstoringsglassymbol bredvid texten ”Sök” upprepar knappens budskap. En ensam ikonknapp utan synlig etikett gör något annat: symbolen måste då få ett namn som hjälpmedel kan läsa upp.</p>
<p>Font Awesome anger att dekorativa SVG-ikoner som läggs in via Kit eller självhostad SVG med JavaScript automatiskt får <code>aria-hidden="true"</code>. För en ikon som ska kommunicera något behöver det interaktiva elementet en begriplig etikett, till exempel <code>aria-label="Sök"</code> på knappen, inte bara ett namn på själva symbolen.</p>
<table>
  <tbody>
    <tr>
      <th scope="col">Situation</th>
      <th scope="col">Trolig orsak eller följd</th>
      <th scope="col">Gör så här</th>
    </tr>
    <tr>
      <td>Ikonen ligger intill en tydlig textetikett</td>
      <td>Symbolen är dekorativ och behöver normalt inte läsas upp separat.</td>
      <td>Dölj ikonen för skärmläsare, exempelvis med <code>aria-hidden="true"</code> där metoden kräver det.</td>
    </tr>
    <tr>
      <td>En knapp består bara av en ikon</td>
      <td>Skärmläsaren kan sakna knappens namn.</td>
      <td>Ge knappen en beskrivande etikett, exempelvis <code>aria-label="Öppna sök"</code>.</td>
    </tr>
    <tr>
      <td>Ikonen förmedlar information som saknas i texten</td>
      <td>Om symbolen döljs kan informationen gå förlorad.</td>
      <td>Lägg till ett textalternativ eller en tydlig etikett enligt ikonens funktion.</td>
    </tr>
  </tbody>
</table>
<p><a href="https://docs.fontawesome.com/web/dig-deeper/accessibility" target="_blank" rel="noopener noreferrer nofollow">Font Awesomes tillgänglighetsdokumentation</a> skiljer mellan dekorativa symboler och ikoner som behöver ett textalternativ. Den praktiska kontrollen är enkel: om ikonen försvinner visuellt, går knappens eller innehållets betydelse fortfarande fram?</p>
<h2 id="stilprefix-och-versionsskillnader-forklarar-manga-saknade-ikoner">Stilprefix och versionsskillnader förklarar många saknade ikoner</h2>
<p>När en ikonklass inte ger någon synlig symbol är det lätt att misstänka CSS. Ofta ligger felet i stället i att den valda stilen inte ingår i installationen, eller att klassnamnet inte passar den Font Awesome-version som projektet använder.</p>
<p>Exempelvis väljer <code>fa-solid</code> Solid-stilen, medan <code>fa-brands</code> används för varumärkesikoner. Klassnamnet <code>fa-house</code> anger själva symbolen. En gammal klass kan fungera genom en aliaslösning i vissa versioner, men det är säkrare att hålla sig till de namn och stilar som projektets installerade paket faktiskt stöder.</p>
<p>För Vue och React finns separata integrationsvägar, så generisk HTML med <code><i></i></code> är inte alltid den renaste lösningen i ett komponentbaserat projekt. <a href="https://docs.fontawesome.com/web/add-icons/how-to" target="_blank" rel="noopener noreferrer nofollow">Font Awesomes guide för att lägga till ikoner</a> visar hur klassnamn, stilprefix och alternativa integrationssätt hänger ihop.</p>
<p>Om en ikon saknas, kontrollera i den här ordningen:</p>
<ol>
  <li><strong>Installationen:</strong> laddas rätt Kit, paket eller CSS-fil på sidan?</li>
  <li><strong>Stilen:</strong> finns Solid, Brands eller den valda varianten med i paketet?</li>
  <li><strong>Namnet:</strong> stämmer ikonens klass med den version projektet använder?</li>
  <li><strong>CSS och JavaScript:</strong> har egna regler eller fel i konsolen påverkat renderingen?</li>
</ol>
<h2 id="gor-ikonvalet-latt-att-andra-senare">Gör ikonvalet lätt att ändra senare</h2>
<p>En ikon som ser självklar ut i dag kan bli svår att förstå när den står ensam i en smal mobilmeny. Välj därför symboler som går att känna igen i den storlek och miljö där de faktiskt visas, och komplettera med text när betydelsen annars blir tvetydig.</p>
<p>Håll också antalet laddade stilar nere och samla återkommande ikonval i komponenter eller designregler. Då slipper du att samma sökknapp råkar använda olika varianter på olika sidor, samtidigt som ett framtida byte från ikonfont till SVG blir enklare.</p>
<p>För ett nytt gränssnitt skulle jag börja med några få ikoner, välja SVG eller en begränsad Font Awesome-installation utifrån projektets behov och sedan kontrollera både laddning och tillgänglighet. Den bästa lösningen är den som fortfarande fungerar när ikonen står ensam, nätverket är långsamt och en skärmläsare tar över.</p>]]></content:encoded>
      
      <category>Frontend- och apputveckling</category>
      <media:thumbnail url="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/thumbnail/92d2eca295ad740bf7af8ce0a0ecd0cf/font-awesome-eller-svg-valj-ratt-ikoner-for-webbplatsen.webp"/>
      <pubDate>Mon, 09 Nov 2026 15:34:00 +0100</pubDate>
    </item>
    <item>
      <title>Så väljer du mellan Record och Map i TypeScript</title>
      <link>https://jelks.nu/sa-valjer-du-mellan-record-och-map-i-typescript</link>
      <description>Ska du använda Record eller Map i TypeScript? Se hur nyckeltypen påverkar valet och hantera saknade uppslag säkert. Läs guiden.</description>
      <content:encoded><![CDATA[<p>När en webbplats ska slå upp en produkt utifrån en kod behöver typen spegla hur uppslaget faktiskt fungerar. En TypeScript-dictionary passar ofta när nycklarna är strängar och värdena har samma form, men om nycklarna kan vara objekt eller saknas är valet mindre självklart.</p>

<p><img src="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/post_image/411c5d0cdb4e78c271fa4ec93e62fd7b/typescript-record-dictionary-object-versus-map-key-value-comparison-code-illustration.webp" class="image article-image" loading="lazy" alt="Flödesschema för att välja mellan Map och Record i TypeScript. En typescript dictionary kan vara en Map eller Record beroende på nycklar och användning."></p>

<div class="short-summary">
  <h2 id="valj-struktur-efter-nycklarna-och-hur-uppslaget-ska-fungera">Välj struktur efter nycklarna och hur uppslaget ska fungera</h2>
  <ul>
    <li><strong>Record</strong> passar när nycklarna är strängar och värdena delar en typ.</li>
    <li><strong>En begränsad nyckelunion</strong> gör att TypeScript kräver ett värde för varje angiven nyckel.</li>
    <li><strong>Map</strong> passar när nycklar kan vara objekt eller när du behöver metoder som <code>set</code> och <code>delete</code>.</li>
    <li><strong>Saknade uppslag</strong> behöver hanteras uttryckligen, särskilt när data kommer från användare eller ett API.</li>
  </ul>
</div>

<h2 id="record-passar-bast-nar-nycklarna-ar-strangar">Record passar bäst när nycklarna är strängar</h2>
<p>En kod som <code>"se-104"</code> eller ett produktnamn fungerar bra som objektets nyckel. Med <code>Record</code> anger du vilken typ nycklarna och värdena ska ha, utan att skriva en indexsignatur manuellt.</p>
<pre><code>type Product = {
  name: string;
  price: number;
};

const products: Record<string product> = {
  "se-104": { name: "Anteckningsbok", price: 49 },
};

const product = products["se-104"];</string></code></pre>
<p><a href="https://www.typescriptlang.org/docs/handbook/utility-types.html" target="_blank" rel="noopener noreferrer nofollow">TypeScripts dokumentation om Record</a> beskriver typen som ett objekt vars nycklar och värden följer de typer du anger. <strong>Jag tycker att Record är den tydligaste starten</strong> när en webbplats behöver ett enkelt uppslag mellan strängar och strukturerade värden.</p>
<p>Men <code>Record<string product></string></code> säger inte att varje möjlig sträng faktiskt finns i objektet. Det är skillnaden mellan typen av ett värde och förekomsten av en viss nyckel, och den kan bli viktig när koden får data utifrån.</p>

<h2 id="en-nyckelunion-gor-obligatoriska-poster-tydliga">En nyckelunion gör obligatoriska poster tydliga</h2>
<p>Om uppsättningen nycklar är känd i förväg kan du låta typen fånga ett vanligt misstag: att glömma en post eller stava en nyckel fel. Här fungerar en union av strängliteraler bättre än en generell strängnyckel.</p>
<pre><code>type Locale = "sv" | "en";

const labels: Record<locale string> = {
  sv: "Lägg i varukorgen",
  en: "Add to cart",
};</locale></code></pre>
<p>Med den här typen förväntar sig TypeScript båda språken. Om <code>en</code> saknas i objektet eller ersätts med exempelvis <code>eng</code>, får du ett typfel. <strong>Det passar för fasta konfigurationer</strong>, som språktexter eller namngivna statusar, men inte för produktkoder som förändras över tid.</p>
<p>Det är också här en vanlig sammanblandning uppstår: en strängindexsignatur eller <code>Record<string v></string></code> beskriver ett öppet nyckelutrymme, medan en union av några få nycklar begränsar vilka namn som är tillåtna. TypeScripts avsnitt om <a href="https://www.typescriptlang.org/docs/handbook/2/objects.html" target="_blank" rel="noopener noreferrer nofollow">indexsignaturer</a> tar även upp att alla egenskaper i objektet måste passa den angivna värdetypen.</p>

<h2 id="map-ar-battre-nar-nycklarna-inte-ar-vanliga-strangar">Map är bättre när nycklarna inte är vanliga strängar</h2>
<p>Två objekt kan ha samma innehåll men ändå behöva fungera som två olika nycklar. Ett vanligt JavaScript-objekt omvandlar nycklar till strängar, medan <code>Map</code> kan använda objekt som nycklar och skilja mellan deras identiteter.</p>
<pre><code>const firstUser = { id: 7 };
const secondUser = { id: 7 };

const sessions = new Map<object string>();
sessions.set(firstUser, "session-a");

sessions.get(firstUser);  // "session-a"
sessions.get(secondUser); // undefined</object></code></pre>
<p>Trots att objekten har samma egenskaper är de två separata objekt, så uppslaget med <code>secondUser</code> hittar ingen post. <a href="https://tc39.es/ecma262/2024/multipage/keyed-collections.html" target="_blank" rel="noopener noreferrer nofollow">ECMAScript-specifikationen</a> beskriver Map som en samling nyckel- och värdepar där nyckeln kan vara ett godtyckligt värde.</p>
<p>Map har också inbyggda metoder för att lägga till, läsa, ta bort och iterera poster. Jag skulle välja Map för en tillfällig cache där nyckeln är ett objekt eller där poster ofta läggs till och tas bort; för en enkel JSON-liknande samling med textnycklar är ett objekt oftast smidigare.</p>

<h2 id="ett-uppslag-kan-saknas-aven-nar-typen-sager-product">Ett uppslag kan saknas även när typen säger Product</h2>
<p>En rad som <code>products[sku]</code> ser självklar ut, men en godtycklig SKU behöver inte finnas i objektet. Med strängindexering kan TypeScript utan extra inställning behandla resultatet som värdetypen, trots att körningen kan ge <code>undefined</code>.</p>
<p>Aktivera <code>noUncheckedIndexedAccess</code> om du vill att typkontrollen ska ta hänsyn till att en indexerad nyckel kan saknas. Då blir det lättare att upptäcka kod som försöker läsa exempelvis <code>product.name</code> innan uppslaget har kontrollerats.</p>
<table>
  <tbody>
    <tr>
      <th scope="col">Situation</th>
      <th scope="col">Trolig följd</th>
      <th scope="col">Gör så här</th>
    </tr>
    <tr>
      <td>Nyckeln är en känd strängunion</td>
      <td>En bortglömd post kan ge typfel.</td>
      <td>Använd <code>Record<keyunion value></keyunion></code>.</td>
    </tr>
    <tr>
      <td>Nyckeln kommer från ett formulär eller API</td>
      <td>Uppslaget kan saknas och ge <code>undefined</code>.</td>
      <td>Kontrollera resultatet innan värdet används.</td>
    </tr>
    <tr>
      <td>Nyckeln är ett objekt</td>
      <td>Ett vanligt objekt passar inte för identitetsbaserade uppslag.</td>
      <td>Använd <code>Map<key value></key></code>.</td>
    </tr>
    <tr>
      <td>Objektet innehåller både fasta fält och extra nycklar</td>
      <td>En indexsignatur kan tvinga de fasta fälten att ha samma värdetyp.</td>
      <td>Lägg de dynamiska posterna i en egen egenskap.</td>
    </tr>
  </tbody>
</table>
<p>En säker läsning kan se ut så här:</p>
<pre><code>const product = products[sku];

if (product === undefined) {
  return "Produkten kunde inte hittas";
}

return product.name;</code></pre>
<p><a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-2.html" target="_blank" rel="noopener noreferrer nofollow">TypeScripts versionsinformation för 4.2</a> visar varför ett uppslag kan bli <code>undefined</code> när en nyckel saknas, och hur <code>noUncheckedIndexedAccess</code> gör den möjligheten synlig i typen. Det är särskilt användbart när en nyckel hämtas från URL:en eller en sökruta.</p>

<h2 id="hall-fasta-falt-atskilda-fran-dynamiska-nycklar">Håll fasta fält åtskilda från dynamiska nycklar</h2>
<p>En indexsignatur gäller alla egenskaper som matchar nyckeltypen. Om ett objekt både har ett fast fält som <code>name: string</code> och godtyckliga numeriska värden kan typen därför bli svår att få ihop.</p>
<pre><code>type ProductStats = {
  name: string;
  counts: Record<string number>;
};</string></code></pre>
<p>Här ligger produktens namn och de dynamiska räknarna på olika nivåer. <strong>Den uppdelningen gör typen lättare att läsa</strong> och hindrar att ett fast textfält blandas ihop med de numeriska värdena i dictionaryn. Samma mönster passar när en inställning har några obligatoriska egenskaper plus en samling extra data.</p>
<p>För data som skickas som JSON bör typen dessutom inte ses som validering av innehållet. TypeScript kontrollerar koden vid kompilering, men den kan inte på egen hand bevisa att ett externt svar verkligen följer typen när det körs. Kontrollera därför data vid gränsen där den kommer in, innan den används som en dictionary.</p>

<h2 id="valj-den-struktur-som-gor-fel-synliga">Välj den struktur som gör fel synliga</h2>
<p>Om nycklarna är kända i förväg ger en begränsad <code>Record</code> tydligast skydd mot saknade poster. För varierande textnycklar är <code>Record<string value></string></code> bekvämt, men hantera saknade uppslag; välj Map när nycklarna behöver vara objekt eller när Map-metoderna passar arbetsflödet.</p>
<p>För en webbplatskatalog med produktkoder skulle jag välja ett objekt med en tydlig värdetyp och kontrollera uppslagets resultat. För sessionsdata som indexeras med användarobjekt skulle jag välja Map. Den bästa dictionaryn är den som gör det svårt att använda ett saknat eller feltypat värde av misstag.</p>]]></content:encoded>
      
      <category>Programmering och AI</category>
      <media:thumbnail url="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/thumbnail/ad176e14e992d9d2cca96cbe780670c0/sa-valjer-du-mellan-record-och-map-i-typescript.webp"/>
      <pubDate>Mon, 09 Nov 2026 12:51:00 +0100</pubDate>
    </item>
    <item>
      <title>Så listar du databaser i PostgreSQL med psql eller SQL</title>
      <link>https://jelks.nu/sa-listar-du-databaser-i-postgresql-med-psql-eller-sql</link>
      <description>Se hur du listar databaser i PostgreSQL med \l, psql -l eller SQL. Lär dig filtrera bort mallar och felsöka saknade databaser.</description>
      <content:encoded><![CDATA[<?xml encoding="utf-8" ?><p>N&auml;r du sitter i `psql` och beh&ouml;ver hitta r&auml;tt databas &auml;r kommandot oftast bara tv&aring; tecken l&aring;ngt: `\l`. Det visar databaserna p&aring; servern, men en rad i listan betyder inte automatiskt att ditt konto kan ansluta till databasen.</p><p><img src="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/post_image/5fdafc3d6295209eef0843c6648bfb4f/postgresql-psql-terminal-list-databases-command-l.webp" class="image article-image" loading="lazy" alt="pgAdmin visar en lista &ouml;ver tabeller och vyer i en PostgreSQL-databas. H&auml;r ser vi hur man kan lista databaser."></p><div class="short-summary">
  <h2 id="snabbaste-vagen-ar-l-i-psql">Snabbaste v&auml;gen &auml;r \l i psql</h2>
  <ul>
    <li><strong>I psql:</strong> k&ouml;r <code>\l</code> eller <code>\list</code> f&ouml;r att visa databaser.</li>
    <li><strong>I terminalen:</strong> k&ouml;r <code>psql -l</code> f&ouml;r att lista och avsluta.</li>
    <li><strong>I en SQL-editor:</strong> fr&aring;ga systemkatalogen <code>pg_database</code>; psql-kommandon med omv&auml;nt snedstreck fungerar inte d&auml;r.</li>
    <li><strong>F&ouml;r anv&auml;ndardatabaser:</strong> filtrera bort mallar med <code>WHERE datistemplate = false</code>.</li>
    <li><strong>Om en databas saknas:</strong> kontrollera server, port och anslutningsuppgifter innan du antar att databasen &auml;r raderad.</li>
  </ul>
</div><h2 id="valj-kommando-efter-var-du-kor-det">V&auml;lj kommando efter var du k&ouml;r det</h2><p>St&aring;r prompten i <code>psql</code>? Skriv <code>\l</code> och tryck Enter. Resultatet inneh&aring;ller normalt namn, &auml;gare, teckenkod och &aring;tkomstinformation, s&aring; du f&aring;r mer &auml;n en ren namnlista.</p><p>Kommandot b&ouml;rjar med ett omv&auml;nt snedstreck eftersom det &auml;r ett <strong>psql-meta-kommando</strong>, allts&aring; ett kommando som tolkas av klientprogrammet och inte skickas som vanlig SQL till servern. D&auml;rf&ouml;r fungerar <code>\l</code> inte i exempelvis en applikations SQL-editor.</p><p>Vill du f&aring; listan fr&aring;n terminalen utan att stanna kvar i interaktivt l&auml;ge, anv&auml;nd <code>psql -l</code>. <a href="https://jelks.nu/vilken-port-anvander-postgresql-sa-hittar-du-ratt">PostgreSQL</a>-dokumentationen beskriver <a href="https://www.postgresql.org/docs/18/app-psql.html" target="_blank" rel="noopener noreferrer nofollow">psql:s listalternativ</a> som ett s&auml;tt att visa tillg&auml;ngliga databaser och sedan avsluta.</p><h2 id="sql-fragan-fungerar-aven-i-en-vanlig-frageeditor">SQL-fr&aring;gan fungerar &auml;ven i en vanlig fr&aring;geeditor</h2><p>I ett GUI-verktyg eller i kod anv&auml;nder du vanlig SQL mot systemkatalogen <code>pg_database</code>. En minimal fr&aring;ga ser ut s&aring; h&auml;r:</p><pre><code>SELECT datname
FROM pg_database
ORDER BY datname;</code></pre><p>Vill du slippa mall-databaser i resultatet, l&auml;gg till villkoret <code>WHERE datistemplate = false</code>. Det &auml;r anv&auml;ndbart n&auml;r du inventerar programmets egna databaser, men beh&aring;ll mallarna om uppgiften &auml;r att granska allt som finns i klustret. Katalogen delas av klustrets databaser, vilket g&ouml;r den l&auml;mplig f&ouml;r den h&auml;r typen av &ouml;versikt.</p><pre><code>SELECT datname
FROM pg_database
WHERE datistemplate = false
ORDER BY datname;</code></pre><p>Jag tycker att det &auml;r b&auml;st att anv&auml;nda <code>\l</code> f&ouml;r en snabb manuell kontroll och SQL-fr&aring;gan n&auml;r resultatet ska filtreras eller anv&auml;ndas vidare. PostgreSQL beskriver kolumnerna, bland annat <code>datname</code> och <code>datistemplate</code>, i dokumentationen om <a href="https://www.postgresql.org/docs/18/catalog-pg-database.html" target="_blank" rel="noopener noreferrer nofollow">systemkatalogen pg_database</a>.</p><h2 id="mall-databaser-ar-inte-nodvandigtvis-dina-projekt">Mall-databaser &auml;r inte n&ouml;dv&auml;ndigtvis dina projekt</h2><p>En lista kan inneh&aring;lla databaser som <code>template0</code> och <code>template1</code>. De har en funktion som mallar n&auml;r nya databaser skapas, s&aring; deras n&auml;rvaro betyder inte att ett projekt har r&aring;kat skapa extra databaser.</p><p>F&auml;ltet <code>datistemplate</code> talar om huruvida en databas &auml;r markerad som mall. Filtreringen ovan ger d&auml;rf&ouml;r en mer relevant lista n&auml;r fr&aring;gan &auml;r &rdquo;vilka databaser h&ouml;r till mina appar?&rdquo;, medan den fullst&auml;ndiga listan passar b&auml;ttre vid serveradministration.</p><p>En viktig skillnad: <strong>synlighet och anslutningsr&auml;tt &auml;r olika saker</strong>. Du kan se en databas i katalogen utan att ha beh&ouml;righet att ansluta till den. PostgreSQLs funktion <code>has_database_privilege</code> kan kontrollera exempelvis <code>CONNECT</code>, vilket f&ouml;rklaras i dokumentationen om <a href="https://www.postgresql.org/docs/18/functions-info.html" target="_blank" rel="noopener noreferrer nofollow">informationsfunktioner och beh&ouml;righetskontroller</a>.</p><h2 id="en-saknad-databas-pekar-ofta-pa-fel-server-eller-port">En saknad databas pekar ofta p&aring; fel server eller port</h2><p>Om databasen du v&auml;ntar dig inte syns, b&ouml;rja med anslutningen innan du fels&ouml;ker sj&auml;lva databasen. Ett vanligt misstag &auml;r att kontrollera r&auml;tt databasnamn mot fel instans, till exempel en lokal server i st&auml;llet f&ouml;r en molnserver eller en annan port.</p><table>
  <tbody>
    <tr>
      <th scope="col">Situation</th>
      <th scope="col">Trolig orsak</th>
      <th scope="col">N&auml;sta steg</th>
    </tr>
    <tr>
      <td>Listan saknar databasen du v&auml;ntar dig</td>
      <td>Klienten &auml;r ansluten till en annan server, port eller milj&ouml;</td>
      <td>Kontrollera v&auml;rdnamn, port och anv&auml;ndare i anslutningen</td>
    </tr>
    <tr>
      <td>Databasen syns, men anslutningen nekas</td>
      <td>Kontot saknar <code>CONNECT</code>-beh&ouml;righet eller anslutning blockeras av serverregler</td>
      <td>Be administrat&ouml;ren kontrollera beh&ouml;righet och serverns anslutningsregler</td>
    </tr>
    <tr>
      <td><code>\l</code> ger syntaxfel i SQL-editorn</td>
      <td>Meta-kommandot k&ouml;rs utanf&ouml;r <code>psql</code></td>
      <td>K&ouml;r SQL-fr&aring;gan mot <code>pg_database</code> i st&auml;llet</td>
    </tr>
    <tr>
      <td>Kommandot <code>psql</code> hittas inte</td>
      <td>Klienten saknas eller finns inte i systemets s&ouml;kv&auml;g</td>
      <td>&Ouml;ppna PostgreSQL:s installerade SQL-skal eller konfigurera s&ouml;kv&auml;gen till klienten</td>
    </tr>
  </tbody>
</table><p>Den h&auml;r kontrollen skiljer mellan tv&aring; problem som l&auml;tt blandas ihop: databasen kan finnas men vara otillg&auml;nglig f&ouml;r ditt konto, eller s&aring; kan klienten visa ett helt annat kluster. Om listan verkar fel &auml;r det d&auml;rf&ouml;r ofta mer tr&auml;ffs&auml;kert att verifiera anslutningsm&aring;let &auml;n att direkt &auml;ndra databasinst&auml;llningar.</p><h2 id="hall-kommandot-enkelt-tills-du-vet-vad-listan-ska-anvandas-till">H&aring;ll kommandot enkelt tills du vet vad listan ska anv&auml;ndas till</h2><p>F&ouml;r en snabb kontroll r&auml;cker <code>\l</code>. F&ouml;r ett skript eller en SQL-editor passar fr&aring;gan mot <code>pg_database</code>, och ett filter p&aring; <code>datistemplate</code> g&ouml;r listan mer l&auml;ttl&auml;st n&auml;r mallarna inte &auml;r relevanta.</p><p>Om du ser databasen men inte kan &ouml;ppna den, fels&ouml;k beh&ouml;righet separat fr&aring;n listningen. Det sparar tid och minskar risken att behandla ett anslutningsproblem som om databasen saknades.</p>]]></content:encoded>
      
      <category>Databaser och SQL</category>
      <media:thumbnail url="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/thumbnail/97bd6e5dfc5bf6e0b9ca2f6cea9c50e0/sa-listar-du-databaser-i-postgresql-med-psql-eller-sql.webp"/>
      <pubDate>Mon, 09 Nov 2026 09:23:00 +0100</pubDate>
    </item>
    <item>
      <title>Ta bort element ur en lista i Python utan att missa något</title>
      <link>https://jelks.nu/ta-bort-element-ur-en-lista-i-python-utan-att-missa-nagot</link>
      <description>Lär dig ta bort element ur en lista i Python med remove(), pop() och list comprehension. Se hur du hanterar dubbletter och saknade värden.</description>
      <content:encoded><![CDATA[<?xml encoding="utf-8" ?><p>N&auml;r en lista inneh&aring;ller fel post, en f&ouml;r m&aring;nga kopior eller ett element p&aring; fel plats beh&ouml;ver du v&auml;lja hur borttagningen ska g&aring; till. Oftast r&auml;cker <code>remove()</code>, men metoden tar bara bort den f&ouml;rsta matchningen och kan ge ett fel om v&auml;rdet saknas.</p><p><img src="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/post_image/f0ca70f57c6f477cd47a8a78ac8264f2/python-kod-som-visar-remove-pop-del-och-list-comprehension-for-att-ta-bort-element-ur-listor.webp" class="image article-image" loading="lazy" alt="Bilden visar hur man kan ta bort element fr&aring;n en lista i Python med metoder som remove(), pop() och del statement. En soptunna symboliserar borttagning."></p><div class="short-summary">
  <h2 id="valj-metod-efter-vad-du-vet-om-elementet">V&auml;lj metod efter vad du vet om elementet</h2>
  <ul>
    <li><strong>K&auml;nt v&auml;rde:</strong> anv&auml;nd <code>remove()</code> f&ouml;r att ta bort den f&ouml;rsta matchningen.</li>
    <li><strong>K&auml;nt index:</strong> anv&auml;nd <code>pop()</code> om du beh&ouml;ver f&aring; tillbaka elementet, eller <code>del</code> om du inte beh&ouml;ver det.</li>
    <li><strong>Alla matchningar:</strong> skapa en ny lista med en list comprehension.</li>
    <li><strong>S&auml;ker mot saknat v&auml;rde:</strong> kontrollera f&ouml;rst med <code>in</code>, eller f&aring;nga <code>ValueError</code>.</li>
  </ul>
</div><h2 id="ta-bort-efter-varde-med-remove">Ta bort efter v&auml;rde med remove()</h2><p>Om du vet vilket v&auml;rde som ska bort men inte var det st&aring;r, &auml;r <code>remove()</code> det raka valet. Metoden s&ouml;ker fr&aring;n b&ouml;rjan och tar bort <strong>den f&ouml;rsta matchningen</strong>, s&aring; upprepade v&auml;rden kr&auml;ver ett extra beslut.</p><pre><code>sprak = ["<a href="https://jelks.nu/python-enum-strenum-och-flag-sa-valjer-du-ratt">Python</a>", "Java", "<a href="https://jelks.nu/sa-fungerar-pass-i-python-och-nar-du-ska-anvanda-det">Python</a>", "Ruby"]
sprak.remove("Python")

print(sprak)
# ["Java", "Python", "Ruby"]</code></pre><p>Finns v&auml;rdet inte i listan f&aring;r du ett <code>ValueError</code>. Om det &auml;r normalt att v&auml;rdet saknas kan du skydda anropet med en medlemskontroll:</p><pre><code>if "Go" in sprak:
    sprak.remove("Go")</code></pre><p>Kontrollen g&ouml;r koden tydlig, men listan s&ouml;ks igen n&auml;r <code>remove()</code> k&ouml;rs. Jag tycker att det &auml;r en rimlig avv&auml;gning n&auml;r saknade v&auml;rden &auml;r vanliga och ett undantag skulle st&ouml;ra fl&ouml;det. &Auml;r det d&auml;remot ett fel att v&auml;rdet saknas, l&aring;t undantaget synas eller hantera det uttryckligen. <a href="https://docs.python.org/3/tutorial/datastructures.html" target="_blank" rel="noopener noreferrer nofollow">Pythons dokumentation om listor</a> beskriver b&aring;de beteendet och felet.</p><h2 id="anvand-index-nar-positionen-ar-det-viktiga">Anv&auml;nd index n&auml;r positionen &auml;r det viktiga</h2><p>Om du redan har positionen i listan beh&ouml;ver du inte s&ouml;ka efter ett v&auml;rde. <code>pop(index)</code> tar bort elementet p&aring; den positionen och <strong>returnerar det</strong>, medan <code>del</code> raderar elementet utan att l&auml;mna tillbaka det.</p><pre><code>filer = ["rapport.csv", "utkast.txt", "bild.png"]

borttagen = filer.pop(1)
print(borttagen)  # utkast.txt

del filer[0]
print(filer)      # ["bild.png"]</code></pre><p>V&auml;lj <code>pop()</code> n&auml;r elementet ska anv&auml;ndas efter borttagningen, till exempel n&auml;r en uppgift h&auml;mtas ur en k&ouml; eller ett objekt tas fr&aring;n en arbetslista. V&auml;lj <code>del</code> n&auml;r du bara vill radera en position eller ett intervall, som <code>del filer[1:3]</code>. Ett index utanf&ouml;r listans gr&auml;nser leder till <code>IndexError</code>, s&aring; kontrollera att indexet verkligen finns om det kommer fr&aring;n anv&auml;ndardata.</p><table>
  <tbody>
    <tr>
      <th scope="col">Situation</th>
      <th scope="col">Trolig orsak eller f&ouml;ljd</th>
      <th scope="col">G&ouml;r s&aring; h&auml;r</th>
    </tr>
    <tr>
      <td>Du vet v&auml;rdet, men inte positionen</td>
      <td><code>remove()</code> tar den f&ouml;rsta matchningen</td>
      <td>Anv&auml;nd <code>remove(v&auml;rde)</code></td>
    </tr>
    <tr>
      <td>Du beh&ouml;ver det borttagna elementet</td>
      <td><code>del</code> returnerar inget element</td>
      <td>Anv&auml;nd <code>pop(index)</code></td>
    </tr>
    <tr>
      <td>V&auml;rdet kan saknas</td>
      <td><code>remove()</code> kan ge <code>ValueError</code></td>
      <td>Kontrollera med <code>in</code> eller hantera undantaget</td>
    </tr>
    <tr>
      <td>Varje post som matchar villkoret ska bort</td>
      <td>Ett enstaka <code>remove()</code> l&auml;mnar senare matchningar kvar</td>
      <td>Filtrera fram en ny lista</td>
    </tr>
  </tbody>
</table><h2 id="filtrera-fram-en-ny-lista-nar-flera-element-ska-bort">Filtrera fram en ny lista n&auml;r flera element ska bort</h2><p>Tre etiketter med samma namn i en lista kan se ut som ett jobb f&ouml;r flera <code>remove()</code>-anrop. Men n&auml;r borttagningen beror p&aring; ett villkor blir en list comprehension oftast l&auml;ttare att l&auml;sa och s&auml;krare &auml;n att &auml;ndra listan medan du g&aring;r igenom den.</p><pre><code>etiketter = ["klar", "utkast", "klar", "granska"]
etiketter = [etikett for etikett in etiketter
             if etikett != "klar"]

print(etiketter)
# ["utkast", "granska"]</code></pre><p>Uttrycket bygger en ny lista och beh&aring;ller ordningen p&aring; de element som klarar villkoret. Det &auml;r praktiskt n&auml;r du tar bort alla likadana v&auml;rden eller rensar poster enligt ett kriterium, exempelvis tomma str&auml;ngar. Om andra delar av programmet beh&ouml;ver se &auml;ndringen i samma listobjekt, tilldela resultatet via en hel slice i st&auml;llet:</p><pre><code>etiketter[:] = [etikett for etikett in etiketter
                if etikett != "klar"]</code></pre><p>Den skillnaden handlar om listans identitet, inte bara inneh&aring;llet. En annan variabel som pekar p&aring; samma lista ser &auml;ndringen n&auml;r slice-tilldelningen anv&auml;nds, medan vanlig tilldelning l&aring;ter den gamla listan vara kvar. <a href="https://docs.python.org/3/tutorial/datastructures.html" target="_blank" rel="noopener noreferrer nofollow">Python-dokumentationen</a> rekommenderar ocks&aring; att skapa en ny lista framf&ouml;r att &auml;ndra listan under iteration.</p><h2 id="att-ta-bort-under-en-loop-kan-hoppa-over-element">Att ta bort under en loop kan hoppa &ouml;ver element</h2><p>En loop som raderar poster ur listan den g&aring;r igenom kan ge ett resultat som &ouml;verraskar. N&auml;r ett element f&ouml;rsvinner flyttas senare element ett steg, medan loopens position g&aring;r vidare, och d&aring; kan n&auml;sta tr&auml;ff passera obem&auml;rkt.</p><pre><code>tal = [2, 4, 6, 7]

for nummer in tal:
    if nummer % 2 == 0:
        tal.remove(nummer)

print(tal)
# Kan l&auml;mna kvar ett j&auml;mnt tal</code></pre><p>F&ouml;r att ta bort alla j&auml;mna tal &auml;r filtrering tydligare:</p><pre><code>tal = [nummer for nummer in tal if nummer % 2 != 0]</code></pre><p>Om det ursprungliga listobjektet m&aring;ste beh&aring;llas, anv&auml;nd slice-tilldelning med samma villkor. D&aring; undviker du att iteratorn arbetar mot en lista som &auml;ndras mitt i genomg&aring;ngen.</p><h2 id="valj-metod-efter-vad-programmet-behover-bevara">V&auml;lj metod efter vad programmet beh&ouml;ver bevara</h2><p>Det enklaste valet &auml;r ofta det r&auml;tta: <code>remove()</code> f&ouml;r ett k&auml;nt v&auml;rde, <code>pop()</code> f&ouml;r en position vars element ska tas tillvara och en list comprehension n&auml;r flera poster ska filtreras bort. <strong>Kontrollera s&auml;rskilt dubbletter, saknade v&auml;rden och om listobjektet m&aring;ste beh&aring;lla sin identitet</strong>; de detaljerna avg&ouml;r om borttagningen blir f&ouml;ruts&auml;gbar &auml;ven n&auml;r listan f&ouml;r&auml;ndras.</p>]]></content:encoded>
      
      <category>Programmering och AI</category>
      <media:thumbnail url="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/thumbnail/f39b5250a57fa82d0a0deeccbac01d06/ta-bort-element-ur-en-lista-i-python-utan-att-missa-nagot.webp"/>
      <pubDate>Mon, 09 Nov 2026 08:48:00 +0100</pubDate>
    </item>
    <item>
      <title>SQL-subqueries och skillnaden mellan IN, EXISTS och skalära frågor</title>
      <link>https://jelks.nu/sql-subqueries-och-skillnaden-mellan-in-exists-och-skalara-fragor</link>
      <description>Lär dig välja rätt SQL-subquery för ett värde, en lista eller en träffkontroll. Se när IN och EXISTS passar och undvik fallgropen med NULL. Läs guiden.</description>
      <content:encoded><![CDATA[<?xml encoding="utf-8" ?><p>N&auml;r en rapport beh&ouml;ver visa kunder vars orderv&auml;rde &ouml;verstiger genomsnittet kan en <strong>SQL-subquery</strong> l&ouml;sa det utan att f&ouml;rst skapa en separat tabell. Men r&auml;tt variant beror p&aring; om den inre fr&aring;gan ska ge ett enda v&auml;rde, en lista eller bara bekr&auml;fta att en matchning finns.</p><p><img src="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/post_image/685f03414c4239b3ccd1e7b60d197ceb/sql-subquery-diagram-inner-query-outer-query-exists-in-scalar-example.webp" class="image article-image" loading="lazy" alt="Diagram som f&ouml;rklarar SQL subquery. Visar resultattyper (skal&auml;r, rad, tabell), beroenden (korrelerad, icke-korrelerad) och var subqueries kan placeras (SELECT, FROM, JOIN, WHERE)."></p><div class="short-summary">
<h2 id="en-nastlad-fraga-fungerar-bast-nar-dess-uppgift-ar-tydlig">En n&auml;stlad fr&aring;ga fungerar b&auml;st n&auml;r dess uppgift &auml;r tydlig</h2>
<ul>
<li><strong>Ett v&auml;rde:</strong> anv&auml;nd en skal&auml;r subquery, till exempel f&ouml;r att j&auml;mf&ouml;ra med ett genomsnitt.</li>
<li><strong>En lista:</strong> anv&auml;nd ofta <code>IN</code> n&auml;r flera v&auml;rden kan matcha.</li>
<li><strong>En tr&auml;ffkontroll:</strong> <code>EXISTS</code> passar n&auml;r du vill hitta rader med relaterade poster.</li>
<li><strong>En fallgrop:</strong> <code>NOT IN</code> kan ge ov&auml;ntat resultat om listan inneh&aring;ller <code>NULL</code>.</li>
</ul>
</div><h2 id="valj-subquery-efter-vad-den-inre-fragan-ska-lamna-tillbaka">V&auml;lj subquery efter vad den inre fr&aring;gan ska l&auml;mna tillbaka</h2><p>En n&auml;stlad SQL-fr&aring;ga &auml;r mest l&auml;ttl&auml;st n&auml;r du f&ouml;rst best&auml;mmer dess jobb. Ska den leverera <strong>ett enda v&auml;rde</strong>, flera m&ouml;jliga v&auml;rden eller bara ett ja eller nej? Det avg&ouml;r vilken form som passar.</p><p>Anta att tabellen <code>orders</code> inneh&aring;ller kolumnerna <code>customer_id</code> och <code>amount</code>. En skal&auml;r subquery kan j&auml;mf&ouml;ra varje order med genomsnittet:</p><pre><code>SELECT customer_id, amount
FROM orders
WHERE amount &gt; (
  SELECT AVG(amount)
  FROM orders
);</code></pre><p>Den inre fr&aring;gan r&auml;knar fram ett v&auml;rde, och den yttre v&auml;ljer order &ouml;ver det v&auml;rdet. <strong>Om subqueryn i st&auml;llet returnerar flera rader</strong> fungerar en vanlig j&auml;mf&ouml;relse som <code>=</code> inte som t&auml;nkt; anv&auml;nd exempelvis <code>IN</code> eller bygg om fr&aring;gan.</p><h2 id="in-och-exists-svarar-pa-tva-olika-fragor">IN och EXISTS svarar p&aring; tv&aring; olika fr&aring;gor</h2><p>Tv&aring; SQL-fr&aring;gor kan se n&auml;stan likadana ut men uttrycka olika saker. <code>IN</code> fr&aring;gar om ett v&auml;rde finns i en lista; <code>EXISTS</code> fr&aring;gar om den inre fr&aring;gan hittar minst en rad.</p><p>Exempelvis kan du hitta kunder som har lagt minst en order s&aring; h&auml;r:</p><pre><code>SELECT c.customer_id
FROM customers AS c
WHERE EXISTS (
  SELECT 1
  FROM orders AS o
  WHERE o.customer_id = c.customer_id
);</code></pre><p>Vill du hellre matcha mot en lista med kund-ID:n kan <code>IN</code> vara mer direkt. Jag tycker att <strong><code>EXISTS</code> ofta uttrycker avsikten tydligast</strong> n&auml;r fr&aring;gan g&auml;ller om en relaterad rad finns, s&auml;rskilt eftersom du d&aring; inte beh&ouml;ver v&auml;lja ut sj&auml;lva v&auml;rdet fr&aring;n den inre fr&aring;gan. Databasmotorn kan dessutom ofta sluta leta n&auml;r den hittar en matchning, enligt <a href="https://www.postgresql.org/docs/current/functions-subquery.html" target="_blank" rel="noopener noreferrer nofollow">PostgreSQL-dokumentationen om subquery-uttryck</a>.</p><h2 id="en-null-i-not-in-listan-kan-sla-ut-alla-traffar">En NULL i NOT IN-listan kan sl&aring; ut alla tr&auml;ffar</h2><p>Resultatet kan bli tomt utan att fr&aring;gan ger ett tydligt fel. Om den inre listan inneh&aring;ller <code>NULL</code> kan villkoret <code>NOT IN</code> bli ok&auml;nt f&ouml;r rader som du v&auml;ntade dig skulle passera.</p><p>F&ouml;rest&auml;ll dig att du vill lista kunder utan order. Om ordertabellens <code>customer_id</code> inneh&aring;ller en null-post kan det h&auml;r villkoret st&auml;lla till det:</p><pre><code>WHERE c.customer_id NOT IN (
  SELECT o.customer_id
  FROM orders AS o
)</code></pre><p>En tydlig alternativ formulering &auml;r <code>NOT EXISTS</code>, d&auml;r kopplingen mellan kund och order st&aring;r inne i subqueryn:</p><pre><code>WHERE NOT EXISTS (
  SELECT 1
  FROM orders AS o
  WHERE o.customer_id = c.customer_id
)</code></pre><p><strong>Praktisk tumregel:</strong> om v&auml;rdena i den inre fr&aring;gan kan vara <code>NULL</code>, v&auml;lj <code>NOT EXISTS</code> eller filtrera bort nullv&auml;rden uttryckligen innan du anv&auml;nder <code>NOT IN</code>. Det h&auml;r &auml;r en fr&aring;ga om korrekt resultat, inte bara kodstil.</p><h2 id="korrelaterade-subqueries-behover-en-tydlig-koppling">Korrelaterade subqueries beh&ouml;ver en tydlig koppling</h2><p>I exemplet med kunder och order anv&auml;nder den inre fr&aring;gan ett v&auml;rde fr&aring;n den yttre fr&aring;gan: <code>c.customer_id</code>. Det g&ouml;r subqueryn <strong>korrelerad</strong>. Den beskriver allts&aring; ett samband mellan raderna, snarare &auml;n en frist&aring;ende lista.</p><p>En korrelerad fr&aring;ga kan vara l&auml;tt att l&auml;sa n&auml;r varje yttre rad ska testas mot relaterade poster. Men anta inte att databasen bokstavligen k&ouml;r den inre fr&aring;gan separat f&ouml;r varje rad. Optimeraren kan omforma planen, och utfallet beror p&aring; databasmotor, index och datam&auml;ngd. <a href="https://learn.microsoft.com/en-us/sql/relational-databases/performance/subqueries?view=sql-server-ver17" target="_blank" rel="noopener noreferrer nofollow">Microsoft Learn om subqueries i SQL Server</a> beskriver att subqueries och motsvarande joins ofta kan ge likv&auml;rdiga planer, men att vissa existenskontroller kan gynnas av en annan formulering.</p><p>Om fr&aring;gan blir l&aring;ng eller sv&aring;r att f&ouml;lja kan en join eller en CTE, allts&aring; en namngiven del-fr&aring;ga med <code>WITH</code>, g&ouml;ra strukturen tydligare. Kontrollera d&aring; att omskrivningen inte &auml;ndrar antalet rader, exempelvis genom att en join skapar flera matchningar per kund.</p><h2 id="felsok-resultatet-innan-du-jagar-prestanda">Fels&ouml;k resultatet innan du jagar prestanda</h2><p>N&auml;r svaret ser fel ut &auml;r det frestande att b&ouml;rja optimera. B&ouml;rja hellre med att kontrollera <strong>vilket resultat den inre fr&aring;gan faktiskt ger</strong>, eftersom b&aring;de fel kardinalitet och nullv&auml;rden kan &auml;ndra den yttre fr&aring;gans urval.</p><table>
<tbody>
<tr><th>Situation</th><th>Trolig orsak</th><th>G&ouml;r s&aring; h&auml;r</th></tr>
<tr><td>J&auml;mf&ouml;relsen med <code>=</code> ger fel eller avbryts</td><td>Subqueryn returnerar fler &auml;n ett v&auml;rde</td><td>Kontrollera om villkoret ska anv&auml;nda <code>IN</code>, <code>EXISTS</code> eller en aggregering</td></tr>
<tr><td><code>NOT IN</code> ger ov&auml;ntat f&aring; eller inga rader</td><td>Den inre listan kan inneh&aring;lla <code>NULL</code></td><td>Byt till <code>NOT EXISTS</code> eller filtrera bort nullv&auml;rden</td></tr>
<tr><td>Samma kund syns flera g&aring;nger efter omskrivning till join</td><td>Flera orderrader matchar samma kund</td><td>Anv&auml;nd <code>EXISTS</code> om du bara beh&ouml;ver testa f&ouml;rekomst</td></tr>
<tr><td>Fr&aring;gan g&aring;r l&aring;ngsamt p&aring; stora tabeller</td><td>Planen kan sakna effektiv &aring;tkomst till kopplingskolumnen</td><td>Granska exekveringsplanen och kontrollera index p&aring; kolumnerna i villkoren</td></tr>
</tbody>
</table><p>En subquery &auml;r allts&aring; inte automatiskt l&aring;ngsam, och en join &auml;r inte automatiskt snabbare. <strong>J&auml;mf&ouml;r exekveringsplaner</strong> n&auml;r prestandan spelar roll, men s&auml;kerst&auml;ll f&ouml;rst att b&aring;da versionerna ger samma resultat.</p><h2 id="en-bra-subquery-gor-avsikten-synlig">En bra subquery g&ouml;r avsikten synlig</h2><p>Om den inre fr&aring;gan l&auml;mnar tillbaka ett enda ber&auml;knat v&auml;rde passar en skal&auml;r subquery; om du vill testa om relaterade rader finns &auml;r <code>EXISTS</code> ofta ett tydligt val. Vid uteslutning b&ouml;r m&ouml;jliga <code>NULL</code>-v&auml;rden f&aring; dig att granska <code>NOT IN</code> extra noga.</p><p>N&auml;r en SQL-fr&aring;ga k&auml;nns som en l&aring;da i en l&aring;da, b&ouml;rja med att k&ouml;ra den inre delen separat och se vad den faktiskt returnerar. D&aring; blir det l&auml;ttare att avg&ouml;ra om problemet ligger i v&auml;rdet, listan eller kopplingen till den yttre fr&aring;gan.</p>]]></content:encoded>
      
      <category>Databaser och SQL</category>
      <media:thumbnail url="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/thumbnail/3856cf7ce832b99cca8bf9754e2dd14c/sql-subqueries-och-skillnaden-mellan-in-exists-och-skalara-fragor.webp"/>
      <pubDate>Sat, 07 Nov 2026 20:46:00 +0100</pubDate>
    </item>
    <item>
      <title>Installera Python på Ubuntu utan att störa systemet</title>
      <link>https://jelks.nu/installera-python-pa-ubuntu-utan-att-stora-systemet</link>
      <description>Installera Python på Ubuntu på rätt sätt. Lär dig när du ska använda apt, venv eller pipx och undvik problem med systemets Python.</description>
      <content:encoded><![CDATA[<?xml encoding="utf-8" ?><p><strong>Python 3 finns ofta redan p&aring; Ubuntu</strong>, men n&auml;r ett projekt beh&ouml;ver externa bibliotek kan det snabbt bli oklart vad som ska installeras och var. Vanligen r&auml;cker Ubuntus paket f&ouml;r att komma ig&aring;ng, men f&ouml;r projektets paket beh&ouml;ver du h&aring;lla milj&ouml;n separat fr&aring;n systemets Python.</p><p><img src="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/post_image/9ab3304069d6537fa9020f382d3de9ac/ubuntu-terminal-python-3-installation-virtual-environment-command-line.webp" class="image article-image" loading="lazy" alt="Python-logotyp, Ubuntu-logotyp och kod f&ouml;r att installera Python p&aring; Ubuntu."></p><div class="short-summary">
  <h2 id="hall-ubuntus-python-och-projektets-paket-atskilda">H&aring;ll Ubuntus Python och projektets paket &aring;tskilda</h2>
  <ul>
    <li><strong>Kontrollera f&ouml;rst:</strong> k&ouml;r <code>python3 --version</code>; Python 3 kan redan finnas installerat.</li>
    <li><strong>Installera verktygen:</strong> anv&auml;nd <code>sudo apt install python3-full</code> om du beh&ouml;ver en komplett utvecklingsmilj&ouml;.</li>
    <li><strong>F&ouml;r projekt:</strong> skapa en virtuell milj&ouml; med <code>python3 -m venv .venv</code>.</li>
    <li><strong>F&ouml;r frist&aring;ende appar:</strong> v&auml;lj <code>pipx</code> i st&auml;llet f&ouml;r att installera dem globalt med pip.</li>
    <li><strong>Skydda systemet:</strong> byt inte ut Ubuntus system-Python och anv&auml;nd inte <code>--break-system-packages</code> som genv&auml;g.</li>
  </ul>
</div><h2 id="kontrollera-forst-om-python-redan-finns">Kontrollera f&ouml;rst om Python redan finns</h2><p>Du &ouml;ppnar terminalen f&ouml;r att b&ouml;rja med ett skript, men beh&ouml;ver du verkligen installera sj&auml;lva spr&aring;ket? Skriv <code>python3 --version</code>; f&aring;r du ett versionsnummer &auml;r tolken redan tillg&auml;nglig, &auml;ven om st&ouml;d f&ouml;r virtuella milj&ouml;er eller paket saknas.</p><p>P&aring; Ubuntu &auml;r <code>python3</code> distributionspaketet som f&ouml;ljer Ubuntus standardversion av Python 3. Enligt <a href="https://ubuntu.com/developers/docs/howto/python-setup/" target="_blank" rel="noopener noreferrer nofollow">Ubuntus guide f&ouml;r Python-utvecklingsmilj&ouml;er</a> &auml;r systemets Python ocks&aring; beroende av andra Ubuntu-verktyg. <strong>Avinstallera eller ers&auml;tt d&auml;rf&ouml;r inte systemets Python</strong> f&ouml;r att f&aring; en annan version till ett projekt.</p><h2 id="installera-tolken-och-utvecklingsverktygen-med-apt">Installera tolken och utvecklingsverktygen med apt</h2><p>Om kontrollen visar att Python saknas, eller om du beh&ouml;ver fler utvecklingskomponenter, uppdaterar du f&ouml;rst paketlistan och installerar Ubuntus kompletta Python-paket:</p><pre><code>sudo apt update
sudo apt install python3-full</code></pre><p><code>python3-full</code> samlar tolken med bland annat st&ouml;d f&ouml;r virtuella milj&ouml;er och IDLE. Jag tycker att det &auml;r ett tydligt val f&ouml;r en nyb&ouml;rjare som vill komma ig&aring;ng med projekt utan att sj&auml;lv pussla ihop flera paket.</p><p>Kontrollera installationen med <code>python3 --version</code>. Om du specifikt beh&ouml;ver paket f&ouml;r utveckling mot C-bibliotek eller vill installera pip separat, v&auml;lj relevanta Ubuntu-paket via apt i st&auml;llet f&ouml;r att f&ouml;rs&ouml;ka &auml;ndra systemets Python med pip.</p><h2 id="en-virtuell-miljo-hindrar-projekt-fran-att-krocka">En virtuell milj&ouml; hindrar projekt fr&aring;n att krocka</h2><p>Ett projekt kan beh&ouml;va en viss version av ett bibliotek medan ett annat beh&ouml;ver en annan. Skapa en egen milj&ouml; i projektmappen s&aring; h&aring;ller du de <a href="https://jelks.nu/uppdatera-ett-npm-paket-utan-att-spracka-bygget">beroenden</a>a borta fr&aring;n Ubuntus systempaket:</p><pre><code>mkdir mitt-projekt
cd mitt-projekt
python3 -m venv .venv
source .venv/bin/activate
python -m pip install requests</code></pre><p>N&auml;r milj&ouml;n &auml;r aktiv pekar <code>python</code> och <code>pip</code> mot projektets egen installation. En snabb kontroll &auml;r <code>which python</code>; s&ouml;kv&auml;gen ska sluta med <code>mitt-projekt/.venv/bin/python</code>. Installera projektets bibliotek med <code>python -m pip</code>, s&aring; anv&auml;nder pip samma tolk som k&ouml;r koden.</p><p>St&ouml;ter du p&aring; <code>externally-managed-environment</code> beror det oftast p&aring; att pip f&ouml;rs&ouml;ker installera paket i Ubuntus systemmilj&ouml;. <a href="https://peps.python.org/pep-0668/" target="_blank" rel="noopener noreferrer nofollow">PEP 668</a> beskriver skyddet som hindrar den typen av &auml;ndringar; l&ouml;sningen f&ouml;r projektbibliotek &auml;r att skapa eller aktivera en virtuell milj&ouml;, inte att kringg&aring; sp&auml;rren.</p><h2 id="valj-apt-venv-eller-pipx-efter-vad-du-installerar">V&auml;lj apt, venv eller pipx efter vad du installerar</h2><p>Det &auml;r l&auml;tt att blanda ihop bibliotek till egen kod med f&auml;rdiga program som r&aring;kar vara skrivna i Python. V&auml;lj verktyg efter anv&auml;ndningen, s&aring; slipper du installera n&aring;got i fel milj&ouml;.</p><table>
  <tbody>
    <tr><th scope="col">Behov</th><th scope="col">V&auml;lj</th><th scope="col">Exempel</th></tr>
    <tr><td>Python eller ett systembibliotek</td><td><code>apt</code></td><td><code>sudo apt install python3-full</code></td></tr>
    <tr><td>Bibliotek till ett kodprojekt</td><td><code>venv</code> och pip</td><td><code>python -m pip install requests</code> i projektmilj&ouml;n</td></tr>
    <tr><td>Frist&aring;ende Python-program</td><td><code>pipx</code></td><td>Installera verktyget i en egen isolerad milj&ouml;</td></tr>
    <tr><td>Flera s&auml;rskilda Python-versioner</td><td><code>pyenv</code></td><td>V&auml;lj en version f&ouml;r ett visst projekt</td></tr>
  </tbody>
</table><p>F&ouml;r ett frist&aring;ende kommandoradsverktyg installerar du pipx med <code>sudo apt install pipx</code> och k&ouml;r sedan <code>pipx ensurepath</code>. Pipx passar d&auml;remot inte som ers&auml;ttning f&ouml;r projektets virtuella milj&ouml;: det hanterar appar separat, medan <code>venv</code> samlar bibliotek som din egen kod beh&ouml;ver.</p><p>Om projektet kr&auml;ver en Python-version som Ubuntu inte erbjuder i sina paket kan <code>pyenv</code> hantera flera tolkversioner. Jag skulle h&aring;lla mig till Ubuntus standardversion om projektet inte kr&auml;ver n&aring;got annat; f&auml;rre parallella versioner inneb&auml;r f&auml;rre m&ouml;jligheter att r&aring;ka k&ouml;ra koden med fel tolk.</p><h2 id="felsok-genom-att-kontrollera-vilken-python-som-kors">Fels&ouml;k genom att kontrollera vilken Python som k&ouml;rs</h2><p>N&auml;r ett paket verkar saknas trots att pip s&auml;ger att installationen lyckades pekar kommandona ofta p&aring; olika milj&ouml;er. Tabellen hj&auml;lper dig att hitta n&auml;sta steg utan att &auml;ndra systeminstallationen p&aring; m&aring;f&aring;.</p><table>
  <tbody>
    <tr><th scope="col">Situation</th><th scope="col">Trolig orsak</th><th scope="col">G&ouml;r s&aring; h&auml;r</th></tr>
    <tr><td><code>python3 --version</code> fungerar inte</td><td>Python 3 saknas eller kan inte hittas i s&ouml;kv&auml;gen</td><td>K&ouml;r <code>sudo apt update</code> och installera <code>python3-full</code>.</td></tr>
    <tr><td><code>python3 -m venv .venv</code> misslyckas</td><td>St&ouml;d f&ouml;r virtuella milj&ouml;er saknas</td><td>Installera <code>python3-full</code> fr&aring;n Ubuntus paketk&auml;llor och f&ouml;rs&ouml;k igen.</td></tr>
    <tr><td>pip visar <code>externally-managed-environment</code></td><td>Kommandot f&ouml;rs&ouml;ker &auml;ndra systemets Python</td><td>Skapa en virtuell milj&ouml; f&ouml;r projektet eller anv&auml;nd apt f&ouml;r ett Ubuntu-paket.</td></tr>
    <tr><td>Koden hittar inte ett installerat bibliotek</td><td>pip och programmet anv&auml;nder olika Python-milj&ouml;er</td><td>Aktivera projektets <code>.venv</code> och k&ouml;r <code>python -m pip</code>.</td></tr>
  </tbody>
</table><p>F&ouml;r fels&ouml;kning inne i milj&ouml;n r&auml;cker det ofta att k&ouml;ra <code>which python</code> och <code>python -m pip --version</code>. Om s&ouml;kv&auml;gen inte inneh&aring;ller projektets <code>.venv</code> har milj&ouml;n inte aktiverats, eller s&aring; k&ouml;rs ett annat terminalf&ouml;nster &auml;n det d&auml;r du aktiverade den.</p><h2 id="lat-ubuntu-skota-sin-egen-python">L&aring;t Ubuntu sk&ouml;ta sin egen Python</h2><p>Den s&auml;kraste uppdelningen &auml;r enkel: <strong>apt sk&ouml;ter Ubuntus paket, venv sk&ouml;ter projektets bibliotek och pipx sk&ouml;ter frist&aring;ende Python-appar</strong>. D&aring; kan du bygga och testa en webbplats eller ett skript utan att projektets beroenden kliver in i systemets verktyg.</p><p>Om du bara vill provk&ouml;ra ett f&ouml;rsta skript beh&ouml;ver du inte jaga en separat Python-version. Kontrollera tolken, skapa en projektmilj&ouml; n&auml;r du ska installera bibliotek och l&aring;t Ubuntus standardinstallation vara ifred.</p>]]></content:encoded>
      
      <category>Utvecklingsverktyg och arbetsflöden</category>
      <media:thumbnail url="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/thumbnail/4b9076930f3e8e745f61143946fef0bd/installera-python-pa-ubuntu-utan-att-stora-systemet.webp"/>
      <pubDate>Sat, 07 Nov 2026 18:12:00 +0100</pubDate>
    </item>
    <item>
      <title>Azure Bicep i praktiken - granska ändringar före distribution</title>
      <link>https://jelks.nu/azure-bicep-i-praktiken-granska-andringar-fore-distribution</link>
      <description>Lär dig använda Azure Bicep säkrare med lintning, what-if, versionslåsta moduler och tydlig hantering av resurser. Läs guiden inför nästa distribution.</description>
      <content:encoded><![CDATA[<p>När en ändring av ett lagringskonto eller ett nätverk ska ut i Azure vill du kunna granska vad som händer innan distributionen körs. <strong>Azure Bicep</strong> passar bra när miljön är Azure-baserad, men hur tryggt arbetsflödet blir beror på hur du validerar ändringar och hanterar resurser som inte längre finns i koden.</p>

<p><img src="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/post_image/fe59b95254415a2ea2b59b2b9bfbf44e/azure-bicep-kodredigerare-och-azure-resursdistribution-infrastruktur-som-kod.webp" class="image article-image" loading="lazy" alt="Diagram över en DevOps-pipeline. En utvecklare skriver IaC-kod för att provisionera AWS-tjänster som ELB, EC2, RDS och S3. Koden committas till Git, triggar en CI/CD-server som kör tester och provisionerar resurserna. Azure bicep är en del av denna pro..."></p>

<div class="short-summary">
  <h2 id="bicep-ger-tydlig-azure-kod-men-saker-distribution-kraver-en-genomtankt-pipeline">Bicep ger tydlig Azure-kod, men säker distribution kräver en genomtänkt pipeline</h2>
  <ul>
    <li><strong>Azure-fokus:</strong> Bicep är ett deklarativt språk för att beskriva Azure-resurser genom Azure Resource Manager.</li>
    <li><strong>Granska först:</strong> kör lintning, bygg och what-if innan en ändring distribueras.</li>
    <li><strong>Moduler:</strong> dela upp återanvändbara delar, men bestäm hur versioner ska låsas och uppdateras.</li>
    <li><strong>Deployment stacks:</strong> kan hantera resurser som en samlad enhet, men har begränsningar som påverkar förhandsgranskningen.</li>
  </ul>
</div>

<h2 id="bicep-passar-bast-nar-azure-ar-den-gemensamma-namnaren">Bicep passar bäst när Azure är den gemensamma nämnaren</h2>
<p>Om teamet arbetar nästan uteslutande i Azure slipper du ofta ett extra lager mellan infrastrukturen och plattformens egna resurstyper. Bicep beskriver önskat sluttillstånd deklarativt, och Azure Resource Manager sköter distributionen. <strong>Jag tycker att den tydliga kopplingen till Azure är språkets främsta styrka</strong>, men den blir också en avgränsning om du vill styra flera moln med samma verktyg.</p>
<p>Jämfört med ARM-mallar i JSON är Bicep lättare att läsa och skriva, samtidigt som filerna kompileras till ARM-mallar vid distribution. Terraform är ett närliggande alternativ när organisationen behöver ett verktyg för flera moln eller vill använda dess ekosystem. Väljer du Bicep bör det vara ett medvetet val av en Azure-nära lösning, inte ett antagande om att samma kod senare flyttas oförändrad till en annan plattform. <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/" target="_blank" rel="noopener noreferrer nofollow">Microsoft Learn-dokumentationen om Bicep</a> beskriver språket och dess distributionsomfattningar.</p>

<h2 id="en-pull-request-bor-fanga-fel-innan-nagon-trycker-pa-deploy">En pull request bör fånga fel innan någon trycker på deploy</h2>
<p>Ett lyckat bygge säger att Bicep-filen kan kompileras. Det bevisar inte att en ändring blir lämplig i den valda miljön. Därför bör pipeline-stegen ge olika skydd: <strong>lintning och bygg fångar kodproblem</strong>, medan validering och what-if hjälper teamet att bedöma distributionen.</p>
<ol>
  <li>Kör Bicep-lintern och bygg filerna i pull requesten. Rätta varningar som pekar på exempelvis saknade beroenden eller olämpliga resursdefinitioner.</li>
  <li>Kör validering mot rätt Azure-omfattning och kontrollera att pipeline-identiteten har de behörigheter distributionen kräver.</li>
  <li>Kör <code>what-if</code> och granska ändringarna, särskilt sådant som kan påverka nätverk, åtkomst eller beständiga data.</li>
  <li>Distribuera först efter godkännande och spara resultatet så att ändringen går att följa i efterhand.</li>
</ol>
<p>Här är det lätt att övertolka förhandsgranskningen. Microsoft beskriver i sin <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/deploy-what-if" target="_blank" rel="noopener noreferrer nofollow">vägledning för what-if</a> olika förändringstyper, däribland <code>Modify</code>, <code>NoChange</code> och <code>Deploy</code>. Det sista betyder att verktyget inte kan avgöra om egenskaper ändras, så resultatet är inte alltid ett entydigt besked om vad som kommer att ske.</p>
<p>För ett litet team räcker ofta ett godkännandesteg efter what-if. Om flera miljöer eller känsliga resurser ingår bör pull requesten dessutom visa vilka parametrar som används, så granskningen gäller rätt miljö och inte bara rätt Bicep-fil.</p>

<h2 id="moduler-hjalper-forst-nar-gransen-mellan-dem-ar-tydlig">Moduler hjälper först när gränsen mellan dem är tydlig</h2>
<p>En modul kan kapsla in en återanvändbar uppsättning resurser, exempelvis ett lagringskonto med tillhörande inställningar. Den gör huvudfilen mer lättöverskådlig, men för många små moduler kan i stället göra det svårt att följa var parametrar kommer ifrån. <strong>Dela därför efter en begriplig ansvarsenhet</strong>, inte efter varje enskild resurs.</p>
<p>En lokal modul är smidig när flera delar utvecklas tillsammans i samma kodbas. En modul från ett privat Azure Container Registry passar bättre när team behöver distribuera en gemensam komponent oberoende av applikationsrepo. Microsofts <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/modules" target="_blank" rel="noopener noreferrer nofollow">dokumentation om Bicep-moduler</a> beskriver bland annat registry-referenser och hur moduler används.</p>
<p>Bestäm samtidigt hur versionsändringar ska hanteras. Om en produktionsdistribution automatiskt tar den senaste modulversionen kan en ändring i ett centralt bibliotek få följder utan att applikationens egen kod ändras. <strong>Lås därför modulversionen i distributionen</strong> och uppdatera den genom en granskad ändring.</p>

<h2 id="deployment-stacks-har-en-viktig-begransning-vid-forhandsgranskning">Deployment stacks har en viktig begränsning vid förhandsgranskning</h2>
<p>Det låter tryggt att samla resurser i en deployment stack och låta Azure hantera deras livscykel som en enhet. Men om planen är att först granska ändringar med what-if finns en hake: Microsofts aktuella dokumentation anger att <strong>what-if ännu inte stöds direkt för deployment stacks</strong>.</p>
<p>Det påverkar särskilt borttagningar. En vanlig what-if-körning kan användas som separat förhandsgranskning, men den visar inte nödvändigtvis exakt samma effekt som när en stack hanterar resurser som inte längre finns i mallen. Microsoft listar också undantag för resurser som Key Vault-hemligheter, vilka stacken inte kan ta bort på vanligt sätt. Se <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/deployment-stacks-known-issues" target="_blank" rel="noopener noreferrer nofollow">kända begränsningar för deployment stacks</a> innan du låter automatisk rensning ingå i ett produktionsflöde.</p>
<table>
  <tbody>
    <tr>
      <th scope="col">Situation</th>
      <th scope="col">Trolig följd</th>
      <th scope="col">Gör så här</th>
    </tr>
    <tr>
      <td>What-if visar <code>Deploy</code> i stället för en tydlig egenskapsändring</td>
      <td>Resultatet räcker inte för att avgöra exakt vad som ändras.</td>
      <td>Granska resursen och distributionens parametrar innan godkännande.</td>
    </tr>
    <tr>
      <td>En resurs tas bort ur stackens mall</td>
      <td>Stackhantering kan påverka resurser som inte längre deklareras.</td>
      <td>Kontrollera stackens hantering av ohanterade resurser och granska listan före distribution.</td>
    </tr>
    <tr>
      <td>En Key Vault-hemlighet tas bort ur mallen</td>
      <td>Stacken kan inte ta bort själva hemligheten på vanligt sätt.</td>
      <td>Använd detach-läget där det behövs och hantera borttagningen separat.</td>
    </tr>
  </tbody>
</table>
<p>För resurser där oavsiktlig radering vore allvarlig bör stackens rensningsbeteende vara uttryckligt granskat och testat. En fin förhandsgranskning i en parallell distribution är inte en garanti för att stackens slutliga hantering blir identisk.</p>

<h2 id="parametrar-och-hemligheter-behover-egna-skydd">Parametrar och hemligheter behöver egna skydd</h2>
<p>En parameterfil är en bra plats för miljöspecifika värden som region, SKU eller resursnamn. Hemligheter hör däremot inte hemma som vanliga parametrar i kod eller loggar. Märk känsliga outputs med <code>@secure()</code>, och låt hemliga värden hämtas från en lämplig säker källa i stället för att bäddas in i repot.</p>
<p>Microsofts <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/best-practices" target="_blank" rel="noopener noreferrer nofollow">rekommenderade arbetssätt för Bicep</a> tar också upp parameterbeskrivningar, säkra standardvärden och implicita beroenden. I praktiken gör en kort beskrivning av varje parameter det lättare att granska om till exempel produktionsmiljön av misstag får en testinställning eller en oväntat dyr SKU.</p>
<p>När en parameter bara gäller en miljö, håll dess värde utanför den återanvändbara modulen och låt miljökonfigurationen leverera det. Då blir modulens ansvar tydligare, och en ändring för utvecklingsmiljön behöver inte skapa en oavsiktlig produktionsändring.</p>

<h2 id="bygg-arbetsflodet-kring-den-risk-som-faktiskt-finns">Bygg arbetsflödet kring den risk som faktiskt finns</h2>
<p>Om Azure är den enda plattformen och teamet vill beskriva resurser nära ARM är Bicep ett rimligt val. Om samma IaC-lösning måste omfatta flera moln kan Terraform passa bättre. <strong>Jag skulle välja Bicep för en Azure-fokuserad miljö</strong>, men bara med versionsstyrda moduler, granskad what-if och tydliga regler för vad som får tas bort.</p>
<p>Börja med en liten, verklig distribution, till exempel ett testresurskonto med nätverksregler. Låt pipeline bygga och validera koden, visa ändringarna i pull requesten och kräva ett aktivt godkännande innan distribution. Då märks det tidigt om teamet har en språkfråga, en behörighetsfråga eller en brist i själva ändringsprocessen.</p>]]></content:encoded>
      
      <category>DevOps och systemadministration</category>
      <media:thumbnail url="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/thumbnail/8efe142f2a11b18fdb3d9da9561c0ba7/azure-bicep-i-praktiken-granska-andringar-fore-distribution.webp"/>
      <pubDate>Sat, 07 Nov 2026 08:23:00 +0100</pubDate>
    </item>
    <item>
      <title>När vinner !important i CSS? Så felsöker du kaskaden</title>
      <link>https://jelks.nu/nar-vinner-important-i-css-sa-felsoker-du-kaskaden</link>
      <description>Får inte din CSS-regel effekt? Lär dig när !important vinner, hur specificitet och kaskadlager påverkar och vad du ska kontrollera i DevTools.</description>
      <content:encoded><![CDATA[<?xml encoding="utf-8" ?><p>Du &auml;ndrar en knappf&auml;rg i CSS, sparar filen och inget h&auml;nder. <code>!important</code> kan f&aring; din deklaration att vinna, men bara om konflikten faktiskt ligger i r&auml;tt del av kaskaden.</p><p><img src="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/post_image/93cef4fce567207fc5e2c296cb977cb8/css-cascade-devtools-important-specificity-cascade-layers-code-example.webp" class="image article-image" loading="lazy" alt="Chrome DevTools visar HTML-struktur och CSS-stilar. Viktig CSS f&ouml;r sidtiteln syns."></p><div class="short-summary">
  <h2 id="important-loser-en-konflikt-snabbt-men-kan-gora-nasta-svarare">!important l&ouml;ser en konflikt snabbt, men kan g&ouml;ra n&auml;sta sv&aring;rare</h2>
  <ul>
    <li><strong>Skriv flaggan efter v&auml;rdet:</strong> <code>color: #fff !important;</code></li>
    <li><strong>Den sl&aring;r vanliga deklarationer</strong>, men kaskadens ursprung och lager avg&ouml;r fortfarande vad som vinner mellan viktiga regler.</li>
    <li><strong>H&ouml;gre specificitet r&auml;cker inte</strong> f&ouml;r att sl&aring; en viktig deklaration fr&aring;n samma ursprung och lager.</li>
    <li><strong>Inspektera f&ouml;rst i DevTools:</strong> kontrollera vilken regel som s&auml;tter v&auml;rdet och varf&ouml;r den andra stryks.</li>
  </ul>
</div><h2 id="important-andrar-kaskaden-inte-hela-css-regeln">!important &auml;ndrar kaskaden, inte hela CSS-regeln</h2><p>N&auml;r tv&aring; regler s&auml;tter olika v&auml;rden p&aring; samma egenskap v&auml;ljer webbl&auml;saren enligt CSS-kaskaden vilken deklaration som ska g&auml;lla. Med <code>!important</code> markeras <strong>en enskild deklaration</strong> som viktig, till exempel f&auml;rgen, inte alla egenskaper i selektorn.</p><p><code>.knapp { color: white !important; }</code> &auml;r giltig CSS. Flaggan ska st&aring; efter v&auml;rdet och f&ouml;re semikolonet. Om deklarationen &auml;nd&aring; inte f&aring;r effekt kan selektorn missa elementet, regeln vara ogiltig eller ett annat ursprung, lager eller en &ouml;verg&aring;ng ha h&ouml;gre prioritet.</p><p>Jag tycker att <code>!important</code> fungerar b&auml;st som en tydligt avgr&auml;nsad undantagsregel. N&auml;r den b&ouml;rjar dyka upp p&aring; m&aring;nga egenskaper blir det sv&aring;rare att f&ouml;rst&aring; vem som styr utseendet.</p><h2 id="hogre-specificitet-slar-inte-alltid-en-viktig-deklaration">H&ouml;gre specificitet sl&aring;r inte alltid en viktig deklaration</h2><p>En l&aring;ng selektor med flera ID:n kan se m&auml;ktig ut, men mot en viktig deklaration fr&aring;n samma ursprung och kaskadlager f&ouml;rlorar den &auml;nd&aring; om den sj&auml;lv &auml;r normal. <strong><code>!important</code> &auml;r inte en del av specificiteten</strong>; flaggan p&aring;verkar ett tidigare steg i kaskadens prioritering.</p><p>F&ouml;rst j&auml;mf&ouml;rs bland annat ursprung och vikt. D&auml;refter spelar lagerordning in, och sedan j&auml;mf&ouml;rs specificitet mellan deklarationer som fortfarande st&aring;r lika. K&auml;llordningen avg&ouml;r f&ouml;rst n&auml;r de relevanta prioriteringarna och specificiteten inte skiljer reglerna &aring;t.</p><p>Det &auml;r d&auml;rf&ouml;r det ofta blir en &aring;terv&auml;ndsgr&auml;nd att stapla fler klasser eller ID:n p&aring; en vanlig regel. <strong>Kontrollera f&ouml;rst om motregeln redan &auml;r markerad som viktig</strong>, och om reglerna ligger i olika lager.</p><h2 id="devtools-visar-vilken-vag-du-ska-ta">DevTools visar vilken v&auml;g du ska ta</h2><p>N&auml;r stilen inte &auml;ndras kan webbl&auml;sarens utvecklarverktyg avsl&ouml;ja orsaken direkt. Markera elementet och &ouml;ppna panelen f&ouml;r ber&auml;knade stilar eller matchande regler; &ouml;verstrukna deklarationer visar ofta vad som f&ouml;rlorade i kaskaden.</p><table>
  <tbody>
    <tr>
      <th scope="col">Situation</th>
      <th scope="col">Trolig orsak</th>
      <th scope="col">N&auml;sta steg</th>
    </tr>
    <tr>
      <td>Din regel syns inte bland matchande regler</td>
      <td>Selektorn tr&auml;ffar inte elementet, eller CSS-filen laddas inte.</td>
      <td>Kontrollera elementets klass, filens laddning och eventuella villkor som media queries.</td>
    </tr>
    <tr>
      <td>Deklarationen &auml;r &ouml;verstruken</td>
      <td>En annan deklaration vinner i kaskaden.</td>
      <td>J&auml;mf&ouml;r vikt, ursprung, lager och specificitet i den ordningen.</td>
    </tr>
    <tr>
      <td>En normal regel f&ouml;rlorar mot en viktig regel</td>
      <td>H&ouml;gre specificitet kan inte kompensera f&ouml;r att deklarationen saknar <code>!important</code>.</td>
      <td>Ta reda p&aring; vem som &auml;ger regeln och om den kan &auml;ndras eller l&auml;ggas i ett l&auml;mpligt lager.</td>
    </tr>
    <tr>
      <td>V&auml;rdet &auml;ndras gradvis trots en viktig deklaration</td>
      <td>En CSS-&ouml;verg&aring;ng kan tillf&auml;lligt ha f&ouml;retr&auml;de.</td>
      <td>Inspektera egenskapens <code>transition</code> och kontrollera slutv&auml;rdet n&auml;r &ouml;verg&aring;ngen &auml;r klar.</td>
    </tr>
  </tbody>
</table><p>Tabellen hj&auml;lper dig att skilja ett prioriteringsproblem fr&aring;n ett laddnings- eller selektorproblem. <strong>L&auml;gg inte till en viktig flagga innan du vet vilken situation du har</strong>, annars kan den verkliga orsaken ligga kvar.</p><h2 id="kaskadlager-kan-vanda-ordningen-mellan-viktiga-regler">Kaskadlager kan v&auml;nda ordningen mellan viktiga regler</h2><p>H&auml;r finns en detalj som l&auml;tt &ouml;verraskar: ordningen f&ouml;r viktiga deklarationer i <code>@layer</code> g&aring;r &aring;t motsatt h&aring;ll j&auml;mf&ouml;rt med vanliga deklarationer. En viktig deklaration i ett tidigare lager prioriteras framf&ouml;r en viktig deklaration i ett senare lager. Inom f&ouml;rfattarens stilar prioriteras ocks&aring; viktiga deklarationer i lager framf&ouml;r viktiga deklarationer utanf&ouml;r lager.</p><p>MDN:s beskrivning av <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/important" target="_blank" rel="noopener noreferrer nofollow"><code>!important</code> i CSS-kaskaden</a> tar &auml;ven upp tv&aring; undantag fr&aring;n den f&ouml;renklade tumregeln att flaggan alltid vinner: viktiga anv&auml;ndar- och webbl&auml;sarstilar kan g&aring; f&ouml;re f&ouml;rfattarens, och aktiva &ouml;verg&aring;ngar har h&ouml;gre prioritet.</p><p>Om ett tredjepartsbibliotek anv&auml;nder m&aring;nga viktiga regler &auml;r en genomt&auml;nkt lagerstruktur ofta l&auml;ttare att underh&aring;lla &auml;n en v&auml;xande samling motregler. Men lager hj&auml;lper bara om du k&auml;nner till ordningen och var bibliotekets regler hamnar.</p><h2 id="valj-en-riktad-atgard-framfor-en-hogre-flaggniva">V&auml;lj en riktad &aring;tg&auml;rd framf&ouml;r en h&ouml;gre flaggniv&aring;</h2><p>Anta att en webbplatsknapp blir gr&aring; eftersom ett till&auml;ggs stilblad s&auml;tter <code>background-color: gray !important</code>. Om regeln kommer fr&aring;n ett anv&auml;ndarstilblad kan den, enligt den vanliga prioritetsordningen, g&aring; f&ouml;re en viktig deklaration i webbplatsens eget stilblad. Att l&auml;gga till &auml;nnu fler ID:n i webbplatsens CSS l&ouml;ser d&aring; inte konflikten.</p><p>Om regeln i st&auml;llet kommer fr&aring;n ett bibliotek som du kontrollerar kan du ta bort flaggan eller justera bibliotekets stil. Om den m&aring;ste ligga kvar kan ett separat lager f&ouml;r viktiga undantag ge en tydlig plats f&ouml;r den smala korrigeringen. <strong>Identifiera ursprunget innan du v&auml;ljer l&ouml;sning</strong>; samma kodrad kan beh&ouml;va olika &aring;tg&auml;rder beroende p&aring; vem som skrev den.</p><p>En anv&auml;ndbar tumregel &auml;r enkel: om du kan &auml;ndra k&auml;llregeln, g&ouml;r det och h&aring;ll den normal. Om du inte kan &auml;ndra den, anv&auml;nd en viktig motregel bara n&auml;r du har bekr&auml;ftat ursprung och lager. N&auml;r korrigeringen ska leva vidare i projektet, dokumentera varf&ouml;r undantaget beh&ouml;vs.</p><h2 id="lat-undantaget-stanna-dar-felet-finns">L&aring;t undantaget stanna d&auml;r felet finns</h2><p><code>!important</code> &auml;r ett legitimt verktyg f&ouml;r en avgr&auml;nsad konflikt, till exempel en tillf&auml;llig korrigering eller en regel du inte sj&auml;lv kan &auml;ndra. Det blir sv&aring;rhanterligt n&auml;r varje ny CSS-konflikt f&aring;r samma behandling, eftersom kommande &auml;ndringar d&aring; kr&auml;ver &auml;nnu mer kunskap om kaskaden.</p><p>Jag skulle b&ouml;rja med DevTools och f&ouml;lja deklarationens ursprung, vikt och lager innan n&aring;gon kod &auml;ndras. Om flaggan fortfarande beh&ouml;vs, h&aring;ll den till <strong>den egenskap som faktiskt strular</strong> och skriv en kort kommentar om varf&ouml;r den finns. D&aring; g&aring;r den gr&aring; knappen att fels&ouml;ka utan att hela stilmallen blir en dragkamp.</p>]]></content:encoded>
      
      <category>Frontend- och apputveckling</category>
      <media:thumbnail url="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/thumbnail/549774fc06abdd29981dc4ca6062d9a6/nar-vinner-important-i-css-sa-felsoker-du-kaskaden.webp"/>
      <pubDate>Fri, 06 Nov 2026 13:28:00 +0100</pubDate>
    </item>
    <item>
      <title>Klasser i JavaScript, från instans till privata fält</title>
      <link>https://jelks.nu/klasser-i-javascript-fran-instans-till-privata-falt</link>
      <description>Lär dig när en klass i JavaScript passar och hur constructor, prototypmetoder och privata fält fungerar. Läs guiden och välj rätt modell.</description>
      <content:encoded><![CDATA[<?xml encoding="utf-8" ?><p>N&auml;r en produktlista p&aring; en webbplats beh&ouml;ver h&aring;lla reda p&aring; namn, pris och lagerstatus kan ett vanligt objekt r&auml;cka en stund, men logiken v&auml;xer l&auml;tt n&auml;r varje produkt ska kunna uppdateras p&aring; samma s&auml;tt. En <strong>klass i JavaScript</strong> passar ofta n&auml;r flera objekt ska dela struktur och metoder, men den &auml;r inte alltid enklare &auml;n en funktion som skapar objekt.</p><p><img src="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/post_image/476cf763647352c551a318bbf2829787/javascript-class-constructor-instance-methods-prototype-diagram-code-example.webp" class="image article-image" loading="lazy" alt="Klassdiagram som visar arv fr&aring;n en abstrakt `Shape` javascript class till `Circle`, `Triangle` och `Rectangle`."></p><div class="short-summary">
  <h2 id="en-klass-samlar-data-och-beteenden-i-en-ateranvandbar-modell">En klass samlar data och beteenden i en &aring;teranv&auml;ndbar modell</h2>
  <ul>
    <li><strong>Skapa en instans</strong> med nyckelordet <code>new</code>.</li>
    <li><strong>Initiera instansdata</strong> i <code>constructor()</code> eller med klassf&auml;lt.</li>
    <li><strong>Dela metoder</strong> mellan instanser via klassens prototyp.</li>
    <li><strong>Skydda intern data</strong> med privata f&auml;lt som b&ouml;rjar med <code>#</code>.</li>
    <li><strong>V&auml;lj klass</strong> n&auml;r flera objekt f&ouml;ljer samma modell och beh&ouml;ver gemensamma metoder.</li>
  </ul>
</div><h2 id="en-klass-blir-anvandbar-nar-objekten-foljer-samma-modell">En klass blir anv&auml;ndbar n&auml;r objekten f&ouml;ljer samma modell</h2><p>T&auml;nk dig att en webbshop visar flera produkter med namn, pris och lagerstatus. Med en klass kan varje produkt f&aring; samma grundform, samtidigt som metoderna f&ouml;r exempelvis prisvisning inte beh&ouml;ver skrivas om f&ouml;r varje objekt.</p><p>Jag tycker att klasser fungerar b&auml;st n&auml;r de uttrycker en tydlig modell i programmet, inte n&auml;r de bara ger ett objekt ett mer h&ouml;gtidligt namn. Om datan &auml;r enkel och saknar egna beteenden kan ett vanligt objekt vara l&auml;ttare att l&auml;sa.</p><h2 id="constructor-och-new-skapar-en-produktinstans">Constructor och new skapar en produktinstans</h2><p>Metoden <code>constructor()</code> k&ouml;rs n&auml;r en instans skapas med <code>new</code>. Parametrarna blir egenskaper p&aring; just det objektet, medan vanliga metoder i klassen delas mellan instanserna.</p><pre><code>class Product {
  constructor(name, price, inStock = true) {
    this.name = name;
    this.price = price;
    this.inStock = inStock;
  }

  displayPrice() {
    return `${this.name}: ${this.price} kr`;
  }
}

const notebook = new Product("Anteckningsbok", 49);
console.log(notebook.displayPrice());</code></pre><p>H&auml;r kan varje produkt ha ett eget namn och pris, men alla anv&auml;nder samma <code>displayPrice()</code>-metod. En vanlig miss &auml;r att f&ouml;rs&ouml;ka anropa <code>Product()</code> utan <code>new</code>; en klass m&aring;ste instansieras med <code>new</code>, annars uppst&aring;r ett fel. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes" target="_blank" rel="noopener noreferrer nofollow">MDN:s referens om klasser</a> beskriver &auml;ven klassf&auml;lt som ett alternativ n&auml;r ett startv&auml;rde inte beh&ouml;ver komma fr&aring;n konstruktorns argument.</p><h2 id="metoder-ligger-pa-prototypen-inte-i-varje-produkt">Metoder ligger p&aring; prototypen, inte i varje produkt</h2><p>En detalj som ofta &ouml;verraskar &auml;r att metoder som deklareras direkt i klassen inte kopieras som separata funktioner till varje instans. Instanserna hittar i st&auml;llet metoden via klassens <strong>prototyp</strong>, en l&auml;nkad objektstruktur som JavaScript anv&auml;nder f&ouml;r arv och delat beteende.</p><p>Det betyder att <code>notebook.displayPrice</code> och metoden p&aring; en annan produktinstans normalt pekar p&aring; samma funktion. En pilfunktion som tilldelas som klassf&auml;lt fungerar annorlunda: d&aring; skapas en separat funktion f&ouml;r varje instans, vilket kan vara anv&auml;ndbart f&ouml;r vissa &aring;teranropsfunktioner men blir on&ouml;digt om metoden ska delas.</p><h2 id="privata-falt-och-statiska-metoder-har-olika-jobb">Privata f&auml;lt och statiska metoder har olika jobb</h2><p>Om lagerantalet ska &auml;ndras via en metod i st&auml;llet f&ouml;r att kunna skrivas &ouml;ver fritt, kan ett privat f&auml;lt b&ouml;rja med tecknet <code>#</code>. Det ger ett faktiskt &aring;tkomstskydd i spr&aring;ket, inte bara en namnkonvention med understreck.</p><pre><code>class Product {
  #stock;

  constructor(name, stock) {
    this.name = name;
    this.#stock = stock;
  }

  isAvailable() {
    return this.#stock &gt; 0;
  }
}</code></pre><p>Kod utanf&ouml;r klassen kan anropa <code>isAvailable()</code>, men kan inte l&auml;sa <code>#stock</code> direkt. Privata f&auml;lt m&aring;ste deklareras i klassens kropp, och en underklass kan inte komma &aring;t f&ouml;r&auml;ldraklassens privata f&auml;lt; det &auml;r en skillnad som blir viktig n&auml;r modellen byggs ut. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_elements" target="_blank" rel="noopener noreferrer nofollow">MDN:s dokumentation om privata klasselement</a> f&ouml;rklarar begr&auml;nsningen.</p><p>En <code>static</code>-metod h&ouml;r d&auml;remot till klassen sj&auml;lv, inte till en viss produkt. Den passar exempelvis f&ouml;r en funktion som validerar produktdata innan n&aring;gon instans skapas; anropa den som <code>Product.validate(data)</code>, inte som <code>notebook.validate(data)</code>.</p><h2 id="valj-klass-nar-gemensamma-regler-vager-tyngre-an-enkel-data">V&auml;lj klass n&auml;r gemensamma regler v&auml;ger tyngre &auml;n enkel data</h2><p>En klass passar n&auml;r flera objekt delar b&aring;de struktur och beteenden, till exempel produkter som alla kan kontrollera lagertillg&auml;nglighet. F&ouml;r en enda konfigurationspost med n&aring;gra f&aring; v&auml;rden kan ett objekt vara tydligare, och en fabriksfunktion kan passa n&auml;r objekt ska skapas utan en klasshierarki.</p><table>
  <tbody>
    <tr>
      <th scope="col">Situation</th>
      <th scope="col">Trolig orsak eller f&ouml;ljd</th>
      <th scope="col">G&ouml;r s&aring; h&auml;r</th>
    </tr>
    <tr>
      <td>Du har flera likartade instanser med samma metoder</td>
      <td>En gemensam modell minskar duplicerad logik</td>
      <td>Skapa en klass och h&aring;ll instansdata i konstruktorn eller klassf&auml;lt</td>
    </tr>
    <tr>
      <td>Objektet best&aring;r av ett f&aring;tal v&auml;rden utan eget beteende</td>
      <td>En klass kan l&auml;gga till struktur utan praktisk nytta</td>
      <td>Anv&auml;nd ett vanligt objekt</td>
    </tr>
    <tr>
      <td>En metod anv&auml;nds som &aring;teranropsfunktion och tappar sitt <code>this</code></td>
      <td>Metodanropets sammanhang f&ouml;ljer inte automatiskt med</td>
      <td>Bind metoden eller anv&auml;nd ett klassf&auml;lt med pilfunktion om en instansbunden funktion beh&ouml;vs</td>
    </tr>
    <tr>
      <td>En underklass beh&ouml;ver l&auml;sa ett privat f&auml;lt fr&aring;n sin f&ouml;r&auml;lder</td>
      <td><code>#f&auml;lt</code> &auml;r privat &auml;ven f&ouml;r underklassen</td>
      <td>Exponera ett avsett skyddat beteende via en metod, eller ompr&ouml;va klassindelningen</td>
    </tr>
  </tbody>
</table><p>Arv med <code>extends</code> och <code>super</code> kan &aring;teranv&auml;nda beteende fr&aring;n en basklass, men varje extra niv&aring; g&ouml;r det sv&aring;rare att f&ouml;lja var en metod kommer ifr&aring;n. Jag skulle v&auml;lja arv f&ouml;rst n&auml;r underklassen verkligen kan behandlas som samma sorts objekt; annars &auml;r separata klasser eller komposition oftast l&auml;ttare att underh&aring;lla.</p><h2 id="en-liten-modell-ar-lattare-att-halla-begriplig">En liten modell &auml;r l&auml;ttare att h&aring;lla begriplig</h2><p>B&ouml;rja med en klass n&auml;r du kan namnge b&aring;de den &aring;terkommande datan och minst ett beteende som h&ouml;r till varje instans. L&auml;gg till privata f&auml;lt n&auml;r andra delar av programmet annars kan skapa ogiltiga tillst&aring;nd, och anv&auml;nd statiska metoder f&ouml;r uppgifter som inte kr&auml;ver en enskild instans.</p><p>Om klassen d&auml;remot mest inneh&aring;ller f&auml;lt utan logik, b&ouml;rja enklare. Den b&auml;sta modellen f&ouml;r en produktlista &auml;r den som g&ouml;r det l&auml;tt att se vad produkten kan g&ouml;ra och vilka regler som skyddar dess data.</p>]]></content:encoded>
      
      <category>Programmering och AI</category>
      <media:thumbnail url="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/thumbnail/7a4e302a0361ce9c08b75df4a4639948/klasser-i-javascript-fran-instans-till-privata-falt.webp"/>
      <pubDate>Thu, 05 Nov 2026 15:58:00 +0100</pubDate>
    </item>
    <item>
      <title>Vilken port använder PostgreSQL? Så hittar du rätt</title>
      <link>https://jelks.nu/vilken-port-anvander-postgresql-sa-hittar-du-ratt</link>
      <description>PostgreSQL använder oftast port 5432, men Docker och anslutningsvägen kan ändra vilken port du behöver. Läs hur du hittar rätt och felsöker.</description>
      <content:encoded><![CDATA[<head></head><p>Du öppnar pgAdmin, fyller i anslutningsuppgifterna och får ändå ingen kontakt med databasen. PostgreSQL använder vanligtvis port <strong>5432</strong>, men rätt portnummer beror också på hur servern körs och varifrån anslutningen kommer.</p>

<p><img src="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/post_image/1dac83b0272984003610eb363120f579/postgresql-port-5432-connection-diagram-docker-host-port-mapping.webp" class="image article-image" loading="lazy" alt="Arkitekturdiagram visar datainmatning från CSV-filer till en datalager med PostgreSQL som databas, uppdelat i brons-, silver- och guldskikt."></p>

<div class="short-summary">
  <h2 id="5432-ar-standard-men-anslutningsvagen-avgor-vilken-port-du-ska-anvanda">5432 är standard, men anslutningsvägen avgör vilken port du ska använda</h2>
  <ul>
    <li><strong>Standardport:</strong> PostgreSQL lyssnar normalt på TCP-port 5432.</li>
    <li><strong>Docker:</strong> porten på din dator kan skilja sig från porten inne i containern.</li>
    <li><strong>Flera servrar:</strong> varje server på samma dator behöver en egen ledig port.</li>
    <li><strong>Felsökning:</strong> kontrollera port, värdnamn och om servern faktiskt lyssnar.</li>
  </ul>
</div>

<h2 id="5432-ar-standardporten-inte-en-garanti">5432 är standardporten, inte en garanti</h2>
<p>Portnumret talar om vilken nätverkstjänst klienten ska kontakta på en dator. PostgreSQL:s vanliga TCP-port är <strong>5432</strong>, och den används ofta i anslutningssträngar, administrationsverktyg och utvecklingsmiljöer. Men en administratör kan ändra serverns port, så standardvärdet räcker inte alltid.</p>
<p>Jag tycker att det är lättast att felsöka genom att skilja på <strong>serverns adress</strong> och <strong>porten</strong>: adressen pekar ut datorn eller tjänsten, medan porten pekar ut PostgreSQL på den adressen. PostgreSQL-dokumentationen beskriver porten som en inställning i serverns konfiguration; kontrollera därför det faktiska värdet i <a href="https://www.postgresql.org/docs/current/runtime-config-connection.html" target="_blank" rel="noopener noreferrer nofollow">PostgreSQLs dokumentation om anslutningsinställningar</a> om 5432 inte fungerar.</p>

<h2 id="i-docker-kan-datorns-port-skilja-sig-fran-containerns">I Docker kan datorns port skilja sig från containerns</h2>
<p>En anslutning kan se rätt ut i containern men ändå misslyckas från datorn. I Docker kan en värdport skickas vidare till containerns port, och numren behöver inte vara samma. I uttrycket <code>-p 5433:5432</code> är <strong>5433 porten på värddatorn</strong> och <strong>5432 porten i containern</strong>.</p>
Det innebär att ett program som körs direkt på datorn kan ansluta till <code>localhost:5433</code>, medan en annan container på samma Docker-nätverk vanligtvis ansluter till PostgreSQL-tjänstens namn och port <code>5432</code>. Docker förklarar <a href="https://jelks.nu/sql-subqueries-och-skillnaden-mellan-in-exists-och-skalara-fragor">skillnaden mellan</a> publicerad port och containerport i sin <a href="https://docs.docker.com/guides/postgresql/" target="_blank" rel="noopener noreferrer nofollow">guide till PostgreSQL i Docker</a>.
<p>Som tumregel: <strong>från värddatorn använder du värdporten</strong>; från en container på samma nätverk använder du tjänstens namn och den interna porten. Om två PostgreSQL-containrar ska köras samtidigt kan de alltså båda lyssna på 5432 internt, medan de publiceras på exempelvis 5432 och 5433 på datorn.</p>

<h2 id="felmeddelandet-pekar-ofta-ut-nasta-kontroll">Felmeddelandet pekar ofta ut nästa kontroll</h2>
<p>Orden i felmeddelandet hjälper dig att välja rätt felsökningssteg. Kontrollera först om anslutningen går till rätt värd och port; ändra inte serverns konfiguration innan du vet om problemet gäller en upptagen port, en felaktig adress eller en server som inte är igång.</p>
<table>
  <tbody>
    <tr>
      <th scope="col">Situation eller fel</th>
      <th scope="col">Trolig förklaring</th>
      <th scope="col">Gör så här</th>
    </tr>
    <tr>
      <td>”Connection refused” på 5432</td>
      <td>Ingen server tar emot anslutningar på den porten, eller så når anslutningen fel värd.</td>
      <td>Kontrollera att PostgreSQL körs och att värdnamn och port stämmer.</td>
    </tr>
    <tr>
      <td>”Address already in use” när servern startar</td>
      <td>En annan process använder redan porten.</td>
      <td>Ta reda på vilken process som lyssnar, eller konfigurera en annan port.</td>
    </tr>
    <tr>
      <td>Det fungerar i containern men inte från datorn</td>
      <td>Porten har inte publicerats, eller så använder klienten containerns port i stället för värdporten.</td>
      <td>Kontrollera Docker-portmappningen och anslut till den publicerade porten.</td>
    </tr>
    <tr>
      <td>Det fungerar från datorn men inte från en annan container</td>
      <td><code>localhost</code> pekar på den container där programmet körs, inte på PostgreSQL-containern.</td>
      <td>Använd databasens tjänstenamn på det gemensamma Docker-nätverket.</td>
    </tr>
  </tbody>
</table>
<p>Fel om att porten redan används betyder alltså inte automatiskt att PostgreSQL är trasigt. PostgreSQLs dokumentation beskriver hur en annan server som redan lyssnar på samma port kan hindra uppstarten; <a href="https://www.postgresql.org/docs/current/server-start.html" target="_blank" rel="noopener noreferrer nofollow">felsökningsavsnittet om serverstart</a> rekommenderar att du granskar felmeddelandet och serverloggen.</p>

<h2 id="hitta-porten-som-servern-faktiskt-anvander">Hitta porten som servern faktiskt använder</h2>
<p>Om du redan kan ansluta till databasen kan du fråga servern direkt. Kör <code>SHOW port;</code> i <code>psql</code> eller ett SQL-verktyg; resultatet visar portinställningen för just den server du nått. Det är mer tillförlitligt än att anta att alla lokala installationer använder samma värde.</p>
<p>Om du inte kan ansluta behöver du kontrollera konfigurationen eller startkommandot där PostgreSQL körs. Klienten kan också ha en egen standardinställning: miljövariabeln <code>PGPORT</code> används som portvärde av PostgreSQL-verktyg när inget annat anges. Ange därför porten uttryckligen vid felsökning, till exempel med <code>psql -h localhost -p 5433 -U postgres</code>.</p>
<p>För lokal utveckling är en annan värdport ett enkelt sätt att köra flera databaser samtidigt. I Docker-exemplet ovan ansluter datorns klient till <code>localhost:5433</code>, medan en app-container på samma nätverk använder tjänstenamnet och <code>5432</code>.</p>

<h2 id="valj-anslutningsadress-efter-var-appen-kors">Välj anslutningsadress efter var appen körs</h2>
<p>När porten är känd återstår frågan varifrån klienten ansluter. En app på samma dator kan ofta använda <code>localhost</code>; en app i en annan container behöver vanligtvis databasens tjänstenamn; en app på en annan maskin behöver serverns nåbara nätverksadress. <strong>Samma portnummer kan alltså vara rätt i ett fall och fel i ett annat.</strong></p>
<p>Om PostgreSQL bara ska användas lokalt, bind publiceringen till loopback-adressen <code>127.0.0.1</code> i stället för att göra porten tillgänglig på alla nätverksgränssnitt. Då blir utvecklingsdatabasen inte automatiskt nåbar från andra enheter som kan nå datorn. Börja med rätt anslutningsväg och kontrollera sedan porten; det brukar snabbt visa om felet ligger i klientens inställningar eller i servern.</p>]]></content:encoded>
      
      <category>Databaser och SQL</category>
      <media:thumbnail url="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/thumbnail/83f2945b7ba33eb499190f7e39133475/vilken-port-anvander-postgresql-sa-hittar-du-ratt.webp"/>
      <pubDate>Wed, 04 Nov 2026 15:14:00 +0100</pubDate>
    </item>
    <item>
      <title>Så ser du fjärrgrenar med git branch -r</title>
      <link>https://jelks.nu/sa-ser-du-fjarrgrenar-med-git-branch-r</link>
      <description>Se vad git branch -r visar och varför listan kan vara inaktuell. Jämför med git ls-remote och lär dig uppdatera fjärrgrenar med fetch --prune.</description>
      <content:encoded><![CDATA[<?xml encoding="utf-8" ?><p>N&auml;r en kollega n&auml;mner en gren som inte syns i terminalen vill du snabbt kontrollera om den finns p&aring; fj&auml;rren. B&ouml;rja med <code>git branch -r</code>, men kom ih&aring;g att listan visar lokalt sparade referenser och d&auml;rf&ouml;r kan vara inaktuell.</p><p><img src="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/post_image/966b44f8019af5bf4121f4dc0918d6a4/terminal-git-command-git-branch-r-remote-tracking-branches-example.webp" class="image article-image" loading="lazy" alt="Git-grafik som visar hur man kan git list remote branches. Visar lokala och fj&auml;rr-grenar p&aring; " origin och samt computer></p><div class="short-summary">
<h2 id="ratt-kommando-beror-pa-om-du-behover-en-sparad-lista-eller-en-farsk-kontroll">R&auml;tt kommando beror p&aring; om du beh&ouml;ver en sparad lista eller en f&auml;rsk kontroll</h2>
<ul>
<li><strong>Visa sparade fj&auml;rrgrenar:</strong> <code>git branch -r</code></li>
<li><strong>Visa b&aring;de lokala och sparade fj&auml;rrgrenar:</strong> <code>git branch -a</code></li>
<li><strong>Kontrollera vad fj&auml;rren annonserar just nu:</strong> <code>git ls-remote --heads origin</code></li>
<li><strong>Uppdatera listan och rensa bort inaktuella referenser:</strong> <code><a href="https://jelks.nu/sa-anvander-du-git-fetch-innan-du-integrerar-andringar">git fetch</a> --prune origin</code></li>
</ul>
</div><h2 id="git-branch-r-visar-fjarrsparningsgrenar-inte-en-live-lista">git branch -r visar fj&auml;rrsp&aring;rningsgrenar, inte en live-lista</h2><p>Kommandot <code>git branch -r</code> skriver ut fj&auml;rrsp&aring;rningsgrenar, till exempel <code>origin/main</code> och <code>origin/feature/search</code>. Namnen finns i din lokala repository och speglar vad Git senast h&auml;mtade fr&aring;n fj&auml;rren. <strong>De kontrolleras inte automatiskt mot servern n&auml;r listan visas.</strong></p><p>Det &auml;r en skillnad som l&auml;tt st&auml;ller till det. Jag tycker att det hj&auml;lper att se <code>origin/feature/search</code> som en lokal bokm&auml;rkeslapp till en gren p&aring; fj&auml;rren, inte som sj&auml;lva grenen. Git beskriver dessa referenser som remote-tracking branches i <a href="https://git-scm.com/docs/git-branch.html" target="_blank" rel="noopener noreferrer nofollow">dokumentationen f&ouml;r git branch</a>.</p><p>Vill du &auml;ven se dina lokala grenar k&ouml;r du <code>git branch -a</code>. Om du bara beh&ouml;ver fj&auml;rrsp&aring;rningsgrenarna &auml;r <code>-r</code> tydligare och ger mindre brus.</p><h2 id="anvand-git-ls-remote-nar-svaret-maste-komma-fran-fjarren">Anv&auml;nd git ls-remote n&auml;r svaret m&aring;ste komma fr&aring;n fj&auml;rren</h2><p>Beh&ouml;ver du veta vilka grenar fj&auml;rren visar just nu, k&ouml;r <code>git ls-remote --heads origin</code>. Kommandot fr&aring;gar fj&auml;rren direkt och skriver ut commit-ID:n tillsammans med referenser, som <code>refs/heads/main</code>. Det uppdaterar d&auml;remot inte dina lokala fj&auml;rrsp&aring;rningsgrenar.</p><p>Det &auml;r en bra kontroll n&auml;r en ny gren nyss har publicerats eller n&auml;r din lokala lista verkar mots&auml;ga teamets. <strong>Ser du grenen i svaret men inte med <code>git branch -r</code>, beh&ouml;ver du h&auml;mta referenserna.</strong> Beskrivningen av vad kommandot visar finns i <a href="https://git-scm.com/docs/git-ls-remote.html" target="_blank" rel="noopener noreferrer nofollow">Git-dokumentationen f&ouml;r git ls-remote</a>.</p><h2 id="valj-kommando-efter-vad-du-vill-kontrollera">V&auml;lj kommando efter vad du vill kontrollera</h2><p>Tv&aring; kommandon kan allts&aring; visa olika resultat utan att n&aring;got av dem &auml;r trasigt. T&auml;nk s&aring; h&auml;r: <strong>beh&ouml;ver du se din lokala Git-kunskap, anv&auml;nd <code>git branch -r</code>; beh&ouml;ver du fr&aring;ga servern, anv&auml;nd <code>git ls-remote</code>.</strong></p><table>
<tbody>
<tr>
<th scope="col">Situation</th>
<th scope="col">Varf&ouml;r listan ser ut s&aring;</th>
<th scope="col">G&ouml;r s&aring; h&auml;r</th>
</tr>
<tr>
<td>En kollega har publicerat en gren, men <code>git branch -r</code> visar den inte</td>
<td>Dina lokala referenser har inte h&auml;mtats sedan grenen skapades</td>
<td>K&ouml;r <code>git fetch origin</code> och lista p&aring; nytt</td>
</tr>
<tr>
<td>En borttagen gren syns fortfarande under <code>origin/</code></td>
<td>Den gamla fj&auml;rrsp&aring;rningsreferensen finns kvar lokalt</td>
<td>K&ouml;r <code>git fetch --prune origin</code></td>
</tr>
<tr>
<td>Du vill veta vad fj&auml;rren annonserar utan att &auml;ndra din lokala lista</td>
<td><code>git branch -r</code> visar sparade referenser, inte en live-f&ouml;rfr&aring;gan</td>
<td>K&ouml;r <code>git ls-remote --heads origin</code></td>
</tr>
<tr>
<td>Du vill se b&aring;de lokala och fj&auml;rrsp&aring;rade grenar</td>
<td>Flaggan <code>-a</code> omfattar b&aring;da grupperna</td>
<td>K&ouml;r <code>git branch -a</code></td>
</tr>
</tbody>
</table><p><code>git fetch</code> h&auml;mtar referenser och uppdaterar deras lokala motsvarigheter, men sammanfogar inte &auml;ndringar till din aktuella arbetsgren. Med <code>--prune</code> tas ocks&aring; lokala fj&auml;rrsp&aring;rningsreferenser bort n&auml;r motsvarande grenar saknas p&aring; fj&auml;rren, vilket beskrivs i <a href="https://git-scm.com/docs/git-fetch.html" target="_blank" rel="noopener noreferrer nofollow">dokumentationen f&ouml;r git fetch</a>. K&ouml;r d&auml;rf&ouml;r prune n&auml;r du vill st&auml;da din lokala lista, inte n&auml;r du enbart vill kontrollera den.</p><h2 id="filtrera-listan-eller-byt-till-grenen-utan-omvagar">Filtrera listan eller byt till grenen utan omv&auml;gar</h2><p>N&auml;r repot har m&aring;nga grenar slipper du skrolla genom allt. Filtrera p&aring; ett namn med <code>git branch -r --list 'origin/feature/*'</code>; jokertecknet begr&auml;nsar resultatet till grenar under det m&ouml;nstret. Beh&aring;ll citattecknen s&aring; att skalet inte f&ouml;rs&ouml;ker tolka m&ouml;nstret innan Git f&aring;r det.</p><p>Hittar du grenen efter en h&auml;mtning kan du skapa en lokal gren som sp&aring;rar den med <code>git switch --track origin/feature/search</code>. D&aring; kopplas den lokala grenen till sin upstream, allts&aring; den gren Git anv&auml;nder som j&auml;mf&ouml;relsepunkt vid status och pull. Med flera fj&auml;rrar b&ouml;r du ange r&auml;tt fj&auml;rrnamn uttryckligen, eftersom samma grennamn kan finnas p&aring; mer &auml;n en.</p><h2 id="en-enkel-rutin-haller-grenlistan-begriplig">En enkel rutin h&aring;ller grenlistan begriplig</h2><p>N&auml;r du bara beh&ouml;ver en snabb &ouml;verblick r&auml;cker <code>git branch -r</code>. Om en gren saknas eller verkar vara borttagen, fr&aring;ga f&ouml;rst fj&auml;rren med <code>git ls-remote --heads origin</code>; h&auml;mta sedan eller rensa lokala referenser utifr&aring;n vad du faktiskt vill g&ouml;ra.</p><p><strong>F&ouml;r dagligt arbete &auml;r kombinationen <code>git fetch --prune</code> f&ouml;ljt av <code>git branch -r</code> ofta den tydligaste rutinen.</strong> D&aring; visar listan uppdaterade fj&auml;rrsp&aring;rningsgrenar, samtidigt som gamla namn inte ligger kvar och f&ouml;rvirrar n&auml;sta beslut.</p>]]></content:encoded>
      
      <category>Utvecklingsverktyg och arbetsflöden</category>
      <media:thumbnail url="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/thumbnail/cdd21e9ecf0327fdfbb9fb8338b8c642/sa-ser-du-fjarrgrenar-med-git-branch-r.webp"/>
      <pubDate>Wed, 04 Nov 2026 08:21:00 +0100</pubDate>
    </item>
    <item>
      <title>GROUP BY i SQL: så får du rätt sammanställning</title>
      <link>https://jelks.nu/group-by-i-sql-sa-far-du-ratt-sammanstallning</link>
      <description>Lär dig använda GROUP BY i SQL för tydliga sammanställningar. Se hur COUNT, WHERE och HAVING fungerar och undvik felaktiga summor efter JOIN.</description>
      <content:encoded><![CDATA[<head></head><p>När du vill se vilka sidor som får flest besök räcker råa analysrader sällan långt. Med <code>GROUP BY</code> kan du samla rader med samma värde och räkna eller summera dem, men resultatet beror på vilka kolumner du grupperar efter.</p>

<div class="short-summary">
  <h2 id="gruppera-ratt-for-att-fa-anvandbara-sammanstallningar">Gruppera rätt för att få användbara sammanställningar</h2>
  <ul>
    <li><strong>En rad per grupp:</strong> välj grupperingskolumnen och ett aggregat som <code>COUNT</code> eller <code>SUM</code>.</li>
    <li><strong>Filtrera före och efter:</strong> <code>WHERE</code> tar bort rader före grupperingen, medan <code>HAVING</code> filtrerar färdiga grupper.</li>
    <li><strong>Flera kolumner</strong> ger en grupp för varje unik kombination av värden.</li>
    <li><strong>Kontrollera JOIN-resultatet:</strong> en koppling kan mångdubbla rader och därmed blåsa upp summor.</li>
    <li><strong>Undvik otydliga kolumner:</strong> välj bara grupperade kolumner och aggregat, så blir frågan tydligare mellan databaser.</li>
  </ul>
</div>

<h2 id="en-grupp-motsvarar-en-rad-i-resultatet">En grupp motsvarar en rad i resultatet</h2>
<p>Tänk dig en tabell med webbplatsbesök där varje rad är en sidvisning. Om du vill räkna sidvisningar per sida grupperar du på sidans namn och låter <code>COUNT</code> räkna raderna i varje grupp.</p>
<pre><code>SELECT page_path, COUNT(*) AS visits
FROM pageviews
GROUP BY page_path
ORDER BY visits DESC;</code></pre>
<p>Resultatet innehåller en rad per unikt värde i <code>page_path</code>. <strong><code>COUNT(*)</code> räknar alla rader</strong> i gruppen, medan exempelvis <code>SUM(revenue)</code> summerar värden och <code>AVG(load_time)</code> beräknar ett genomsnitt. Jag tycker att det blir lättare att granska resultatet när varje vald kolumn antingen står i <code>GROUP BY</code> eller används i ett aggregat.</p>

<h2 id="where-och-having-filtrerar-vid-olika-tillfallen">WHERE och HAVING filtrerar vid olika tillfällen</h2>
<p>En rapport kan ge rätt totalsumma men ändå svara på fel fråga om filtret hamnar på fel ställe. <code>WHERE</code> väljer vilka rader som får delta i grupperingen; <code>HAVING</code> väljer vilka grupper som ska finnas kvar efter att aggregaten räknats fram.</p>
<pre><code>SELECT page_path, COUNT(*) AS visits
FROM pageviews
WHERE visited_at &gt;= '2026-01-01'
GROUP BY page_path
HAVING COUNT(*) &gt;= 100
ORDER BY visits DESC;</code></pre>
Här tas äldre sidvisningar bort före beräkningen, och därefter visas bara sidor med minst 100 besök under perioden. En <a href="https://jelks.nu/sql-subqueries-och-skillnaden-mellan-in-exists-och-skalara-fragor">praktisk tumregel</a> är enkel: filtrerar du enskilda poster, börja med <code>WHERE</code>; filtrerar du på ett beräknat gruppresultat, använd <code>HAVING</code>. <a href="https://www.postgresql.org/docs/current/queries-table-expressions.html" target="_blank" rel="noopener noreferrer nofollow">PostgreSQLs dokumentation om GROUP BY och HAVING</a> beskriver samma skillnad i frågans bearbetning.

<h2 id="flera-grupperingskolumner-delar-upp-resultatet-mer">Flera grupperingskolumner delar upp resultatet mer</h2>
<p>Om trafiken ska delas upp både per sida och enhetstyp lägger du till båda kolumnerna i grupperingen. Då blir varje unik kombination en egen grupp, exempelvis startsida plus mobil eller startsida plus dator.</p>
<pre><code>SELECT page_path, device_type, COUNT(*) AS visits
FROM pageviews
GROUP BY page_path, device_type
ORDER BY page_path, device_type;</code></pre>
<p>Det här kan avslöja att en sida fungerar väl på dator men får få besök från mobil. Samtidigt blir resultatet mer uppdelat: varje extra grupperingskolumn kan skapa fler rader och mindre underlag per grupp. Om du bara behöver en lista över unika sidnamn kan <code>SELECT DISTINCT page_path</code> vara tydligare än <code>GROUP BY page_path</code> utan aggregat.</p>

<h2 id="null-och-join-kan-ge-ovantade-gruppresultat">NULL och JOIN kan ge oväntade gruppresultat</h2>
<p>En tom kategori försvinner inte automatiskt ur resultatet. Databasens grupperingsbeteende samlar <code>NULL</code>-värden i en grupp, så du kan få en rad där kategorin saknas. Det kan vara en användbar signal om spårningen inte skickar in värdet, snarare än en kategori att ignorera.</p>
<p>En annan fallgrop uppstår när tabeller kopplas ihop. Anta att en orderrad på 100 kronor matchar två kampanjrader: efter kopplingen förekommer orderraden två gånger, och en efterföljande <code>SUM</code> kan räkna 200 kronor. Kontrollera därför hur många matchningar varje rad får innan du summerar, eller aggregera orderraderna i en undertabell före kopplingen.</p>
<table>
  <tbody>
    <tr><th scope="col">Situation</th><th scope="col">Trolig orsak eller följd</th><th scope="col">Gör så här</th></tr>
    <tr><td>En extra rad har tom kategori</td><td>Grupperingskolumnen innehåller <code>NULL</code></td><td>Kontrollera källdatan; använd vid behov <code>COALESCE</code> för en tydlig etikett.</td></tr>
    <tr><td>Summan efter en JOIN är för hög</td><td>En rad matchar flera rader i den andra tabellen</td><td>Granska matchningsantalet och aggregera på rätt nivå före kopplingen.</td></tr>
    <tr><td>Frågan ger fel för en vald kolumn</td><td>Kolumnen är varken grupperad eller aggregerad</td><td>Lägg till den i <code>GROUP BY</code> eller välj ett aggregat som passar frågan.</td></tr>
  </tbody>
</table>

<h2 id="databasmotorn-kan-avgora-om-fragan-godkanns">Databasmotorn kan avgöra om frågan godkänns</h2>
<p>En fråga som fungerar i en databas kan stoppas av en annan, särskilt om <code>SELECT</code> innehåller en kolumn som inte grupperas. MySQL 8.4 med läget <code>ONLY_FULL_GROUP_BY</code> aktiverat avvisar normalt sådana otydliga val om kolumnen inte bestäms av grupperingskolumnerna; utan läget kan MySQL välja ett godtyckligt värde från gruppen. <a href="https://dev.mysql.com/doc/refman/8.4/en/group-by-handling.html" target="_blank" rel="noopener noreferrer nofollow">MySQL 8.4 Reference Manual</a> beskriver både begränsningen och varför ett sådant värde kan bli icke-deterministiskt.</p>
<p>SQL Server kräver att kolumner som används i icke-aggregerade uttryck i urvalet finns med i grupperingen. <a href="https://learn.microsoft.com/en-us/sql/t-sql/queries/select-group-by-transact-sql?view=sql-server-ver17" target="_blank" rel="noopener noreferrer nofollow">Microsofts dokumentation om GROUP BY i Transact-SQL</a> anger också att grupperingen kan omfatta uttryck och erbjuder tillägg som <code>ROLLUP</code> för delsummor. För frågor som ska flyttas mellan motorer är därför den säkraste vanan att hålla urvalet tydligt och undvika icke-aggregerade kolumner utanför grupperingen.</p>

<h2 id="en-tydlig-gruppering-ger-mer-palitliga-rapporter">En tydlig gruppering ger mer pålitliga rapporter</h2>
<p>När en sammanställning ser märklig ut, kontrollera först gruppnycklarna, därefter filtren och till sist om en JOIN har duplicerat rader. Den ordningen brukar snabbt skilja ett grupperingsfel från ett problem i källdatan.</p>
<p>För en rapport över webbtrafik betyder det att du först bestämmer nivån, exempelvis sida eller sida och enhet, och sedan väljer ett aggregat som verkligen beskriver den nivån. Då blir varje resultat rad för rad begripligt, även när analysen växer.</p>]]></content:encoded>
      
      <category>Databaser och SQL</category>
      <media:thumbnail url="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/thumbnail/7320356a4a00a854a4abcdee04849a94/group-by-i-sql-sa-far-du-ratt-sammanstallning.webp"/>
      <pubDate>Tue, 03 Nov 2026 17:07:00 +0100</pubDate>
    </item>
    <item>
      <title>Skriv säkrare Bash-skript för automatiska säkerhetskopior</title>
      <link>https://jelks.nu/skriv-sakrare-bash-skript-for-automatiska-sakerhetskopior</link>
      <description>Lär dig skriva säkrare Bash-skript för säkerhetskopiering med citerade variabler, pipefail och ShellCheck. Läs guiden och upptäck vanliga fallgropar.</description>
      <content:encoded><![CDATA[<?xml encoding="utf-8" ?><p>N&auml;r en schemalagd s&auml;kerhetskopia misslyckas mitt i natten vill du snabbt veta om felet kom fr&aring;n databasen, komprimeringen eller &ouml;verf&ouml;ringen. Ett Bash-skript passar ofta bra f&ouml;r att koppla ihop s&aring;dana verktyg, men bara om fel och indata hanteras med eftertanke.</p><p><img src="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/post_image/daed4e8aa4a1c4b420bac7babf344468/terminal-med-bash-skript-for-automatiserad-sakerhetskopiering-pa-linux-server.webp" class="image article-image" loading="lazy" alt="Schemal&auml;ggning av automatisk backup med ett bash script. Visar terminalkommandon f&ouml;r lagringsutrymme."></p><div class="short-summary">
  <h2 id="ett-bra-bash-skript-gor-serverjobb-repeterbara-och-fel-synliga">Ett bra Bash-skript g&ouml;r serverjobb repeterbara och fel synliga</h2>
  <ul>
    <li><strong>Anv&auml;nd Bash</strong> n&auml;r uppgiften fr&auml;mst kopplar ihop befintliga kommandoradsverktyg.</li>
    <li><strong>Citera variabler</strong> s&aring; att mellanslag och specialtecken i s&ouml;kv&auml;gar inte &auml;ndrar kommandot.</li>
    <li><strong>Kontrollera fel uttryckligen</strong>; <code>set -e</code> f&aring;ngar inte alla fel p&aring; ett intuitivt s&auml;tt.</li>
    <li><strong>K&ouml;r ShellCheck</strong> f&ouml;re drifts&auml;ttning och testa &auml;ven det felaktiga scenariot.</li>
  </ul>
</div><h2 id="bash-passar-bast-nar-skriptet-binder-ihop-befintliga-verktyg">Bash passar b&auml;st n&auml;r skriptet binder ihop befintliga verktyg</h2><p>En Bash-fil &auml;r som en liten arbetsledare f&ouml;r kommandon som redan finns p&aring; systemet: den kan kontrollera en katalog, starta en s&auml;kerhetskopia och skriva resultatet till en logg. F&ouml;r ett avgr&auml;nsat jobb p&aring; en Linux-server blir l&ouml;sningen ofta l&auml;tt att l&auml;sa och k&ouml;ra, s&auml;rskilt n&auml;r det mesta arbetet redan g&ouml;rs av exempelvis <code>tar</code>, <code>rsync</code> eller <code>systemctl</code>.</p><p>Gr&auml;nsen kommer n&auml;r logiken v&auml;xer. Beh&ouml;ver skriptet hantera m&aring;nga datatyper, komplicerade API-anrop eller omfattande fel&aring;terh&auml;mtning tycker jag att Python ofta blir tydligare. Bash &auml;r starkt som lim mellan program, men sk&ouml;rt som ers&auml;ttning f&ouml;r ett st&ouml;rre program.</p><h2 id="en-sakerhetskopia-bor-stoppa-innan-den-rapporteras-som-klar">En s&auml;kerhetskopia b&ouml;r stoppa innan den rapporteras som klar</h2><p>Det farliga felet &auml;r inte alltid att ett kommando kraschar. En pipeline kan ge ett missvisande resultat om ett tidigt kommando misslyckas men det sista &auml;nd&aring; avslutas utan fel. GNU:s <a href="https://www.gnu.org/s/bash/manual/bash.html" target="_blank" rel="noopener noreferrer nofollow">Bash Reference Manual</a> beskriver hur <code>pipefail</code> &auml;ndrar pipeline-statusen s&aring; att ett fel i ett tidigare led kan synas.</p><p>H&auml;r &auml;r en kompakt grund f&ouml;r en s&auml;kerhetskopia. Den kr&auml;ver att m&aring;lkatalogen redan finns och l&auml;mnar ett tydligt felmeddelande om n&aring;got kommando i pipelinen misslyckas:</p><pre><code>#!/usr/bin/env bash
set -o pipefail

source_dir="/srv/site"
backup_dir="/var/backups/site"
archive="$backup_dir/site-$(date +%F).tar.gz"

if [[ ! -d "$source_dir" || ! -d "$backup_dir" ]]; then
  printf 'K&auml;ll- eller m&aring;lkatalog saknas\n' &gt;&amp;2
  exit 1
fi

if tar -czf - -C "$source_dir" . | tee "$archive" &gt;/dev/null; then
  printf 'S&auml;kerhetskopia skapad: %s\n' "$archive"
else
  status=$?
  rm -f -- "$archive"
  printf 'S&auml;kerhetskopian misslyckades, status %s\n' "$status" &gt;&amp;2
  exit "$status"
fi</code></pre><p><code>pipefail</code> &auml;r valt h&auml;r i st&auml;llet f&ouml;r att blint l&auml;gga till <code>set -e</code>. Manualen p&aring;pekar att <code>-e</code> har undantag, bland annat i villkor och vissa listor av kommandon. <strong>Kontrollera d&auml;rf&ouml;r kritiska steg d&auml;r resultatet anv&auml;nds</strong>, i st&auml;llet f&ouml;r att anta att en enda inst&auml;llning l&ouml;ser all felhantering.</p><h2 id="citat-runt-variabler-hindrar-sokvagar-fran-att-splittras">Citat runt variabler hindrar s&ouml;kv&auml;gar fr&aring;n att splittras</h2><p>En katalog som heter <code>/srv/site files</code> r&auml;cker f&ouml;r att avsl&ouml;ja ett vanligt Bash-fel. Om en variabel anv&auml;nds utan citattecken kan skalet dela upp v&auml;rdet vid blanksteg och &auml;ven tolka jokertecken; skriv d&auml;rf&ouml;r normalt <code>"$source_dir"</code>, inte <code>$source_dir</code>.</p><p>F&ouml;redra ocks&aring; <code>[[ ... ]]</code> f&ouml;r Bash-villkor och <code>$(kommando)</code> f&ouml;r kommandosubstitution. Googles <a href="https://google.github.io/styleguide/shellguide.html" target="_blank" rel="noopener noreferrer nofollow">Shell Style Guide</a> rekommenderar bland annat dessa m&ouml;nster och lyfter ShellCheck som ett s&auml;tt att hitta vanliga misstag.</p><table>
  <tbody>
    <tr><th scope="col">Situation</th><th scope="col">Trolig f&ouml;ljd</th><th scope="col">G&ouml;r s&aring; h&auml;r</th></tr>
    <tr><td>S&ouml;kv&auml;g eller argument kan inneh&aring;lla blanksteg</td><td>Oquotad variabel delas upp i flera argument</td><td>Citat variabeln, till exempel <code>"$archive"</code></td></tr>
    <tr><td>Ett tidigt steg i en pipeline fallerar</td><td>Utan <code>pipefail</code> kan det sista stegets status d&ouml;lja felet</td><td>Anv&auml;nd <code>set -o pipefail</code> och hantera felgrenen</td></tr>
    <tr><td>Skriptet k&ouml;rs med <code>sh script.sh</code></td><td>Bash-specifika konstruktioner kan bete sig fel</td><td>K&ouml;r med Bash, exempelvis <code>bash script.sh</code>, eller g&ouml;r skriptet POSIX-kompatibelt</td></tr>
    <tr><td>ShellCheck visar en varning</td><td>Det kan r&ouml;ra sig om ett verkligt quoting- eller logikfel</td><td>L&auml;s varningen och r&auml;tta orsaken innan eventuellt undantag</td></tr>
  </tbody>
</table><h2 id="shellcheck-hittar-fel-innan-skriptet-nar-servern">ShellCheck hittar fel innan skriptet n&aring;r servern</h2><p>En skriptfil kan se rimlig ut och &auml;nd&aring; hantera ett argument fel. <a href="https://www.shellcheck.net/" target="_blank" rel="noopener noreferrer nofollow">ShellCheck</a> analyserar Bash- och shellkod statiskt och flaggar bland annat risker med oquotade variabler. Jag tycker att det &auml;r en av de mest anv&auml;ndbara kvalitetskontrollerna f&ouml;r ett skript som ska k&ouml;ras automatiskt, eftersom en liten miss i ett cron-jobb annars kan ligga ouppt&auml;ckt l&auml;nge.</p><p>K&ouml;r kontrollen lokalt med <code>shellcheck backup.sh</code> och syntaxkontrollera sedan med <code>bash -n backup.sh</code>. Det senare k&ouml;r inte sj&auml;lva arbetsfl&ouml;det, s&aring; testa ocks&aring; med en saknad k&auml;llkatalog och kontrollera att skriptet avslutas med felstatus i st&auml;llet f&ouml;r att skriva ut ett lyckat meddelande.</p><p>Om skriptet ligger i Git kan samma kontroller k&ouml;ras i CI innan &auml;ndringen godk&auml;nns. D&aring; uppt&auml;cks ett trasigt skript f&ouml;re drifts&auml;ttning, medan ett test med tillf&auml;lliga kataloger kan bekr&auml;fta att det producerade arkivet faktiskt g&aring;r att l&auml;sa.</p><h2 id="valj-bash-for-korta-arbetsfloden-ett-annat-sprak-for-vaxande-logik">V&auml;lj Bash f&ouml;r korta arbetsfl&ouml;den, ett annat spr&aring;k f&ouml;r v&auml;xande logik</h2><p>Ett Bash-skript l&auml;mpar sig n&auml;r stegen &auml;r f&aring;, kommandona &auml;r etablerade och resultatet g&aring;r att kontrollera med exitstatus och filer. Om du b&ouml;rjar bygga avancerad argumenttolkning, &aring;terf&ouml;rs&ouml;k, JSON-hantering och flera beroende funktioner blir skriptet snabbt sv&aring;rare att fels&ouml;ka &auml;n ett litet program i ett spr&aring;k med tydligare datastrukturer.</p><p>En anv&auml;ndbar tumregel &auml;r att beh&aring;lla Bash n&auml;r det mest handlar om att starta och koppla ihop systemverktyg. Om sj&auml;lva beslutslogiken b&ouml;rjar dominera skulle jag flytta den till Python och l&aring;ta Bash, om det beh&ouml;vs, bara starta programmet.</p><h2 id="gor-resultatet-synligt-innan-jobbet-kors-obevakat">G&ouml;r resultatet synligt innan jobbet k&ouml;rs obevakat</h2><p>Automatisering &auml;r f&ouml;rst trygg n&auml;r misslyckanden ocks&aring; m&auml;rks. Skriv fel till standard error, ge processen en meningsfull exitstatus och l&aring;t schemal&auml;ggaren eller &ouml;vervakningen reagera p&aring; den; ett tyst fel &auml;r l&auml;tt att f&ouml;rv&auml;xla med en lyckad k&ouml;rning.</p><p>F&ouml;r s&auml;kerhetskopian betyder det att kontrollera b&aring;de skriptets status och att arkivet g&aring;r att l&auml;sa. Ett kort Bash-skript kan spara &aring;terkommande arbete, men den lilla kontrollen efter k&ouml;rningen &auml;r det som skiljer automation fr&aring;n enbart automatiserad optimism.</p>]]></content:encoded>
      
      <category>DevOps och systemadministration</category>
      <media:thumbnail url="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/thumbnail/3485beb071066d21c546af1c438d268f/skriv-sakrare-bash-skript-for-automatiska-sakerhetskopior.webp"/>
      <pubDate>Mon, 02 Nov 2026 17:45:00 +0100</pubDate>
    </item>
    <item>
      <title>TanStack Table ger frihet, men kräver eget gränssnitt</title>
      <link>https://jelks.nu/tanstack-table-ger-frihet-men-kraver-eget-granssnitt</link>
      <description>Lär dig när TanStack Table passar, hur v9 skiljer sig från äldre exempel och hur du samordnar serverpaginering, sortering och filter. Läs guiden.</description>
      <content:encoded><![CDATA[<?xml encoding="utf-8" ?><p>N&auml;r en orderlista ska f&aring; egen design, fungerande sortering och filtrering kan en f&auml;rdig tabellkomponent k&auml;nnas f&ouml;r l&aring;st. <strong>TanStack Table ger dig logiken och l&aring;ter dig bygga gr&auml;nssnittet sj&auml;lv</strong>, men det inneb&auml;r ocks&aring; att du ansvarar f&ouml;r s&aring;dant som knappar, sidnavigering och tomma l&auml;gen.</p><p><img src="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/post_image/73ee0d9e73e65b67dca53440ef34f5df/react-tanstack-table-headless-data-table-custom-ui-sorting-filtering-pagination.webp" class="image article-image" loading="lazy" alt="En React-app med en tanstack table som visar anst&auml;llda, deras avdelning och betyg."></p><div class="short-summary">
  <h2 id="passar-bast-nar-tabellens-utseende-och-beteende-ska-formas-efter-appen">Passar b&auml;st n&auml;r tabellens utseende och beteende ska formas efter appen</h2>
  <ul>
    <li><strong>Headless betyder</strong> att biblioteket hanterar tabellogik, medan du bygger markup och styling.</li>
    <li><strong>V&auml;lj TanStack Table</strong> n&auml;r egen design och kontroll v&auml;ger tyngre &auml;n ett f&auml;rdigt datagrid.</li>
    <li><strong>Kontrollera versionsnumret:</strong> v9 anv&auml;nder en annan API-struktur &auml;n m&aring;nga &auml;ldre v8-exempel.</li>
    <li><strong>H&aring;ll datahanteringen konsekvent:</strong> blanda inte sortering p&aring; webbl&auml;sarens aktuella sida med filtrering &ouml;ver hela serverns dataset.</li>
  </ul>
</div><h2 id="headless-ger-frihet-men-lamnar-granssnittet-till-dig">Headless ger frihet, men l&auml;mnar gr&auml;nssnittet till dig</h2><p>En tabell kan se enkel ut tills den ska hantera sorteringspilar, laddning, mobilvy och tangentbordsnavigation. TanStack Table ger dig tabellens <strong>tillst&aring;nd och funktioner</strong>, men inte en f&auml;rdig visuell komponent. Du skapar sj&auml;lv HTML-strukturen och kopplar anv&auml;ndarens klick till tabellens API.</p><p>Det g&ouml;r biblioteket l&auml;ttare att anpassa till en befintlig design &auml;n en f&auml;rdig datagrid. Samtidigt m&aring;ste du bygga s&aring;dant som annars ofta ing&aring;r fr&aring;n b&ouml;rjan: sidknappar, filterf&auml;lt, felmeddelanden och tydliga <a href="https://jelks.nu/sa-bygger-du-en-tillganglig-hamburgermeny-med-css">tillg&auml;nglighet</a>setiketter. Jag tycker att det &auml;r ett bra byte n&auml;r tabellen ska k&auml;nnas som en naturlig del av produkten, men ett on&ouml;digt extrajobb f&ouml;r en enkel administrationsvy.</p><h2 id="valj-tanstack-table-nar-designkontroll-vager-tyngre-an-fardig-ui">V&auml;lj TanStack Table n&auml;r designkontroll v&auml;ger tyngre &auml;n f&auml;rdig UI</h2><p>Beslutet blir tydligare om du utg&aring;r fr&aring;n vad teamet faktiskt vill &auml;ga. En egen tabell kr&auml;ver mer gr&auml;nssnittskod, men du kan styra varje cell och interaktion; en f&auml;rdig datagrid kommer snabbare p&aring; plats, men kan s&auml;tta ramar f&ouml;r hur appen ser ut och fungerar.</p><table>
  <tbody>
    <tr>
      <th scope="col">Situation</th>
      <th scope="col">Trolig f&ouml;ljd</th>
      <th scope="col">V&auml;lj s&aring; h&auml;r</th>
    </tr>
    <tr>
      <td>Tabellen ska f&ouml;lja en unik produktdesign</td>
      <td>En f&auml;rdig komponent kan vara sv&aring;r att forma exakt</td>
      <td>V&auml;lj TanStack Table och avs&auml;tt tid f&ouml;r UI-delarna</td>
    </tr>
    <tr>
      <td>Du beh&ouml;ver snabbt en standardtabell f&ouml;r intern administration</td>
      <td>Egen markup och interaktionskod kan bli merarbete</td>
      <td>&Ouml;verv&auml;g en komponent med f&auml;rdigt utseende och inbyggda kontroller</td>
    </tr>
    <tr>
      <td>Tabellen ska ha m&aring;nga kalkylbladsliknande funktioner direkt</td>
      <td>Funktionerna beh&ouml;ver byggas eller integreras separat</td>
      <td>J&auml;mf&ouml;r med ett fullst&auml;ndigt datagrid innan du best&auml;mmer dig</td>
    </tr>
  </tbody>
</table><p>Min tumregel &auml;r enkel: <strong>v&auml;lj headless n&auml;r du vill &auml;ga presentationen</strong>, och v&auml;lj en f&auml;rdig grid n&auml;r snabb v&auml;g till ett komplett standardgr&auml;nssnitt &auml;r viktigare. Det &auml;r s&auml;rskilt l&auml;tt att underskatta tiden f&ouml;r tillg&auml;nglighet och mobilanpassning.</p><h2 id="v9-exempel-kraver-en-annan-start-an-manga-aldre-guider">V9-exempel kr&auml;ver en annan start &auml;n m&aring;nga &auml;ldre guider</h2><p>En gammal kodsnutt kan se bekant ut och &auml;nd&aring; leda fel. Den aktuella v9-guiden anv&auml;nder <code>useTable</code> och l&aring;ter dig ange tabellens funktioner genom <code>tableFeatures()</code>; m&aring;nga v8-exempel utg&aring;r i st&auml;llet fr&aring;n <code>useReactTable</code> och en annan modell f&ouml;r radfunktioner.</p><p>Det &auml;r ingen liten namnskillnad att ignorera. Enligt <a href="https://tanstack.com/table/latest/docs/framework/react/guide/migrating" target="_blank" rel="noopener noreferrer nofollow">TanStack Tables migreringsguide f&ouml;r v9</a> beh&ouml;ver du vid uppgradering flytta funktioner och radmodeller till den nya strukturen. Om ett exempel inte g&aring;r ihop med installerad version, kontrollera f&ouml;rst om det &auml;r skrivet f&ouml;r v8 innan du b&ouml;rjar fels&ouml;ka TypeScript.</p><p>F&ouml;r ett nytt projekt &auml;r det s&auml;krast att b&ouml;rja med den version som paketet faktiskt installerar och f&ouml;lja dess React-dokumentation. <a href="https://tanstack.com/table/latest/docs/framework/react/quick-start" target="_blank" rel="noopener noreferrer nofollow">TanStack Tables snabbstart f&ouml;r React</a> visar hur tabell, kolumner och funktioner s&auml;tts ihop i v9.</p><h2 id="serverpaginering-fungerar-bast-nar-sortering-och-filter-foljer-med">Serverpaginering fungerar b&auml;st n&auml;r sortering och filter f&ouml;ljer med</h2><p>Anta att en orderlista har tusentals poster men API:et skickar en sida &aring;t g&aring;ngen. Om webbl&auml;saren sorterar den sidan lokalt ser anv&auml;ndaren bara posterna i den ordning som g&auml;ller f&ouml;r just den h&auml;mtade m&auml;ngden, inte n&ouml;dv&auml;ndigtvis i global ordning bland alla ordrar.</p><p>F&ouml;r serverpaginering ska servern d&auml;rf&ouml;r g&ouml;ra sj&auml;lva urvalet och sorteringen, medan tabellen f&aring;r veta att datan redan &auml;r paginerad. Skicka med totalantalet rader eller sidantalet n&auml;r det finns tillg&auml;ngligt; utan det kan tabellen inte s&auml;kert avg&ouml;ra n&auml;r sista sidan &auml;r n&aring;dd. <a href="https://tanstack.com/table/latest/docs/framework/react/guide/pagination" target="_blank" rel="noopener noreferrer nofollow">TanStack Tables guide f&ouml;r paginering</a> beskriver alternativen f&ouml;r klient- och serverhantering.</p><table>
  <tbody>
    <tr>
      <th scope="col">Situation</th>
      <th scope="col">Trolig orsak eller f&ouml;ljd</th>
      <th scope="col">G&ouml;r s&aring; h&auml;r</th>
    </tr>
    <tr>
      <td>Sorteringen verkar bara g&auml;lla den synliga sidan</td>
      <td>Sortering sker i webbl&auml;saren efter att en sida h&auml;mtats</td>
      <td>Flytta sorteringen till API:et och skicka sorteringsvalet med beg&auml;ran</td>
    </tr>
    <tr>
      <td>N&auml;sta-knappen g&aring;r aldrig att st&auml;nga av</td>
      <td>Tabellen saknar uppgift om totalt antal rader eller sidor</td>
      <td>Skicka totalantalet fr&aring;n servern eller hantera slutet p&aring; resultatet sj&auml;lv</td>
    </tr>
    <tr>
      <td>Filtret hittar bara poster p&aring; aktuell sida</td>
      <td>Klientfilter k&ouml;rs p&aring; den redan h&auml;mtade delm&auml;ngden</td>
      <td>L&aring;t servern filtrera hela datasetet och h&auml;mta om sidan</td>
    </tr>
  </tbody>
</table><p>H&aring;ll samma ansvarsf&ouml;rdelning genom hela fl&ouml;det: <strong>serverbaserad paginering b&ouml;r paras med serverbaserad sortering och filtrering</strong>. D&aring; slipper anv&auml;ndaren en tabell som ser korrekt ut men ger ofullst&auml;ndiga resultat.</p><h2 id="bygg-forsta-tabellen-liten-och-lagg-till-funktioner-efter-behov">Bygg f&ouml;rsta tabellen liten och l&auml;gg till funktioner efter behov</h2><p>Det &auml;r lockande att b&ouml;rja med s&ouml;kf&auml;lt, kolumnfilter, sortering, markering och sidindelning p&aring; en g&aring;ng. Jag skulle b&ouml;rja med en kolumn och ett par rader, f&aring; rendering och datatyper p&aring; plats och sedan l&auml;gga till en funktion i taget. D&aring; g&aring;r det snabbare att hitta vilken del som orsakar ett fel.</p><p>Skilj ocks&aring; mellan tabellens logik och appens datah&auml;mtning. Om ett filter p&aring;verkar API-anropet beh&ouml;ver det kopplas till beg&auml;ran och uppdatera resultaten; en filterkontroll som bara &auml;ndrar utseende hj&auml;lper inte anv&auml;ndaren att hitta fler poster. <strong>En liten fungerande tabell</strong> ger en b&auml;ttre grund &auml;n en stor komponent med flera halvt inkopplade reglage.</p><h2 id="en-bra-tabell-borjar-med-ratt-ansvarsfordelning">En bra tabell b&ouml;rjar med r&auml;tt ansvarsf&ouml;rdelning</h2><p>TanStack Table passar n&auml;r du vill forma tabellens utseende sj&auml;lv och kan ta ansvar f&ouml;r kontrollerna runt den. F&ouml;r en f&auml;rdig standardgrid kan en UI-komponent spara tid; f&ouml;r en produktanpassad tabell &auml;r friheten ofta v&auml;rd arbetet, s&aring; l&auml;nge datafl&ouml;det &auml;r genomt&auml;nkt.</p><p>B&ouml;rja med att best&auml;mma om hela datasetet finns i webbl&auml;saren eller om servern ska sk&ouml;ta urvalet. Det valet styr paginering, sortering och filtrering redan fr&aring;n start, och g&ouml;r resten av bygget betydligt mindre sv&aring;rnavigerat.</p>]]></content:encoded>
      
      <category>Frontend- och apputveckling</category>
      <media:thumbnail url="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/thumbnail/95d8934b6136b1fb9cce5ae286e6f5e0/tanstack-table-ger-frihet-men-kraver-eget-granssnitt.webp"/>
      <pubDate>Mon, 02 Nov 2026 17:32:00 +0100</pubDate>
    </item>
    <item>
      <title>Länkad lista i Python och när den faktiskt passar</title>
      <link>https://jelks.nu/lankad-lista-i-python-och-nar-den-faktiskt-passar</link>
      <description>Lär dig bygga en länkad lista i Python, förstå tidsåtgången och välja mellan egen kod, list och deque. Läs guiden och se när strukturen passar.</description>
      <content:encoded><![CDATA[<?xml encoding="utf-8" ?><p>N&auml;r en k&ouml; f&aring;r m&aring;nga &auml;ndringar i b&ouml;rjan kan en vanlig <a href="https://jelks.nu/python-range-forklarat-start-stopp-och-steg">Python</a>-lista bli besv&auml;rlig, och d&aring; kan en l&auml;nkad lista verka lockande. En egen <strong>linked list i Python</strong> g&ouml;r det enkelt att koppla in och koppla loss noder, men vinsten beror p&aring; om du redan k&auml;nner till noden som ska &auml;ndras.</p><p><img src="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/post_image/ab5a3ba69aebd5297e0b9ff77551d864/python-singly-linked-list-diagram-nodes-data-next-pointer-head.webp" class="image article-image" loading="lazy" alt="En person tittar p&aring; en display som visar en linked list i Python. Ovanf&ouml;r syns en l&auml;nkad lista med N1 till N5, och nedanf&ouml;r en dubbelt l&auml;nkad lista med N1 till N4."></p><div class="short-summary">
  <h2 id="en-lankad-lista-passar-nar-pekare-ar-viktigare-an-index">En l&auml;nkad lista passar n&auml;r pekare &auml;r viktigare &auml;n index</h2>
  <ul>
    <li><strong>Varje nod</strong> lagrar ett v&auml;rde och en referens till n&auml;sta nod.</li>
    <li><strong>Infogning efter en k&auml;nd nod</strong> tar konstant tid, men s&ouml;kning efter ett v&auml;rde tar linj&auml;r tid.</li>
    <li><strong>Python-listor</strong> passar b&auml;ttre n&auml;r du ofta h&auml;mtar element via index.</li>
    <li><strong>collections.deque</strong> &auml;r oftast ett b&auml;ttre f&auml;rdigt val f&ouml;r k&ouml;er.</li>
  </ul>
</div><h2 id="en-nod-pekar-vidare-den-hoppar-inte-till-ett-index">En nod pekar vidare, den hoppar inte till ett index</h2><p>T&auml;nk dig en kedja av kort d&auml;r varje kort visar ett v&auml;rde och adressen till n&auml;sta. I en <strong>enkell&auml;nkad lista</strong> b&ouml;rjar du vid huvudet, ofta kallat <code>head</code>, och f&ouml;ljer sedan pekarna en i taget. D&auml;rf&ouml;r kan du inte sl&aring; upp &rdquo;element nummer 500&rdquo; direkt som i en vanlig lista.</p><p>Det l&aring;ter enkelt, men det p&aring;verkar vilka operationer som blir snabba. Jag tycker att den l&auml;nkade listan &auml;r mest anv&auml;ndbar som ett s&auml;tt att f&ouml;rst&aring; referenser och datastrukturer, snarare &auml;n som en sj&auml;lvklar ers&auml;ttare f&ouml;r <a href="https://jelks.nu/sa-fungerar-pass-i-python-och-nar-du-ska-anvanda-det">Python</a>s inbyggda typer.</p><h2 id="en-liten-implementation-racker-for-att-se-hela-kedjan">En liten implementation r&auml;cker f&ouml;r att se hela kedjan</h2><p>H&auml;r &auml;r en grundversion med till&auml;gg sist, borttagning av f&ouml;rsta matchningen och iteration. Klassen h&aring;ller &auml;ven reda p&aring; svansen, s&aring; <code>append</code> slipper g&aring; igenom hela kedjan varje g&aring;ng.</p><pre><code>class Node:
    __slots__ = ("value", "next")

    def __init__(self, value):
        self.value = value
        self.next = None

class LinkedList:
    def __init__(self):
        self.head = None
        self.tail = None
        self.size = 0

    def append(self, value):
        node = Node(value)

        if self.tail is None:
            self.head = self.tail = node
        else:
            self.tail.next = node
            self.tail = node

        self.size += 1

    def remove(self, value):
        previous = None
        current = self.head

        while current is not None:
            if current.value == value:
                if previous is None:
                    self.head = current.next
                else:
                    previous.next = current.next

                if current is self.tail:
                    self.tail = previous

                self.size -= 1
                return True

            previous = current
            current = current.next

        return False

    def __iter__(self):
        current = self.head

        while current is not None:
            yield current.value
            current = current.next

    def __len__(self):
        return self.size

items = LinkedList()
items.append("startsida")
items.append("portfolio")
items.append("kontakt")

items.remove("portfolio")
print(list(items))  # ['startsida', 'kontakt']</code></pre><p><code>remove</code> beh&ouml;ver h&aring;lla reda p&aring; b&aring;de aktuell nod och f&ouml;reg&aring;ende nod, eftersom den f&ouml;reg&aring;ende nodens <code>next</code> m&aring;ste kopplas om. Om listan blir tom ska b&aring;de <code>head</code> och <code>tail</code> vara <code>None</code>; det h&auml;r exemplet hanterar &auml;ven borttagning fr&aring;n b&ouml;rjan och slutet.</p><h2 id="en-kand-nod-kan-kopplas-om-pa-o1">En k&auml;nd nod kan kopplas om p&aring; O(1)</h2><p>Big O beskriver hur arbetet v&auml;xer n&auml;r antalet element &ouml;kar. Med listan ovan tar <code>append</code> <strong>O(1)</strong> tack vare svansreferensen, medan s&ouml;kning och borttagning efter v&auml;rde tar <strong>O(n)</strong>, eftersom programmet kan beh&ouml;va g&aring; igenom varje nod.</p><table>
  <tbody>
    <tr><th>Operation</th><th>Tids&aring;tg&aring;ng</th><th>Varf&ouml;r</th></tr>
    <tr><td>L&auml;gg till sist med <code>tail</code></td><td>O(1)</td><td>Svansen hittas direkt.</td></tr>
    <tr><td>Hitta v&auml;rde eller position</td><td>O(n)</td><td>Noderna m&aring;ste f&ouml;ljas i ordning.</td></tr>
    <tr><td>Infoga efter en redan k&auml;nd nod</td><td>O(1)</td><td>En enda referens kopplas om.</td></tr>
    <tr><td>Ta bort ett v&auml;rde genom s&ouml;kning</td><td>O(n)</td><td>F&ouml;rst m&aring;ste r&auml;tt nod hittas.</td></tr>
  </tbody>
</table><p>H&auml;r finns en vanlig missuppfattning: &rdquo;infogning i en l&auml;nkad lista &auml;r O(1)&rdquo; g&auml;ller bara n&auml;r platsen redan &auml;r k&auml;nd. Om du f&ouml;rst m&aring;ste leta efter platsen blir hela operationen fortfarande <strong>O(n)</strong>. F&ouml;r en editor d&auml;r aktuell nod redan finns sparad kan det vara relevant; f&ouml;r en samling d&auml;r du s&ouml;ker efter index &auml;r det s&auml;llan det.</p><h2 id="deque-ar-oftast-battre-for-en-vanlig-ko">Deque &auml;r oftast b&auml;ttre f&ouml;r en vanlig k&ouml;</h2><p>Om problemet &auml;r att ta bort det &auml;ldsta elementet ur en k&ouml; beh&ouml;ver du f&ouml;rmodligen inte bygga egna noder. Pythons dokumentation anger att <code>collections.deque</code> st&ouml;der till&auml;gg och borttagning i b&aring;da &auml;ndar med ungef&auml;r <strong>O(1)</strong>-prestanda, medan <code>list.pop(0)</code> kr&auml;ver att &ouml;vriga referenser flyttas.</p><p>Som tumregel: v&auml;lj <code>deque</code> f&ouml;r k&ouml;er och arbete i b&aring;da &auml;ndar, en vanlig <code>list</code> f&ouml;r indexering och sekventiella data, och en egen l&auml;nkad lista n&auml;r du beh&ouml;ver kontroll &ouml;ver noderna eller &ouml;var p&aring; datastrukturer. Den skillnaden &auml;r tydligare &auml;n ett rent &rdquo;l&auml;nkad lista mot lista&rdquo;-p&aring;st&aring;ende. Se beskrivningen av <a href="https://docs.python.org/3/library/collections.html" target="_blank" rel="noopener noreferrer nofollow">collections.deque</a> i Python-dokumentationen.</p><h2 id="sma-noder-kan-anda-kosta-mer-minne">Sm&aring; noder kan &auml;nd&aring; kosta mer minne</h2><p>En nod inneh&aring;ller mer &auml;n sj&auml;lva v&auml;rdet: den beh&ouml;ver ocks&aring; en referens till n&auml;sta nod, och vanliga Python-objekt har attributhantering. Det inneb&auml;r att en l&aring;ng l&auml;nkad lista ofta har betydande minneskostnad j&auml;mf&ouml;rt med en kompakt arrayliknande representation, &auml;ven om exakta skillnader beror p&aring; Python-version och objekt.</p><p>I koden anv&auml;nds <code>__slots__</code> f&ouml;r att deklarera nodens tv&aring; attribut och undvika den vanliga instansens attributordbok. Python-dokumentationen beskriver detta som en m&ouml;jlig minnesbesparing, men det g&ouml;r inte pekarstrukturen gratis och begr&auml;nsar vilka attribut som kan l&auml;ggas till dynamiskt. L&auml;s om begr&auml;nsningarna i <a href="https://docs.python.org/3/reference/datamodel.html#slots" target="_blank" rel="noopener noreferrer nofollow">Python-dokumentationens avsnitt om __slots__</a>.</p><h2 id="felsok-utifran-det-som-hander-med-kedjan">Fels&ouml;k utifr&aring;n det som h&auml;nder med kedjan</h2><p>De flesta buggar visar sig n&auml;r en referens gl&ouml;ms bort eller n&auml;r en gr&auml;ns, som b&ouml;rjan eller slutet, &auml;ndras. Tabellen hj&auml;lper dig att koppla ett symtom till den del av strukturen som beh&ouml;ver granskas.</p><table>
  <tbody>
    <tr><th>Situation eller symtom</th><th>Trolig orsak</th><th>Vad du g&ouml;r</th></tr>
    <tr><td>Iteration forts&auml;tter utan slut</td><td>En nod pekar tillbaka till en tidigare nod.</td><td>Granska varje tilldelning till <code>next</code> och kontrollera att sista noden pekar p&aring; <code>None</code>.</td></tr>
    <tr><td>En nod f&ouml;rsvinner efter borttagning</td><td>F&ouml;reg&aring;ende nods pekare kopplades inte till n&auml;sta nod.</td><td>S&auml;tt <code>previous.next = current.next</code> n&auml;r noden inte &auml;r huvudet.</td></tr>
    <tr><td>En ny nod l&auml;ggs till men syns inte</td><td><code>tail</code> eller <code>head</code> uppdaterades inte.</td><td>Hantera tom lista separat och uppdatera svansen n&auml;r den sista noden &auml;ndras.</td></tr>
    <tr><td>L&auml;ngden st&auml;mmer inte</td><td><code>size</code> &auml;ndras inte exakt en g&aring;ng vid till&auml;gg och lyckad borttagning.</td><td>Kontrollera r&auml;knaren n&auml;r v&auml;rdet saknas och n&auml;r listan redan &auml;r tom.</td></tr>
  </tbody>
</table><p>En bra kontroll efter varje &auml;ndring &auml;r att g&aring; igenom listan, r&auml;kna noderna och j&auml;mf&ouml;ra med <code>len(items)</code>. L&auml;gg g&auml;rna till tester f&ouml;r tom lista, borttagning av enda noden och upprepade v&auml;rden, eftersom dessa fall avsl&ouml;jar fel som ett enkelt exempel ofta missar.</p><h2 id="valj-struktur-efter-hur-data-ska-anvandas">V&auml;lj struktur efter hur data ska anv&auml;ndas</h2><p>En l&auml;nkad lista g&ouml;r det synligt hur referenser kan koppla ihop separata objekt, men den kr&auml;ver mer kod och ger l&aring;ngsam &aring;tkomst via position. F&ouml;r k&ouml;er finns redan <code>deque</code>, och f&ouml;r data som ska indexeras snabbt &auml;r en vanlig lista i regel ett b&auml;ttre f&ouml;rstaval.</p><p>Om du &auml;nd&aring; bygger en egen implementation, b&ouml;rja med enkell&auml;nkad form och testa s&auml;rskilt tom lista, en enda nod och borttagning av svansen. D&aring; blir kedjan l&auml;ttare att f&ouml;rst&aring;, och buggarna sv&aring;rare att g&ouml;mma bakom till synes fungerande exempel.</p>]]></content:encoded>
      
      <category>Programmering och AI</category>
      <media:thumbnail url="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/thumbnail/4decf2be1c61dec4b662d70b35f292d7/lankad-lista-i-python-och-nar-den-faktiskt-passar.webp"/>
      <pubDate>Mon, 02 Nov 2026 15:54:00 +0100</pubDate>
    </item>
    <item>
      <title>Så gör CTE:er SQL-frågor tydligare och lättare att följa</title>
      <link>https://jelks.nu/sa-gor-cteer-sql-fragor-tydligare-och-lattare-att-folja</link>
      <description>Lär dig använda CTE:er för tydligare SQL-frågor, kedja beräkningssteg och förstå rekursion och prestandaskillnader. Läs guiden.</description>
      <content:encoded><![CDATA[<head></head><p>En rapportfråga börjar som en enda `SELECT`, men efter några nästlade delfrågor blir det svårt att se var resultatet faktiskt kommer ifrån. En CTE kan ge frågan tydliga, namngivna steg, men hur databasen kör dem beror på vilken SQL-motor du använder.</p>

<p><img src="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/post_image/4dd018b7b42786524e0f1a09a6f7a6b9/sql-common-table-expression-cte-query-flow-diagram-with-clause-example.webp" class="image article-image" loading="lazy" alt="Datadiagram visar hur CTE f_customer_sales skapas genom att joina tabeller."></p>

<div class="short-summary">
  <h2 id="en-cte-delar-upp-en-fraga-i-namngivna-steg">En CTE delar upp en fråga i namngivna steg</h2>
  <ul>
    <li><strong>WITH</strong> definierar ett tillfälligt namngivet resultat för en SQL-sats.</li>
    <li><strong>Flera CTE:er</strong> kan kedjas ihop och göra rapportfrågor lättare att följa.</li>
    <li><strong>Rekursiva CTE:er</strong> kan följa hierarkier, exempelvis kategorier med underkategorier.</li>
    <li><strong>Prestanda är inte garanterad</strong> av att en fråga skrivs med CTE.</li>
  </ul>
</div>

<h2 id="en-cte-gor-nastlade-sql-fragor-lattare-att-lasa">En CTE gör nästlade SQL-frågor lättare att läsa</h2>
<p>När en underfråga får ett namn blir det enklare att förstå vad nästa steg bygger på. En CTE, eller Common Table Expression, är ett <strong>namngivet frågeresultat</strong> som hör till en enskild SQL-sats, inte en permanent tabell.</p>
<p>Anta att du vill visa webbplatsens försäljning per land och bara ta med länder över en viss gräns. Du kan först summera orderraderna och sedan filtrera summeringen:</p>
<pre><code>WITH sales_by_country AS (
    SELECT country, SUM(order_total) AS revenue
    FROM orders
    GROUP BY country
)
SELECT country, revenue
FROM sales_by_country
WHERE revenue &gt; 10000
ORDER BY revenue DESC;</code></pre>
<p>Namnet `sales_by_country` gör rollen tydlig: den första frågan skapar en sammanställning, och den yttre frågan väljer ur den. <strong>Resultatet finns bara inom den här satsen</strong>, så en separat fråga kan inte använda namnet senare.</p>

<h2 id="flera-cteer-kan-gora-en-rapport-enklare-att-felsoka">Flera CTE:er kan göra en rapport enklare att felsöka</h2>
<p>När en rapport har flera beräkningssteg blir det frestande att pressa in allt i en enda fråga. Jag tycker att en CTE-kedja är ett bättre val när varje steg går att beskriva med ett tydligt namn och kontrollera för sig.</p>
<p>En webbplatsrapport kan till exempel först välja betalda ordrar, sedan summera intäkten per land och till sist visa de största marknaderna:</p>
<pre><code>WITH paid_orders AS (
    SELECT country, order_total
    FROM orders
    WHERE status = 'paid'
),
sales_by_country AS (
    SELECT country, SUM(order_total) AS revenue
    FROM paid_orders
    GROUP BY country
)
SELECT country, revenue
FROM sales_by_country
WHERE revenue &gt; 10000
ORDER BY revenue DESC;</code></pre>
<p>Varje CTE efter den första kan använda föregående definition. I den här frågan går det därför att kontrollera filtreringen före summeringen, vilket ofta gör fel i rapportlogik lättare att hitta än i en lång nästlad fråga.</p>

<h2 id="cte-betyder-inte-automatiskt-att-data-sparas-eller-kors-snabbare">CTE betyder inte automatiskt att data sparas eller körs snabbare</h2>
<p>Här finns en vanlig missuppfattning: en CTE ser ut som en tillfällig tabell, men <strong>namnet säger inte att databasen lagrar resultatet på det sättet</strong>. Exekveringen skiljer sig mellan databasmotorer, och en tydligare fråga blir inte av den anledningen automatiskt snabbare.</p>
<p>I SQL Server materialiseras CTE-resultat inte som standard; om samma CTE refereras flera gånger kan den definierande frågan köras om. Microsoft föreslår att man överväger ett tillfälligt objekt vid upprepade referenser. PostgreSQL har andra optimeringsregler: en enkel CTE som används en gång kan vanligtvis slås ihop med huvudfrågan, medan en CTE som används flera gånger normalt materialiseras. <a href="https://learn.microsoft.com/sql/t-sql/queries/with-common-table-expression-transact-sql" target="_blank" rel="noopener noreferrer nofollow">Microsoft Learn om CTE i Transact-SQL</a> och <a href="https://www.postgresql.org/docs/17/queries-with.html" target="_blank" rel="noopener noreferrer nofollow">PostgreSQLs dokumentation om WITH-frågor</a> beskriver dessa skillnader.</p>
<table>
  <tbody>
    <tr>
      <th scope="col">Situation</th>
      <th scope="col">Möjlig följd</th>
      <th scope="col">Gör så här</th>
    </tr>
    <tr>
      <td>CTE:n används en gång och gör frågan tydligare</td>
      <td>Optimeraren kan ofta behandla den som en del av huvudfrågan, beroende på motor.</td>
      <td>Behåll CTE:n om namnet hjälper dig att förstå logiken.</td>
    </tr>
    <tr>
      <td>Samma kostsamma CTE används flera gånger i SQL Server</td>
      <td>Den definierande frågan kan köras om vid varje referens.</td>
      <td>Jämför exekveringsplanen med en temporär tabell.</td>
    </tr>
    <tr>
      <td>En PostgreSQL-CTE används flera gånger och läser en stor tabell</td>
      <td>Materialisering kan hindra villkor från huvudfrågan från att skjutas ned till tabellskanningen.</td>
      <td>Kontrollera planen; testa vid behov `NOT MATERIALIZED` för en icke-rekursiv fråga utan bieffekter.</td>
    </tr>
  </tbody>
</table>
<strong>Beslutsregeln är enkel:</strong> välj CTE för läsbarhet, men använd en temporär tabell eller <a href="https://jelks.nu/sql-subqueries-och-skillnaden-mellan-in-exists-och-skalara-fragor">jämför exekveringsplaner</a> när en dyr del återanvänds. I PostgreSQL bör `NOT MATERIALIZED` testas mot den faktiska frågan, eftersom det kan leda till att beräkningen görs flera gånger.

<h2 id="rekursiva-cteer-foljer-hierarkier-steg-for-steg">Rekursiva CTE:er följer hierarkier steg för steg</h2>
<p>En organisationslista lagrar ofta varje persons chef, inte hela rapporteringskedjan. En rekursiv CTE kan börja med en person och sedan hitta nästa nivå genom att åter använda sitt eget resultat.</p>
<pre><code>WITH RECURSIVE team_tree AS (
    SELECT employee_id, manager_id, 0 AS level
    FROM employees
    WHERE employee_id = 42

    UNION ALL

    SELECT e.employee_id, e.manager_id, t.level + 1
    FROM employees AS e
    JOIN team_tree AS t
      ON e.manager_id = t.employee_id
)
SELECT employee_id, manager_id, level
FROM team_tree
ORDER BY level;</code></pre>
<p>Den första delen kallas ankardelen och hämtar startpersonen. Den andra delen hittar personer som rapporterar till rader från föregående nivå; arbetet fortsätter tills inga fler rader hittas. I PostgreSQL och MySQL skrivs `RECURSIVE` efter `WITH`, medan SQL Server inte använder det nyckelordet i CTE-syntaxen. <a href="https://learn.microsoft.com/en-us/sql/t-sql/queries/with-common-table-expression-transact-sql" target="_blank" rel="noopener noreferrer nofollow">SQL Servers dokumentation om rekursiva CTE:er</a> beskriver ankardel och rekursiv del.</p>
<p>Rekursion behöver ett tydligt stoppvillkor. Om tabellen innehåller en cirkel i relationerna kan sökningen fortsätta oväntat länge; i SQL Server går det att sätta en gräns med `MAXRECURSION`, medan PostgreSQL erbjuder bland annat en `CYCLE`-klausul för cykeldetektering. Anpassa syntaxen till din databas och kontrollera att hierarkin verkligen ska omfatta alla nivåer.</p>

<h2 id="valj-cte-underfraga-eller-temporar-tabell-efter-behov">Välj CTE, underfråga eller temporär tabell efter behov</h2>
<p>Det finns ingen syntax som passar bäst för alla frågor. För ett enda tydligt beräkningssteg kan en underfråga räcka; när flera steg behöver namn blir en CTE ofta lättare att läsa; och när ett stort mellanresultat återanvänds kan en temporär tabell vara mer lämplig.</p>
<ul>
  <li><strong>Välj CTE</strong> när frågan har logiska steg eller behöver rekursion.</li>
  <li><strong>Välj underfråga</strong> när beräkningen är liten och bara används på ett ställe.</li>
  <li><strong>Testa temporär tabell</strong> när samma omfattande resultat behövs flera gånger eller när du vill inspektera mellanresultatet separat.</li>
</ul>
<p>Om du bygger en SQL-rapport för exempelvis webbplatsens försäljning skulle jag välja CTE för ett par tydliga sammanställningssteg, men jämföra med en temporär tabell om den dyraste sammanställningen återanvänds. Då får du läsbar kod utan att anta att CTE-namnet i sig förbättrar körningen.</p>
<h2 id="en-lasbar-fraga-ar-lattare-att-kontrollera">En läsbar fråga är lättare att kontrollera</h2>
<p>Se CTE:n som ett sätt att ge delresultat begripliga namn, inte som en ny tabell eller prestandagaranti. Börja med en CTE när den gör logiken tydligare, och låt <strong>exekveringsplanen avgöra</strong> om upplägget också fungerar bra för din databas.</p>]]></content:encoded>
      
      <category>Databaser och SQL</category>
      <media:thumbnail url="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/thumbnail/404056538ee080930d811ee539ea62cd/sa-gor-cteer-sql-fragor-tydligare-och-lattare-att-folja.webp"/>
      <pubDate>Mon, 02 Nov 2026 13:15:00 +0100</pubDate>
    </item>
    <item>
      <title>Lägg till en kolumn i SQL utan att missa viktiga skillnader</title>
      <link>https://jelks.nu/lagg-till-en-kolumn-i-sql-utan-att-missa-viktiga-skillnader</link>
      <description>Lär dig använda ALTER TABLE ADD COLUMN i PostgreSQL, MySQL, SQL Server och SQLite, och hantera befintliga rader säkert. Se stegen här.</description>
      <content:encoded><![CDATA[<p>Tabellen fungerar, men formuläret behöver plötsligt lagra en ny uppgift, till exempel en kampanjkod eller ett publiceringsdatum. Vanligen lägger du till kolumnen med <code>ALTER TABLE ... ADD COLUMN</code>, men exakt syntax och vad som händer med befintliga rader beror på databasen.</p>

<p><img src="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/post_image/605ea550aa39b5540de702c4c43e408c/sql-alter-table-add-column-database-table-example-diagram.webp" class="image article-image" loading="lazy" alt="Databasdiagram som visar tabeller som `playlists`, `tracks` och `invoice_items`. Kolumnen `sql` är synlig i tabellen `tracks`."></p>

<div class="short-summary">
  <h2 id="ratt-syntax-beror-pa-databasmotorn-och-kolumnens-regler">Rätt syntax beror på databasmotorn och kolumnens regler</h2>
  <ul>
    <li><strong>Grundmönstret:</strong> <code>ALTER TABLE tabell ADD COLUMN kolumn datatyp;</code></li>
    <li><strong>Befintliga rader:</strong> en ny kolumn kan ge dem <code>NULL</code> eller ett standardvärde, beroende på definitionen.</li>
    <li><strong>NOT NULL:</strong> kontrollera att varje befintlig rad kan få ett giltigt värde innan kolumnen görs obligatorisk.</li>
    <li><strong>Kolumnordning:</strong> SQL Server lägger nya kolumner sist; MySQL har särskild syntax för en annan placering.</li>
    <li><strong>SQLite:</strong> har begränsningar för vilka kolumndefinitioner som kan läggas till direkt.</li>
  </ul>
</div>

<h2 id="borja-med-en-nullable-kolumn-om-befintliga-rader-saknar-varde">Börja med en nullable kolumn om befintliga rader saknar värde</h2>
<p>Om du vill lägga till exempelvis en kort beskrivning i en redan använd tabell kan grundkommandot se ut så här:</p>
<pre><code>ALTER TABLE products
ADD COLUMN description TEXT;</code></pre>
<p>Med den här definitionen får äldre rader normalt <code>NULL</code> i den nya kolumnen. Det är ofta den minst riskabla starten när appen behöver tid att börja fylla fältet, men det finns en hake om kolumnen ska vara obligatorisk.</p>
<p>En kolumn med <code>NOT NULL</code> får inte sakna värde. Om tabellen redan innehåller rader måste databasmotorn kunna ge dem ett tillåtet värde, vanligtvis via ett standardvärde. I <a href="https://www.postgresql.org/docs/18/sql-altertable.html" target="_blank" rel="noopener noreferrer nofollow">PostgreSQLs dokumentation om ALTER TABLE</a> framgår också att kommandot kan kräva ett starkt lås på tabellen. För en stor, aktiv tabell bör ändringen därför planeras så att den inte överraskar pågående trafik.</p>

<h2 id="valj-syntax-efter-databasmotorn-inte-efter-ett-allmant-sql-exempel">Välj syntax efter databasmotorn, inte efter ett allmänt SQL-exempel</h2>
<p>Samma idé uttrycks lite olika mellan databaser. Ett kommando som fungerar i en produkt kan fallera i en annan, särskilt när du lägger till en kolumn på en viss position.</p>
<table>
  <tbody>
    <tr>
      <th>Databas</th>
      <th>Exempel</th>
      <th>Praktisk skillnad</th>
    </tr>
    <tr>
      <td>PostgreSQL</td>
      <td><code>ALTER TABLE products ADD COLUMN description TEXT;</code></td>
      <td><code>IF NOT EXISTS</code> kan användas för att undvika fel om kolumnen redan finns.</td>
    </tr>
    <tr>
      <td>MySQL</td>
      <td><code>ALTER TABLE products ADD COLUMN description TEXT;</code></td>
      <td><code>AFTER column_name</code> eller <code>FIRST</code> kan placera kolumnen på en viss position.</td>
    </tr>
    <tr>
      <td>SQL Server</td>
      <td><code>ALTER TABLE dbo.products ADD description NVARCHAR(200) NULL;</code></td>
      <td>En kolumn som läggs till med T-SQL hamnar sist i tabellen.</td>
    </tr>
    <tr>
      <td>SQLite</td>
      <td><code>ALTER TABLE products ADD COLUMN description TEXT;</code></td>
      <td>Vissa definitioner, som en ny <code>NOT NULL</code>-kolumn utan ett icke-NULL-standardvärde, tillåts inte.</td>
    </tr>
  </tbody>
</table>
<p>Skillnaden kring placering är lätt att missa. <a href="https://dev.mysql.com/doc/refman/8.0/en/alter-table.html" target="_blank" rel="noopener noreferrer nofollow">MySQLs ALTER TABLE-dokumentation</a> beskriver <code>FIRST</code> och <code>AFTER</code>, medan <a href="https://learn.microsoft.com/en-us/sql/relational-databases/tables/add-columns-to-a-table-database-engine" target="_blank" rel="noopener noreferrer nofollow">Microsofts guide för SQL Server</a> anger att T-SQL lägger till kolumnen sist. Jag tycker att det oftast är bättre att styra visningsordningen i en fråga eller i gränssnittet än att bygga om tabellen bara för kolumnordningens skull.</p>

<h2 id="om-tillagget-misslyckas-ar-null-regeln-ofta-forsta-kontrollen">Om tillägget misslyckas är NULL-regeln ofta första kontrollen</h2>
<p>Felmeddelandet pekar ofta mot en konflikt mellan kolumnens krav och tabellens befintliga innehåll. Kontrollera först om kolumnen redan finns, om datatypen passar och om den nya definitionen kräver värden som äldre rader inte har.</p>
<table>
  <tbody>
    <tr>
      <th>Situation</th>
      <th>Trolig orsak</th>
      <th>Gör så här</th>
    </tr>
    <tr>
      <td>Kommandot klagar på att kolumnen redan finns</td>
      <td>Skriptet har körts tidigare eller miljön har redan ändrats.</td>
      <td>Kontrollera tabellens schema och använd en databasspecifik lösning för upprepade migreringar.</td>
    </tr>
    <tr>
      <td>En obligatorisk kolumn kan inte läggas till</td>
      <td>Äldre rader saknar ett giltigt värde.</td>
      <td>Lägg först till kolumnen som nullable, fyll den med data och inför sedan <code>NOT NULL</code>.</td>
    </tr>
    <tr>
      <td>SQLite avvisar standardvärdet</td>
      <td>SQLite begränsar bland annat uttryck och vissa tidsfunktioner som standardvärde vid direkt tillägg.</td>
      <td>Använd ett tillåtet konstant standardvärde eller planera en migrering med ny tabell och datakopiering.</td>
    </tr>
    <tr>
      <td>Kolumnen hamnar på fel plats</td>
      <td>Ordningen styrs av databasmotorn och kommandot.</td>
      <td>Ändra kolumnordningen i SELECT-frågan eller i presentationen i stället för att anta att SQL är portabelt.</td>
    </tr>
  </tbody>
</table>
<p>SQLite har särskilda begränsningar när en kolumn läggs till, bland annat kring <code>NOT NULL</code> och standardvärden. <a href="https://www.sqlite.org/lang_altertable.html" target="_blank" rel="noopener noreferrer nofollow">SQLite-dokumentationen om ALTER TABLE</a> beskriver också att tillägg utan vissa kontroller kan gå snabbt eftersom tabellens innehåll inte behöver skrivas om. Med begränsningar som måste verifieras kan arbetet däremot ta längre tid.</p>

<h2 id="fyll-kolumnen-i-steg-innan-du-gor-den-obligatorisk">Fyll kolumnen i steg innan du gör den obligatorisk</h2>
<p>En trygg migrering för en kolumn som så småningom måste ha ett värde sker ofta stegvis. Då hinner databasen, applikationskoden och befintliga poster komma i takt i stället för att allt ändras på en gång.</p>
<ol>
  <li>Lägg till kolumnen som tillåter <code>NULL</code>.</li>
  <li>Uppdatera applikationen så att nya poster sparar ett värde i kolumnen.</li>
  <li>Fyll kolumnen för äldre rader med relevanta värden, med en <code>UPDATE</code>-fråga eller en kontrollerad datamigrering.</li>
  <li>Kontrollera att inga rader fortfarande saknar värde.</li>
  <li>Lägg till <code>NOT NULL</code> när datan uppfyller kravet och databasmotorn stöder ändringen.</li>
</ol>
<p>Ta en kampanjtabell som exempel: nya registreringar ska få fältet <code>source</code>, men äldre poster har ingen känd källa. Att direkt sätta ett påhittat standardvärde kan förvanska rapporteringen; börja hellre med ett tomt fält och fyll bara i sådant som går att härleda. För <a href="https://www.sqlite.org/lang_altertable.html" target="_blank" rel="noopener noreferrer nofollow">SQLite</a> behöver du dessutom välja en metod som följer motorns begränsningar om schemat kräver mer än ett enkelt kolumntillägg.</p>

<h2 id="en-liten-schemamigrering-blir-sakrare-med-en-kontroll-fore-driftsattning">En liten schemamigrering blir säkrare med en kontroll före driftsättning</h2>
<p>Innan du kör ändringen i produktion, kontrollera databastyp, tabellnamn, datatyp och kolumnens null-regel i den miljö där kommandot ska köras. Kör migreringen mot en kopia eller testmiljö först om tabellen är viktig eller stor.</p>
<p>Kontrollera även kod som läser rader med positionsbaserad logik eller använder <code>SELECT *</code>; ett nytt fält kan påverka antaganden utanför själva databasen. När syftet är tydligt och befintliga rader hanteras medvetet blir tillägget oftast enkelt, även om rätt syntax beror på motorn.</p>]]></content:encoded>
      
      <category>Databaser och SQL</category>
      <media:thumbnail url="https://frce8xp4ye4n.compat.objectstorage.eu-frankfurt-1.oraclecloud.com/blog-assets/thumbnail/6fb5b4a21a6f454b25862c95af37cf1a/lagg-till-en-kolumn-i-sql-utan-att-missa-viktiga-skillnader.webp"/>
      <pubDate>Mon, 02 Nov 2026 12:09:00 +0100</pubDate>
    </item>
  </channel>
</rss>