<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: kdkumawat</title>
    <description>The latest articles on DEV Community by kdkumawat (@kdkumawat).</description>
    <link>https://dev.to/kdkumawat</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4204231%2Fc84b3346-b07f-47ee-92a9-eaa29a706949.png</url>
      <title>DEV Community: kdkumawat</title>
      <link>https://dev.to/kdkumawat</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kdkumawat"/>
    <language>en</language>
    <item>
      <title>How to find missing IDs between two lists (and get the SQL for free)</title>
      <dc:creator>kdkumawat</dc:creator>
      <pubDate>Sat, 24 Oct 2026 08:18:46 +0000</pubDate>
      <link>https://dev.to/kdkumawat/how-to-find-missing-ids-between-two-lists-and-get-the-sql-for-free-3dpk</link>
      <guid>https://dev.to/kdkumawat/how-to-find-missing-ids-between-two-lists-and-get-the-sql-for-free-3dpk</guid>
      <description>&lt;p&gt;You have two exports. One is the source of truth (every paying customer in billing), the other is what you're auditing (customers synced to the CRM). The question is always the same: &lt;strong&gt;which IDs are in the first list but missing from the second?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here are three ways to answer it, depending on where the data lives.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Both lists are already in the database
&lt;/h2&gt;

&lt;p&gt;Use an anti-join. &lt;code&gt;NOT EXISTS&lt;/code&gt; is the safe default because it behaves correctly when the other side contains &lt;code&gt;NULL&lt;/code&gt;s (&lt;code&gt;NOT IN&lt;/code&gt; does not):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;billing&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;crm&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, if your database supports it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;customer_id&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;billing&lt;/span&gt;
&lt;span class="k"&gt;EXCEPT&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;customer_id&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;crm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. One list is in a spreadsheet, the other in the database
&lt;/h2&gt;

&lt;p&gt;Turn the pasted list into rows with &lt;code&gt;VALUES&lt;/code&gt;, then anti-join against the table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'1001'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'1002'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'1003'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'1004'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;crm&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Building that &lt;code&gt;VALUES&lt;/code&gt; list by hand for a few thousand IDs is the annoying part.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Both lists are just text (CSV exports, Slack pastes, log output)
&lt;/h2&gt;

&lt;p&gt;This is the case I hit most, so I built a tool for it. In &lt;a href="https://formaty.dev/compare-lists" rel="noopener noreferrer"&gt;Formaty's Compare Lists&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Put the complete list on the left.&lt;/strong&gt; It's the reference set.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   1001
   1002
   1003
   1004
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Paste the list you're checking on the right.&lt;/strong&gt; It can be shorter, longer or contain duplicates.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   1002
   1003
   1005
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Read the "Only in left" bucket.&lt;/strong&gt; Those are the missing IDs. Copy them as SQL:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;   &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'1001'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'1004'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same bucket can be copied as &lt;code&gt;IN (...)&lt;/code&gt;, &lt;code&gt;VALUES&lt;/code&gt; rows, JSON, CSV or Markdown, and you also get "Only in right", "Common" and "Duplicates".&lt;/p&gt;

&lt;p&gt;Delimiters are auto-detected (newlines, commas, semicolons, pipes, JSON arrays), so you can paste raw query output as-is. It runs entirely in your browser in a Web Worker, so 50k+ IDs compare in well under a second and nothing is uploaded.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What if my IDs are strings, like UUIDs?&lt;/strong&gt; Comparison is exact, and the SQL export quotes values correctly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I compare more than two lists?&lt;/strong&gt; Chain it: compare A vs B, then compare the result with C.&lt;/p&gt;




&lt;p&gt;Formaty is free and open source (&lt;a href="https://github.com/kdkumawat/formaty" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;). Besides list compare it does JSON diff, JSON to TypeScript/Zod/SQL, cURL to code and more. Here's a &lt;a href="https://youtu.be/G1DtZnSSZEM" rel="noopener noreferrer"&gt;60-second demo&lt;/a&gt;. Feedback welcome in the comments.&lt;/p&gt;

</description>
      <category>sql</category>
      <category>database</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
