<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged reference</title>
<link>https://coderlegion.com/tag/reference</link>
<description>Powered by Question2Answer</description>
<item>
<title>Regular Expression - A Comprehensive Guide</title>
<link>https://coderlegion.com/3193/regular-expression-a-comprehensive-guide</link>
<description>&lt;p&gt;(Originally posted on Methodox Wiki, visit &lt;a rel=&quot;nofollow&quot; href=&quot;https://wiki.methodox.io/en/KnowledgeBase/Regex&quot;&gt;the page&lt;/a&gt; for a live tester!)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Contents&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#h-1-introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#h-2-live-tester&quot;&gt;Live Tester&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#h-3-practical-syntax&quot;&gt;Practical Syntax&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#h-4-comprehensive-reference&quot;&gt;Comprehensive Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#h-5-conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;(Due to CoderLegion content length limit, section 4 is ommitted)&lt;/p&gt;
&lt;h3 id=&quot;1-introduction&quot;&gt;1. Introduction&lt;/h3&gt;
&lt;p&gt;Text - whether it’s log files, configuration data, user input, or documents - is everywhere in programming. From simple scripts to full-blown applications, developers frequently need to &lt;strong&gt;search&lt;/strong&gt;, &lt;strong&gt;validate&lt;/strong&gt;, &lt;strong&gt;extract&lt;/strong&gt;, or &lt;strong&gt;transform&lt;/strong&gt; pieces of text. While many IDEs and editors (like Notepad++, VS Code, or Sublime Text) offer basic find-and-replace functionality, they quickly reach their limits when you need to handle patterns, conditional logic, or repeated structures. That’s where &lt;strong&gt;regular expressions&lt;/strong&gt; (regex) come in.&lt;/p&gt;
&lt;p&gt;At its core, a regular expression is a compact, declarative way to describe a set of strings. Instead of manually scanning through text to find, say, all warning messages in a log, you can write a single pattern that matches timestamps, log levels, filenames, email addresses, URLs - you name it. Once you understand the fundamentals, regex can become one of the most powerful “weapons” in your developer toolbox.&lt;/p&gt;
&lt;p&gt;Consider a typical log snippet:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2025-05-31 14:23:48 [Info] Starting application...
2025-05-31 14:23:50 [Info] Loading application data...
2025-05-31 14:23:55 [Warning] Missing font file: New Times Roman.
2025-05-31 14:24:22 [Info] The application has started, with 1 warning.
2025-05-31 14:25:01 [Error] Unhandled exception: NullReferenceException.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you want to answer questions like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“What warnings were emitted, and when?”&lt;/li&gt;
&lt;li&gt;“Which lines contain error messages?”&lt;/li&gt;
&lt;li&gt;“How many times did the application start?”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You could write a script in your favorite language that splits on spaces, checks tokens, and does string comparisons. But that quickly becomes tedious: parsing variability in timestamps, handling optional fields, or ignoring whitespace quirks can make your code fragile.&lt;/p&gt;
&lt;p&gt;With a well-crafted regex, however, you can match on the entire log line, capture the timestamp, the log level, and the rest of the message - all in one pattern. More importantly, regex can handle &lt;strong&gt;any&lt;/strong&gt; text-based format for which there’s a consistent structure: CSV files, HTML/XML tags, custom configuration formats, and so on.&lt;/p&gt;
&lt;p&gt;By the end of this article, you will:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Understand the basic motivation behind regular expressions.&lt;/li&gt;
&lt;li&gt;See practical syntax elements and examples for day-to-day tasks.&lt;/li&gt;
&lt;li&gt;Have a handy reference that summarizes the most commonly used regex constructs.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Whether you’ve done a bit of “find and replace” in an editor, or you’ve written simple string processing code, this guide will bridge the gap and show you how to level up with regular expressions.&lt;/p&gt;
&lt;h3 id=&quot;2-live-tester&quot;&gt;2. Live Tester&lt;/h3&gt;
&lt;p&gt;See &lt;a rel=&quot;nofollow&quot; href=&quot;https://wiki.methodox.io/en/KnowledgeBase/Regex#h-2-live-tester&quot;&gt;original post&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;3-practical-syntax&quot;&gt;3. Practical Syntax&lt;/h3&gt;
&lt;p&gt;In this section, we’ll cover the core building blocks of regex patterns. Each subsection introduces a concept, followed by real-world examples - some based on log processing, others on everyday tasks like validating email addresses or extracting numbers from text.&lt;/p&gt;
&lt;h4 id=&quot;3-1-literal-characters-and-simple-matches&quot;&gt;3.1 Literal Characters and Simple Matches&lt;/h4&gt;
&lt;p&gt;At the simplest level, a regex can be just literal characters. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pattern &lt;code&gt;Error&lt;/code&gt; will match any occurrence of the substring “Error” in a text.&lt;/li&gt;
&lt;li&gt;Pattern &lt;code&gt;2025-05-31&lt;/code&gt; will match that exact date string.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, real-world text rarely lines up perfectly. Log messages, for instance, include varying timestamps and different log levels. To match them in a generic way, you need &lt;strong&gt;metacharacters&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Key Point:&lt;/strong&gt; Most characters in a regex match themselves literally, except for special metacharacters (like &lt;code&gt;.&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt;, &lt;code&gt;?&lt;/code&gt;, &lt;code&gt;\&lt;/code&gt;, etc.). To match a literal period, bracket, or other metacharacter, you must “escape” it with a backslash (&lt;code&gt;\.&lt;/code&gt; to match a literal dot, &lt;code&gt;\[&lt;/code&gt; to match a literal left bracket, and so on).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;3-2-character-classes-and-ranges&quot;&gt;3.2 Character Classes (&lt;code&gt;[]&lt;/code&gt;) and Ranges&lt;/h4&gt;
&lt;p&gt;A &lt;strong&gt;character class&lt;/strong&gt; is a bracketed set of characters that match exactly one character from the set. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[AEIOU]&lt;/code&gt; matches any single uppercase vowel.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[0-9]&lt;/code&gt; matches any digit from 0 through 9.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[A-Za-z0-9_]&lt;/code&gt; matches a typical word character (letter, digit, or underscore).&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;example-1-matching-a-four-digit-year&quot;&gt;Example 1: Matching a Four-Digit Year&lt;/h5&gt;
&lt;p&gt;Suppose you want to match any year between 1900 and 2099:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;^(19|20)[0-9]{2}$
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;^&lt;/code&gt; and &lt;code&gt;$&lt;/code&gt; are &lt;strong&gt;anchors&lt;/strong&gt; (we’ll cover them in a moment).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(19|20)&lt;/code&gt; matches either “19” or “20”.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[0-9]{2}&lt;/code&gt; matches exactly two digits.&lt;/li&gt;
&lt;li&gt;Altogether, this matches “1900” through “2099”.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;example-2-extracting-log-levels&quot;&gt;Example 2: Extracting Log Levels&lt;/h5&gt;
&lt;p&gt;Given a log line like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2025-05-31 14:23:55 [Warning] Missing font file: New Times Roman.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can match the log level (&lt;code&gt;Info&lt;/code&gt;, &lt;code&gt;Warning&lt;/code&gt;, &lt;code&gt;Error&lt;/code&gt;, etc.) with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;\[(Info|Warning|Error|Debug)\]
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;\[` and `\]&lt;/code&gt; match literal square brackets.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(Info|Warning|Error|Debug)&lt;/code&gt; matches one of those four words.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you expect additional levels (e.g., &lt;code&gt;Trace&lt;/code&gt; or &lt;code&gt;Fatal&lt;/code&gt;), you can add them inside the parentheses:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;\[(?:Info|Warning|Error|Debug|Trace|Fatal)\]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here we’ve used &lt;code&gt;(?: … )&lt;/code&gt; to create a &lt;strong&gt;non-capturing group&lt;/strong&gt; (we’ll talk about groups more in section 5).&lt;/p&gt;
&lt;h4 id=&quot;3-3-quantifiers-repetition-control&quot;&gt;3.3 Quantifiers: Repetition Control&lt;/h4&gt;
&lt;p&gt;Quantifiers specify how many times the preceding element should match. The most common quantifiers are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;*&lt;/code&gt; – Match zero or more times (greedy).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;+&lt;/code&gt; – Match one or more times (greedy).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;?&lt;/code&gt; – Match zero or one time (makes the preceding token optional).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{n}&lt;/code&gt; – Match exactly &lt;em&gt;n&lt;/em&gt; times.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{n,m}&lt;/code&gt; – Match between &lt;em&gt;n&lt;/em&gt; and &lt;em&gt;m&lt;/em&gt; times (inclusive).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;{n,}&lt;/code&gt; – Match &lt;em&gt;n&lt;/em&gt; or more times.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;example-3-matching-timestamps&quot;&gt;Example 3: Matching Timestamps&lt;/h5&gt;
&lt;p&gt;A timestamp like &lt;code&gt;2025-05-31 14:23:48&lt;/code&gt; can be matched with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;\d&lt;/code&gt; is shorthand for &lt;code&gt;[0-9]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\d{4}&lt;/code&gt; matches exactly four digits (the year).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-&lt;/code&gt; matches a literal hyphen.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\d{2}&lt;/code&gt; matches two digits (month and day).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\s+&lt;/code&gt; matches one or more whitespace characters (space, tab).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\d{2}:\d{2}:\d{2}&lt;/code&gt; matches &lt;code&gt;HH:MM:SS&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you’re sure there’s exactly one space between date and time, you could use &lt;code&gt;\s&lt;/code&gt; instead of &lt;code&gt;\s+&lt;/code&gt;.&lt;/p&gt;
&lt;h5 id=&quot;example-4-optional-file-extension&quot;&gt;Example 4: Optional File Extension&lt;/h5&gt;
&lt;p&gt;Suppose you have filenames like &lt;code&gt;report.txt&lt;/code&gt; or &lt;code&gt;report&lt;/code&gt;. To match both, you could use:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;^report(?:\.txt)?$
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;^&lt;/code&gt; and &lt;code&gt;$&lt;/code&gt; ensure we match the entire string.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;(?:\.txt)?&lt;/code&gt; means “optionally match ‘.txt’”.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;\.&lt;/code&gt; matches a literal dot.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;txt&lt;/code&gt; matches “txt”.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;?&lt;/code&gt; after the group makes it optional.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;3-4-anchors-positioning-matches&quot;&gt;3.4 Anchors: Positioning Matches&lt;/h4&gt;
&lt;p&gt;Anchors specify positions in the text rather than actual characters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;^&lt;/code&gt; – Start of the line/string.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$&lt;/code&gt; – End of the line/string.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\b&lt;/code&gt; – Word boundary (between &lt;code&gt;\w&lt;/code&gt; and &lt;code&gt;\W&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\B&lt;/code&gt; – Non-word boundary.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;example-5-lines-starting-with-error-&quot;&gt;Example 5: Lines Starting with “Error”&lt;/h5&gt;
&lt;p&gt;If you want to catch any line that begins with the word “Error” (as a standalone word), you can write:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;^Error\b.*$
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;^Error&lt;/code&gt; ensures the line starts with “Error”.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\b&lt;/code&gt; asserts a word boundary so that “Errors” or “ErrorCode” are not matched.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.*&lt;/code&gt; matches the rest of the line (any character, zero or more times).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;$&lt;/code&gt; anchors the end of line.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;3-5-groups-and-capturing&quot;&gt;3.5 Groups and Capturing&lt;/h4&gt;
&lt;p&gt;Parentheses &lt;code&gt;(&lt;/code&gt; and &lt;code&gt;)&lt;/code&gt; serve two main purposes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Grouping&lt;/strong&gt;: Treat multiple tokens as a single unit (often used with quantifiers or alternation).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Capturing&lt;/strong&gt;: Store the text matched by that group for later retrieval (in code or in a replacement string).&lt;/li&gt;
&lt;/ol&gt;
&lt;h5 id=&quot;example-6-capturing-timestamps-and-levels&quot;&gt;Example 6: Capturing Timestamps and Levels&lt;/h5&gt;
&lt;p&gt;Given:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2025-05-31 14:23:55 [Warning] Missing font...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You might write:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;^(\d{4}-\d{2}-\d{2})\s+(\d{2}:\d{2}:\d{2})\s+\[(Info|Warning|Error|Debug)\]\s+(.*)$
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;(\d{4}-\d{2}-\d{2})&lt;/code&gt; captures the date (&lt;code&gt;Group 1&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(\d{2}:\d{2}:\d{2})&lt;/code&gt; captures the time (&lt;code&gt;Group 2&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(Info|Warning|Error|Debug)&lt;/code&gt; captures the log level (&lt;code&gt;Group 3&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(.*)&lt;/code&gt; captures the rest of the message (&lt;code&gt;Group 4&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In most languages, after matching, you can extract Group 1, Group 2, etc.:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;e.g., in C#: &lt;code&gt;match.Groups[1].Value&lt;/code&gt; gives the date.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you want to group without capturing (for alternation or quantifier purposes), use &lt;code&gt;(?: … )&lt;/code&gt;. For instance:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(?:Info|Warning|Error|Debug)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;does &lt;strong&gt;not&lt;/strong&gt; create a numbered backreference.&lt;/p&gt;
&lt;h4 id=&quot;3-6-common-metacharacters-and-escape-sequences&quot;&gt;3.6 Common Metacharacters and Escape Sequences&lt;/h4&gt;
&lt;p&gt;Some of the most frequently used shorthand and metacharacters include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.&lt;/code&gt; – Matches any character except newline (in most flavors; some allow a “dotall” mode to match newline).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\d&lt;/code&gt; – Digit (equivalent to &lt;code&gt;[0-9]&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\D&lt;/code&gt; – Non-digit (equivalent to &lt;code&gt;[^0-9]&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\w&lt;/code&gt; – Word character (letter, digit, underscore; &lt;code&gt;[A-Za-z0-9_]&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\W&lt;/code&gt; – Non-word character (anything not in &lt;code&gt;\w&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\s&lt;/code&gt; – Whitespace character (space, tab, newline, etc.).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\S&lt;/code&gt; – Non-whitespace character.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\t&lt;/code&gt;, &lt;code&gt;\n&lt;/code&gt;, &lt;code&gt;\r&lt;/code&gt; – Tab, newline, carriage return.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; When writing regexes in code, you often need to escape backslashes. For instance, in C# you can use verbatim string literals (&lt;code&gt;@&quot;\d{4}-\d{2}-\d{2}&quot;&lt;/code&gt;) to avoid double escapes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id=&quot;3-7-practical-example-extracting-email-addresses&quot;&gt;3.7 Practical Example: Extracting Email Addresses&lt;/h4&gt;
&lt;p&gt;Say you have a document or a configuration file and need to pull out all email addresses. A simple - but not fully RFC‑compliant - pattern is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;\b&lt;/code&gt; – Ensure we start at a word boundary.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[A-Za-z0-9._%+-]+&lt;/code&gt; – One or more letters, digits, dots, underscores, percent signs, plus, or hyphens (the local part before the &lt;code&gt;@&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@&lt;/code&gt; – Literal “@” symbol.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[A-Za-z0-9.-]+&lt;/code&gt; – One or more letters, digits, dots, or hyphens (domain).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\.&lt;/code&gt; – Literal dot.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[A-Za-z]{2,}&lt;/code&gt; – At least two letters for the TLD (e.g., “com”, “org”, “io”).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\b&lt;/code&gt; – End at a word boundary to prevent partial matches (so we don’t match trailing punctuation).&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;testing-it&quot;&gt;Testing It&lt;/h5&gt;
&lt;p&gt;Given:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Please contact *Emails are not allowed* or *Emails are not allowed* for more info. Alternatively, reach out to admin@localhost if testing locally.
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;*Emails are not allowed*&lt;/code&gt; matches.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;*Emails are not allowed*&lt;/code&gt; matches.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;admin@localhost&lt;/code&gt; does &lt;strong&gt;not&lt;/strong&gt; match because &lt;code&gt;localhost&lt;/code&gt; has no “&lt;code&gt;.&lt;/code&gt; + two-or-more-letters” TLD.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;3-8-practical-example-validating-north-american-phone-numbers&quot;&gt;3.8 Practical Example: Validating North American Phone Numbers&lt;/h4&gt;
&lt;p&gt;North American Numbering Plan (NANP) phone numbers often look like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;123-456-7890&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(123) 456-7890&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;123.456.7890&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;+1 (123) 456-7890&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A practical regex might be:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;^(\+1\s?)?           # Optional country code +1 and a space
(?:\(\d{3}\)|\d{3})  # Either (123) or 123
[ .-]?               # Separator: space, dot, or hyphen (optional)
\d{3}                # Next three digits
[ .-]?               # Separator again (optional)
\d{4}$               # Last four digits
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When compacted (and removing whitespace/comments):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;^(\+1\s?)?(?:\(\d{3}\)|\d{3})[ .-]?\d{3}[ .-]?\d{4}$
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;^&lt;/code&gt; and &lt;code&gt;$&lt;/code&gt; anchor the pattern to the entire string.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(\+1\s?)?&lt;/code&gt; – Optionally match “+1” followed by an optional space.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(?:\(\d{3}\)|\d{3})&lt;/code&gt; – Either three digits inside parentheses or three digits without.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[ .-]?&lt;/code&gt; – Optionally match a space, a dot, or a hyphen.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\d{3}&lt;/code&gt; – Three digits.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;[ .-]?&lt;/code&gt; – Separator again.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\d{4}&lt;/code&gt; – Four digits.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This pattern will match most common North American formats. By tweaking the groups and quantifiers, you can adapt it for other regions or stricter/looser rules.&lt;/p&gt;
&lt;h4 id=&quot;3-9-practical-example-parsing-log-files&quot;&gt;3.9 Practical Example: Parsing Log Files&lt;/h4&gt;
&lt;p&gt;Returning to our log example, suppose you want to extract &lt;strong&gt;only&lt;/strong&gt; the warning messages and their timestamps. You might apply a regex like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;^(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})\s+\[Warning\]\s+(.*)$
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Group 1&lt;/strong&gt; captures the timestamp (&lt;code&gt;2025-05-31 14:23:55&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Group 2&lt;/strong&gt; captures the message itself (&lt;code&gt;Missing font file: New Times Roman.&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In most programming languages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;C#&lt;/strong&gt; (using &lt;code&gt;System.Text.RegularExpressions&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;var pattern = @&quot;^(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})\s+\[Warning\]\s+(.*)$&quot;;
var matches = Regex.Matches(logContents, pattern, RegexOptions.Multiline);
foreach (Match m in matches) {
    string timestamp = m.Groups[1].Value;
    string message   = m.Groups[2].Value;
    Console.WriteLine($&quot;[{timestamp}] Warning: {message}&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Python&lt;/strong&gt; (using the &lt;code&gt;re&lt;/code&gt; module):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import re

pattern = r'^(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})\s+\[Warning\]\s+(.*)$'
for line in log_contents.splitlines():
    m = re.match(pattern, line)
    if m:
        timestamp = m.group(1)
        message   = m.group(2)
        print(f&quot;[{timestamp}] Warning: {message}&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Even if you’ve only ever clicked “Replace” in an editor, these examples should give you a clear sense of how powerful a single regex can be. You define &lt;strong&gt;“match everything up until &lt;code&gt;[&lt;/code&gt;Warning&lt;code&gt;]&lt;/code&gt;, then capture whatever comes next”&lt;/strong&gt;, and you get exactly the data you want.&lt;/p&gt;
&lt;h4 id=&quot;3-10-testing-and-debugging-regex&quot;&gt;3.10 Testing and Debugging Regex&lt;/h4&gt;
&lt;p&gt;When you’re new to regex, it’s easy to overlook small mistakes - missing an escape, misplacing a quantifier, forgetting an anchor. Here are a few tips:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use an Online Tester&lt;/strong&gt;&lt;br&gt;
Websites like &lt;a rel=&quot;nofollow&quot; href=&quot;https://regex101.com&quot;&gt;regex101.com&lt;/a&gt; (PCRE, JavaScript, Python), &lt;a rel=&quot;nofollow&quot; href=&quot;http://regexstorm.net/tester&quot;&gt;RegexStorm&lt;/a&gt; (for .NET), or &lt;a rel=&quot;nofollow&quot; href=&quot;https://regexr.com&quot;&gt;regexr.com&lt;/a&gt; let you type your pattern, paste test text, and see matches/highlights in real time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Start Simple, Then Grow&lt;/strong&gt;&lt;br&gt;
If you need a complex pattern, start with a small piece. For instance, test just &lt;code&gt;\d{4}-\d{2}-\d{2}&lt;/code&gt; on the date first, then add time, then add log level, etc.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Comment Your Patterns&lt;/strong&gt; (When Supported)&lt;br&gt;
Some languages/flavors support the “extended” or “free-spacing” mode, where you can add whitespace and &lt;code&gt;# comments&lt;/code&gt; inside your regex:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(?x)            # Enable free-spacing mode
^               # Start of line
(\d{4}-\d{2}-\d{2})   # Group 1: Date
\s+             # One or more spaces
(\d{2}:\d{2}:\d{2})   # Group 2: Time
\s+             # One or more spaces
\[Warning\]     # Literal [Warning]
\s+             # One or more spaces
(.*)            # Group 3: Message text
$
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This makes maintenance and future edits easier, especially for complex regexes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Escape Early&lt;/strong&gt;&lt;br&gt;
If you need to match special characters (&lt;code&gt;.&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt;, &lt;code&gt;?&lt;/code&gt;, &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;[&lt;/code&gt;, &lt;code&gt;]&lt;/code&gt;, &lt;code&gt;(&lt;/code&gt;, &lt;code&gt;)&lt;/code&gt;, &lt;code&gt;|&lt;/code&gt;, &lt;code&gt;^&lt;/code&gt;, &lt;code&gt;$&lt;/code&gt;, &lt;code&gt;\&lt;/code&gt;), always escape them with a backslash unless you explicitly want their special behavior.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;4-comprehensive-reference&quot;&gt;4. Comprehensive Reference&lt;/h3&gt;
&lt;p&gt;Omitted due to content length limit. Visit &lt;a rel=&quot;nofollow&quot; href=&quot;https://wiki.methodox.io/en/KnowledgeBase/Regex&quot;&gt;Methodox Wiki&lt;/a&gt; for more.&lt;/p&gt;
&lt;h3 id=&quot;5-conclusion&quot;&gt;5. Conclusion&lt;/h3&gt;
&lt;p&gt;By now you should have a solid grasp of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Why&lt;/strong&gt; regular expressions are invaluable for text processing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How&lt;/strong&gt; to write basic patterns: literals, character classes, quantifiers, anchors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How&lt;/strong&gt; to use groups, lookarounds, and backreferences for more advanced matching.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Which&lt;/strong&gt; tokens and constructs constitute the “core” of most practical regexes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Where&lt;/strong&gt; to look when you need to refresh your memory (the reference section above, or a site like &lt;a rel=&quot;nofollow&quot; href=&quot;http://regexstorm.net/reference&quot;&gt;regexstorm.net/reference&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With a few dozen minutes of practice - writing regexes against sample text - you’ll rapidly gain confidence. Remember:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Test early and often&lt;/strong&gt; in an online tester or your IDE’s “Find in Files” - seeing the matches in real time is far more enlightening than manually eyeballing code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Readability matters.&lt;/strong&gt; If the pattern becomes unreadable, use the free-spacing mode (&lt;code&gt;(?x)&lt;/code&gt;) and add comments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keep it simple&lt;/strong&gt; for common tasks. You rarely need the most arcane syntax; matching log levels, dates, email addresses, or basic CSV fields can usually be done with straightforward character classes and quantifiers.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once you’ve mastered the basics, you can explore more advanced topics like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Atomic grouping&lt;/strong&gt; and &lt;strong&gt;possessive quantifiers&lt;/strong&gt; (for performance-critical patterns).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Recursive patterns&lt;/strong&gt; (in PCRE or some advanced flavors) to match nested constructs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conditional subpatterns&lt;/strong&gt; (in PCRE or .NET) where you test if a group has matched before deciding the next part of the pattern.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But those are topics for another day. For now, lean on the examples and reference sheet above, and try applying regex to your next text‑processing challenge. In no time, you’ll find yourself thinking in patterns - and you won’t look back.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Congratulations on starting your pattern crafting journey! Keep this guide handy, bookmark your favorite regex tester, and remember that a well‑written regular expression often turns hours of manual parsing into a single line of elegant code.&lt;/em&gt;&lt;/p&gt;
&lt;h4 id=&quot;references&quot;&gt;References&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;http://regexstorm.net/&quot;&gt;RegStorm for C#&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Syntax Basics</category>
<guid isPermaLink="true">https://coderlegion.com/3193/regular-expression-a-comprehensive-guide</guid>
<pubDate>Mon, 02 Jun 2025 23:03:31 +0000</pubDate>
</item>
<item>
<title>SQL - A Quick Intro</title>
<link>https://coderlegion.com/3192/sql-a-quick-intro</link>
<description>&lt;h2 id=&quot;sql---a-quick-intro&quot;&gt;SQL - A Quick Intro&lt;/h2&gt;
&lt;h3 id=&quot;overview&quot;&gt;Overview&lt;/h3&gt;
&lt;p&gt;In this article, we’ll walk through the essentials of SQL using the SQLite dialect. We’ll start by creating a couple of sample tables and populating them with data. These tables will serve as the foundation for our examples in later sections. By the end of this overview, you will have a simple schema to work with and understand how to set the scene for common SQL operations.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;-- Create a table for users
CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY,
    username TEXT NOT NULL,
    email TEXT NOT NULL,
    joined_date TEXT NOT NULL  -- stored as ISO-8601 strings in SQLite
);

-- Create a table for orders
CREATE TABLE IF NOT EXISTS orders (
    id INTEGER PRIMARY KEY,
    user_id INTEGER NOT NULL,
    product TEXT NOT NULL,
    quantity INTEGER NOT NULL,
    order_date TEXT NOT NULL,
    FOREIGN KEY (user_id) REFERENCES users(id)
);

-- Insert sample data into users
INSERT INTO users (username, email, joined_date) VALUES
    ('alice', '*Emails are not allowed*', '2023-01-15'),
    ('bob', '*Emails are not allowed*', '2023-02-10'),
    ('carol', '*Emails are not allowed*', '2023-03-05');

-- Insert sample data into orders
INSERT INTO orders (user_id, product, quantity, order_date) VALUES
    (1, 'Keyboard', 2, '2023-04-01'),
    (1, 'Mouse', 1, '2023-04-07'),
    (2, 'Monitor', 1, '2023-04-15'),
    (3, 'Desk Lamp', 3, '2023-05-02'),
    (2, 'USB Cable', 5, '2023-05-10');
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These two tables - &lt;strong&gt;users&lt;/strong&gt; and &lt;strong&gt;orders&lt;/strong&gt; - will be the basis for our queries. Feel free to run these statements in an SQLite environment (e.g., the &lt;code&gt;sqlite3&lt;/code&gt; CLI or any GUI tool) to experiment with the examples that follow.&lt;/p&gt;
&lt;h3 id=&quot;common-syntax&quot;&gt;Common Syntax&lt;/h3&gt;
&lt;p&gt;In this section, we’ll introduce the four most common SQL statements:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;SELECT&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;UPDATE&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DELETE&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;INSERT&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We’ll focus on the typical usage patterns for each statement without covering every possible option or keyword. All SQL keywords are shown in uppercase by convention - this is a good practice. However, they are usually case-insensitive to the SQL engine.&lt;/p&gt;
&lt;h4 id=&quot;1-select&quot;&gt;1. SELECT&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;SELECT&lt;/code&gt; statement is used to retrieve data from one or more tables. At its simplest, you specify the columns you want and the table from which to retrieve them:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT id, username, email
FROM users;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you want all columns, use &lt;code&gt;*&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT *
FROM orders;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can filter results using &lt;code&gt;WHERE&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT username, email
FROM users
WHERE joined_date &amp;gt;= '2023-02-01';
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To sort results, use &lt;code&gt;ORDER BY&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT id, product, quantity, order_date
FROM orders
WHERE quantity &amp;gt; 1
ORDER BY order_date DESC;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Limit the number of rows returned:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT *
FROM orders
LIMIT 3;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Combine clauses:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT username, email
FROM users
WHERE username LIKE 'a%'
ORDER BY joined_date;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;LIKE&lt;/code&gt; keyword here matches all names starting with an &lt;code&gt;a&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;2-update&quot;&gt;2. UPDATE&lt;/h4&gt;
&lt;p&gt;Use &lt;code&gt;UPDATE&lt;/code&gt; to modify existing rows. Always include a &lt;code&gt;WHERE&lt;/code&gt; clause to avoid updating every row unintentionally:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;-- Change Bob's email address
UPDATE users
SET email = '*Emails are not allowed*'
WHERE username = 'bob';
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can update multiple columns at once:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;UPDATE users
SET email = '*Emails are not allowed*',
    joined_date = '2023-01-20'
WHERE username = 'alice';
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s good practice to run a &lt;code&gt;SELECT&lt;/code&gt; with the same &lt;code&gt;WHERE&lt;/code&gt; first:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT * FROM users WHERE username = 'alice';
-- Review the row, then:
UPDATE users
SET email = '*Emails are not allowed*'
WHERE username = 'alice';
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;3-delete&quot;&gt;3. DELETE&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;DELETE&lt;/code&gt; statement removes rows from a table. Again, a &lt;code&gt;WHERE&lt;/code&gt; clause is essential:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;-- Delete Carol's record
DELETE FROM users
WHERE username = 'carol';
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To delete all rows in a table (but keep the table structure):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;DELETE FROM orders;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;SQLite supports &lt;code&gt;DELETE FROM table_name;&lt;/code&gt; without &lt;code&gt;WHERE&lt;/code&gt; to remove every row. If you only want to remove specific rows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;DELETE FROM orders
WHERE order_date &amp;lt; '2023-04-01';
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;4-insert&quot;&gt;4. INSERT&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;INSERT&lt;/code&gt; adds new rows into a table. We already used this in the overview to populate &lt;code&gt;users&lt;/code&gt; and &lt;code&gt;orders&lt;/code&gt;. The basic syntax specifies columns and values:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;INSERT INTO users (username, email, joined_date)
VALUES ('dave', '*Emails are not allowed*', '2023-06-01');
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can omit the column list if you supply values for every column in the exact order:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;INSERT INTO orders VALUES (NULL, 4, 'Webcam', 2, '2023-06-02');
-- NULL for id since it's an AUTOINCREMENT primary key
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you want to insert from another table (a simple form of &lt;code&gt;SELECT&lt;/code&gt; inside &lt;code&gt;INSERT&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;INSERT INTO orders (user_id, product, quantity, order_date)
SELECT id, 'Headphones', 1, '2023-06-05'
FROM users
WHERE username = 'bob';
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;techniques&quot;&gt;Techniques&lt;/h3&gt;
&lt;p&gt;The examples above covered basic CRUD operations. In this section, we’ll focus on more advanced - but frequently used - &lt;code&gt;SELECT&lt;/code&gt; patterns in SQLite, including implicit joins, explicit joins, Common Table Expressions (&lt;code&gt;WITH&lt;/code&gt;), and subqueries. These techniques are particularly helpful when you need to combine data from multiple tables or derive aggregated results.&lt;/p&gt;
&lt;h4 id=&quot;1-implicit-join-using-multiple-tables-in-from&quot;&gt;1. Implicit Join Using Multiple Tables in FROM&lt;/h4&gt;
&lt;p&gt;An implicit join (sometimes called a “comma join”) lists multiple tables in the &lt;code&gt;FROM&lt;/code&gt; clause and specifies the join condition in &lt;code&gt;WHERE&lt;/code&gt;. This style is concise but can be less clear for complex queries:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;-- List every order along with the username of the user who placed it
SELECT u.username, o.product, o.quantity, o.order_date
FROM users u, orders o
WHERE u.id = o.user_id;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, &lt;code&gt;u&lt;/code&gt; is an alias for &lt;code&gt;users&lt;/code&gt; and &lt;code&gt;o&lt;/code&gt; is an alias for &lt;code&gt;orders&lt;/code&gt;. The join condition &lt;code&gt;u.id = o.user_id&lt;/code&gt; ties rows in &lt;code&gt;users&lt;/code&gt; to matching rows in &lt;code&gt;orders&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can add filters:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;-- Only orders with quantity &amp;gt; 1
SELECT u.username, o.product, o.quantity
FROM users u, orders o
WHERE u.id = o.user_id
  AND o.quantity &amp;gt; 1
ORDER BY o.order_date;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;2-explicit-join-syntax-inner-join-left-join-&quot;&gt;2. Explicit Join Syntax (INNER JOIN, LEFT JOIN)&lt;/h4&gt;
&lt;p&gt;SQLite supports the standard explicit &lt;code&gt;JOIN&lt;/code&gt; syntax, which is recommended for clarity:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;-- INNER JOIN retrieves only matching rows
SELECT u.username, o.product, o.order_date
FROM users u
INNER JOIN orders o
    ON u.id = o.user_id;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For a left (or left outer) join, which returns all rows from the left table and matching rows (if any) from the right table:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;-- List all users, including those who have not placed orders
SELECT u.username, o.product, o.order_date
FROM users u
LEFT JOIN orders o
    ON u.id = o.user_id;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If a user has no matching &lt;code&gt;orders&lt;/code&gt;, the &lt;code&gt;product&lt;/code&gt; and &lt;code&gt;order_date&lt;/code&gt; columns will be &lt;code&gt;NULL&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Multiple Joins&lt;/strong&gt;&lt;br&gt;
When you have more than two tables, chain the joins together:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;-- Suppose we add a table for payment info
CREATE TABLE IF NOT EXISTS payments (
    id INTEGER PRIMARY KEY,
    order_id INTEGER NOT NULL,
    amount REAL NOT NULL,
    payment_date TEXT NOT NULL,
    FOREIGN KEY (order_id) REFERENCES orders(id)
);

-- Sample data
INSERT INTO payments (order_id, amount, payment_date) VALUES
    (1, 49.98, '2023-04-02'),
    (2, 19.99, '2023-04-08'),
    (3, 149.99, '2023-04-16');

-- Query: find username, product, and payment amount for each paid order
SELECT u.username,
       o.product,
       p.amount,
       p.payment_date
FROM users u
INNER JOIN orders o
    ON u.id = o.user_id
INNER JOIN payments p
    ON o.id = p.order_id
ORDER BY p.payment_date;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;3-with-clause-common-table-expressions-&quot;&gt;3. WITH Clause (Common Table Expressions)&lt;/h4&gt;
&lt;p&gt;A Common Table Expression (CTE) defined by &lt;code&gt;WITH&lt;/code&gt; allows you to create a temporary, named result set that you can reference in a subsequent query. This is useful for breaking complex queries into more readable pieces.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;-- Example: Find users who have spent more than $50 in total
WITH user_totals AS (
    SELECT u.id AS user_id,
           u.username,
           SUM(p.amount) AS total_spent
    FROM users u
    INNER JOIN orders o
        ON u.id = o.user_id
    INNER JOIN payments p
        ON o.id = p.order_id
    GROUP BY u.id, u.username
)
SELECT username, total_spent
FROM user_totals
WHERE total_spent &amp;gt; 50;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The CTE named &lt;code&gt;user_totals&lt;/code&gt; aggregates total spending per user.&lt;/li&gt;
&lt;li&gt;The outer &lt;code&gt;SELECT&lt;/code&gt; filters users based on their aggregated spending.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;CTEs can be &lt;strong&gt;recursive&lt;/strong&gt; as well, but for a quick intro, focus on non-recursive CTEs.&lt;/p&gt;
&lt;h4 id=&quot;4-subqueries&quot;&gt;4. Subqueries&lt;/h4&gt;
&lt;p&gt;Subqueries (also called inner queries or nested queries) are queries embedded inside other SQL statements. They can appear in the &lt;code&gt;SELECT&lt;/code&gt; list, &lt;code&gt;FROM&lt;/code&gt; clause, or &lt;code&gt;WHERE&lt;/code&gt; clause.&lt;/p&gt;
&lt;h5 id=&quot;4-1-subquery-in-select-list&quot;&gt;4.1 Subquery in SELECT List&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;-- Add a column showing the number of orders each user has placed
SELECT u.username,
       u.email,
       (
           SELECT COUNT(*)
           FROM orders o
           WHERE o.user_id = u.id
       ) AS order_count
FROM users u;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The subquery &lt;code&gt;(SELECT COUNT(*) FROM orders o WHERE o.user_id = u.id)&lt;/code&gt; executes for each row in &lt;code&gt;users&lt;/code&gt;.&lt;/p&gt;
&lt;h5 id=&quot;4-2-subquery-in-where-clause&quot;&gt;4.2 Subquery in WHERE Clause&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;-- Find users who have never placed an order
SELECT username, email
FROM users
WHERE id NOT IN (
    SELECT DISTINCT user_id
    FROM orders
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Alternatively, using &lt;code&gt;NOT EXISTS&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT username, email
FROM users u
WHERE NOT EXISTS (
    SELECT 1
    FROM orders o
    WHERE o.user_id = u.id
);
&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id=&quot;4-3-subquery-in-from-clause&quot;&gt;4.3 Subquery in FROM Clause&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;-- Join users to a derived table that calculates order counts
SELECT t.username, t.order_count
FROM (
    SELECT u.id AS user_id,
           u.username,
           COUNT(o.id) AS order_count
    FROM users u
    LEFT JOIN orders o
        ON u.id = o.user_id
    GROUP BY u.id, u.username
) AS t
WHERE t.order_count &amp;gt;= 2;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, the subquery in the &lt;code&gt;FROM&lt;/code&gt; clause (aliased as &lt;code&gt;t&lt;/code&gt;) computes the number of orders per user. The outer query then filters on &lt;code&gt;order_count&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id=&quot;5-aggregation-and-group-by&quot;&gt;5. Aggregation and GROUP BY&lt;/h4&gt;
&lt;p&gt;While technically a part of &lt;code&gt;SELECT&lt;/code&gt; patterns, aggregation is so common that it merits a dedicated mention:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;-- Total quantity ordered per product
SELECT product,
       SUM(quantity) AS total_quantity
FROM orders
GROUP BY product
ORDER BY total_quantity DESC;
&lt;/code&gt;&lt;/pre&gt;
&lt;h5 id=&quot;having&quot;&gt;HAVING&lt;/h5&gt;
&lt;p&gt;To filter on aggregated values, use &lt;code&gt;HAVING&lt;/code&gt; rather than &lt;code&gt;WHERE&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;-- Only products with total quantity &amp;gt; 2
SELECT product,
       SUM(quantity) AS total_quantity
FROM orders
GROUP BY product
HAVING total_quantity &amp;gt; 2;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;6-putting-it-all-together&quot;&gt;6. Putting It All Together&lt;/h4&gt;
&lt;p&gt;Let’s combine a few of these techniques into a more comprehensive example:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We want to list each user, their total number of orders, total quantity ordered, and their most recent order date.&lt;/li&gt;
&lt;li&gt;Only include users who have placed at least one order.&lt;/li&gt;
&lt;li&gt;Sort by total quantity descending.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;WITH user_orders AS (
    SELECT u.id    AS user_id,
           u.username,
           COUNT(o.id)           AS order_count,
           SUM(o.quantity)       AS total_quantity,
           MAX(o.order_date)     AS last_order_date
    FROM users u
    INNER JOIN orders o
        ON u.id = o.user_id
    GROUP BY u.id, u.username
)
SELECT username,
       order_count,
       total_quantity,
       last_order_date
FROM user_orders
WHERE order_count &amp;gt;= 1
ORDER BY total_quantity DESC;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Explanation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The CTE &lt;code&gt;user_orders&lt;/code&gt; aggregates order-related metrics per user.&lt;/li&gt;
&lt;li&gt;The outer query filters out users with zero orders and sorts the results.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;putting-it-into-practice&quot;&gt;Putting It into Practice&lt;/h3&gt;
&lt;p&gt;Here are a few additional examples and variations you might find useful in everyday data analysis with SQLite:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Top 3 Users by Total Spending&lt;/strong&gt;&lt;br&gt;
Combine payments and orders to rank users.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;WITH spending AS (
    SELECT u.id         AS user_id,
           u.username,
           SUM(p.amount) AS total_spent
    FROM users u
    INNER JOIN orders o
        ON u.id = o.user_id
    INNER JOIN payments p
        ON o.id = p.order_id
    GROUP BY u.id, u.username
)
SELECT username, total_spent
FROM spending
ORDER BY total_spent DESC
LIMIT 3;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Find Orders with No Payment Records&lt;/strong&gt;&lt;br&gt;
Use a left join and look for &lt;code&gt;NULL&lt;/code&gt; in the payment side.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;SELECT o.id AS order_id,
       u.username,
       o.product,
       o.order_date
FROM orders o
LEFT JOIN payments p
    ON o.id = p.order_id
INNER JOIN users u
    ON o.user_id = u.id
WHERE p.id IS NULL;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Update via Subquery&lt;/strong&gt;&lt;br&gt;
Suppose we want to mark users who joined before a certain date as “legacy” in a new column. First, add a column:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;ALTER TABLE users ADD COLUMN status TEXT DEFAULT 'active';

UPDATE users
SET status = 'legacy'
WHERE joined_date &amp;lt; '2023-02-01';
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Delete Based on a Joined Condition&lt;/strong&gt;&lt;br&gt;
If you needed to delete payments for orders that were canceled (imagine a hypothetical &lt;code&gt;orders.status = 'canceled'&lt;/code&gt; column), you could write:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;DELETE FROM payments
WHERE order_id IN (
    SELECT id
    FROM orders
    WHERE status = 'canceled'
);
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Nested CTEs&lt;/strong&gt;&lt;br&gt;
Chain multiple CTEs to break down a complex problem:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;WITH recent_orders AS (
    SELECT *
    FROM orders
    WHERE order_date &amp;gt;= '2023-04-01'
),
recent_payments AS (
    SELECT o.id     AS order_id,
           o.user_id,
           p.amount,
           p.payment_date
    FROM recent_orders o
    INNER JOIN payments p
        ON o.id = p.order_id
)
SELECT u.username,
       SUM(rp.amount) AS recent_spending
FROM users u
INNER JOIN recent_payments rp
    ON u.id = rp.user_id
GROUP BY u.username
ORDER BY recent_spending DESC;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;This article has introduced the basics of SQL using the SQLite dialect, focusing on the most common statements - &lt;strong&gt;SELECT&lt;/strong&gt;, &lt;strong&gt;UPDATE&lt;/strong&gt;, &lt;strong&gt;DELETE&lt;/strong&gt;, and &lt;strong&gt;INSERT&lt;/strong&gt; - as well as several useful &lt;code&gt;SELECT&lt;/code&gt; techniques. You now have a schema with &lt;code&gt;users&lt;/code&gt;, &lt;code&gt;orders&lt;/code&gt;, and &lt;code&gt;payments&lt;/code&gt; to experiment with, and you’ve seen how to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create tables and insert data.&lt;/li&gt;
&lt;li&gt;Perform simple CRUD operations.&lt;/li&gt;
&lt;li&gt;Join tables both implicitly and explicitly.&lt;/li&gt;
&lt;li&gt;Use Common Table Expressions (&lt;code&gt;WITH&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Write subqueries in various parts of a statement.&lt;/li&gt;
&lt;li&gt;Aggregate data and filter with &lt;code&gt;HAVING&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These examples should provide a solid foundation for everyday data analysis tasks. As you become more comfortable, you can explore advanced topics like window functions, triggers, and indexing strategies in SQLite.&lt;/p&gt;
</description>
<category>Data Science</category>
<guid isPermaLink="true">https://coderlegion.com/3192/sql-a-quick-intro</guid>
<pubDate>Mon, 02 Jun 2025 23:03:06 +0000</pubDate>
</item>
</channel>
</rss>