-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsql-formatter.html
More file actions
785 lines (723 loc) · 55.7 KB
/
Copy pathsql-formatter.html
File metadata and controls
785 lines (723 loc) · 55.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SQL Formatter — MySQL, PostgreSQL, MSSQL | FreeDevTool</title>
<meta name="description" content="Free SQL formatter & beautifier — MySQL, PostgreSQL, SQL Server, Oracle, SQLite. Customizable indent & case. Browser-only, no upload.">
<meta name="robots" content="index, follow">
<meta name="author" content="Anees Ur Rehman">
<script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","datePublished":"2026-05-02","dateModified":"2026-05-19","inLanguage":"en-US","isPartOf":{"@type":"WebSite","name":"FreeDevTool","url":"https://freedevtool.org"}}</script>
<script type="application/ld+json">{"@context":"https://schema.org","@type":"Person","name":"Anees Ur Rehman","url":"https://freedevtool.org/about","jobTitle":"Full-stack developer","worksFor":{"@type":"Organization","name":"FreeDevTool","url":"https://freedevtool.org"}}</script>
<link rel="canonical" href="https://freedevtool.org/sql-formatter">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="preload" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=DM+Sans:wght@300;400;500;600&display=swap" as="style">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=DM+Sans:wght@300;400;500;600&display=swap">
<link rel="preload" href="style.css?v=20260502-cards" as="style">
<link rel="stylesheet" href="style.css?v=20260502-cards">
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/favicon.svg">
<meta property="og:image" content="https://freedevtool.org/og-image.svg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="FreeDevTool — 50+ free, fast, privacy-first developer tools">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://freedevtool.org/og-image.svg">
<meta name="twitter:title" content="SQL Formatter & Beautifier Online — Free | FreeDevTool">
<meta name="twitter:description" content="Pretty print SQL queries for MySQL, PostgreSQL, SQL Server & Oracle. Runs in browser, no signup, no logging.">
<meta property="og:image" content="https://freedevtool.org/og-image.svg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta name="twitter:image" content="https://freedevtool.org/og-image.svg">
<script async src="https://www.googletagmanager.com/gtag/js?id=G-3L0CMH3X36"></script>
<script>window.dataLayer=window.dataLayer||[];function gtag(){dataLayer.push(arguments)}gtag('js',new Date());gtag('config','G-3L0CMH3X36');</script>
<meta property="og:title" content="SQL Formatter & Beautifier Online — Format SQL Queries Free">
<meta property="og:description" content="Format, beautify and minify SQL queries online. Indent, uppercase keywords, validate statements. Free browser-based SQL formatter.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://freedevtool.org/sql-formatter">
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"WebApplication","name":"SQL Formatter & Beautifier Online","url":"https://freedevtool.org/sql-formatter","description":"Format, beautify and minify SQL queries online with proper indentation and keyword highlighting.","applicationCategory":"DeveloperApplication","operatingSystem":"Any","offers":{"@type":"Offer","price":"0","priceCurrency":"USD"}}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "HowTo",
"name": "How to format SQL queries online (MySQL, PostgreSQL, SQL Server)",
"description": "Pretty-print or minify SQL with dialect-aware keyword casing for MySQL, PostgreSQL, SQL Server, Oracle, or SQLite.",
"step": [
{"@type":"HowToStep","name":"Paste SQL query","text":"Paste any SQL — SELECT, INSERT, UPDATE, DELETE, DDL, or stored procedure body — into the input pane. Parsing happens locally; queries never upload."},
{"@type":"HowToStep","name":"Pick dialect","text":"Choose MySQL, PostgreSQL, SQL Server, Oracle, or SQLite from the dropdown so dialect-specific keywords (LIMIT vs TOP, RETURNING, MERGE) are recognized."},
{"@type":"HowToStep","name":"Configure style","text":"Set keyword case (UPPER recommended for readability), indent width (2 or 4 spaces), and JOIN-on-newline preference."},
{"@type":"HowToStep","name":"Copy formatted SQL","text":"Click Copy to grab the formatted query and paste into your IDE, migration file, or PR comment."}
]
}
</script>
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"FAQPage","mainEntity":[{"@type":"Question","name":"What is SQL formatting and why should I format my SQL queries?","acceptedAnswer":{"@type":"Answer","text":"SQL formatting is the process of restructuring SQL code with consistent indentation, line breaks, and keyword casing to improve readability. Properly formatted SQL is easier to debug, review in code reviews, and maintain across teams. Most SQL style guides recommend uppercase keywords (SELECT, FROM, WHERE) and consistent indentation for subqueries and JOIN clauses."}},{"@type":"Question","name":"Does this SQL formatter support different database dialects?","acceptedAnswer":{"@type":"Answer","text":"This formatter handles standard SQL keywords used across MySQL, PostgreSQL, SQL Server, Oracle, and SQLite. It recognizes keywords like SELECT, FROM, WHERE, JOIN, GROUP BY, ORDER BY, HAVING, INSERT, UPDATE, DELETE, CREATE TABLE, ALTER TABLE, and more. Dialect-specific functions are preserved as-is."}},{"@type":"Question","name":"Is it safe to paste production SQL queries into an online formatter?","acceptedAnswer":{"@type":"Answer","text":"Yes. This tool processes everything 100% client-side in your browser using JavaScript. Your SQL queries are never sent to any server, stored, or logged. You can verify this by using the tool offline after the page loads."}},{"@type":"Question","name":"Should SQL keywords be uppercase or lowercase?","acceptedAnswer":{"@type":"Answer","text":"Pure preference — both are valid SQL. Uppercase SELECT is traditional and standard in style guides because it visually distinguishes keywords from identifiers. Lowercase select is increasingly common in modern teams. Pick one style for your project."}},{"@type":"Question","name":"How do I format complex SQL with CTEs?","acceptedAnswer":{"@type":"Answer","text":"Common Table Expressions (WITH clauses) should be at the start with each CTE on its own line block. The main SELECT that follows should align at the same indent level. Most formatters handle this correctly; verify your formatter respects the WITH structure."}},{"@type":"Question","name":"Does SQL formatting affect query performance?","acceptedAnswer":{"@type":"Answer","text":"No. Formatting is purely cosmetic — whitespace is ignored by SQL parsers. A formatted and minified query produce identical execution plans. Format for human readability; the database engine does not care."}}]}
</script>
<style>
.sql-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.sql-pane{display:flex;flex-direction:column;gap:6px}
.sql-pane label{font-size:12px;color:var(--text3);font-family:var(--mono)}
.sql-pane textarea{width:100%;height:320px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius);padding:14px;color:var(--text);font-family:var(--mono);font-size:13px;resize:vertical;line-height:1.6;tab-size:2}
.sql-pane textarea:focus{border-color:var(--accent);outline:none;box-shadow:0 0 0 3px rgba(0,208,132,.08)}
.sql-controls{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin:12px 0}
.sql-controls select,.sql-controls label{font-size:12px;font-family:var(--mono);color:var(--text2)}
.sql-controls select{background:var(--bg);border:1px solid var(--border);border-radius:var(--radius);padding:6px 10px;color:var(--text)}
.sql-stats{display:flex;gap:16px;font-size:11px;font-family:var(--mono);color:var(--text3);margin-top:6px}
.chk-label{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--text2);cursor:pointer}
.chk-label input{accent-color:var(--accent)}
@media(max-width:700px){.sql-grid{grid-template-columns:1fr}}
</style>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://freedevtool.org/"
},
{
"@type": "ListItem",
"position": 2,
"name": "All Tools",
"item": "https://freedevtool.org/all-tools"
},
{
"@type": "ListItem",
"position": 3,
"name": "SQL Formatter & Beautifier",
"item": "https://freedevtool.org/sql-formatter"
}
]
}
</script>
<script src="/ga4-events.js" defer></script>
</head>
<body>
<nav>
<a class="nav-logo" href="/" aria-label="FreeDevTool home"><svg class="logo-mark" width="22" height="22" viewBox="0 0 24 24" aria-hidden="true" fill="none"><rect x="1" y="1" width="22" height="22" rx="6" fill="currentColor" opacity=".12"/><path d="M9.5 8.5L6 12l3.5 3.5M14.5 8.5L18 12l-3.5 3.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>FreeDevTool</a>
<div class="nav-links">
<a href="all-tools">All Tools</a>
<a href="/guides">Guides</a>
<a href="about">About</a>
<a href="privacy">Privacy</a>
</div>
</nav>
<div class="wrapper">
<section class="tool-header">
<a class="tool-back" href="/" aria-label="Back to home">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 18l-6-6 6-6"/></svg>
Back
</a>
<span class="tool-badge">Formatting</span>
<h1>SQL Formatter & Beautifier Online</h1>
<p>Format, beautify, and minify SQL queries with dialect-aware rules for <strong>MySQL</strong>, <strong>PostgreSQL</strong>, <strong>SQL Server</strong>, <strong>Oracle</strong>, and <strong>SQLite</strong>. Pick keyword casing (UPPER/lower/preserve), indent width (2/4 spaces or tabs), and comma placement. Validates basic syntax and processes queries entirely in your browser — even queries containing real customer data, API keys, or production schemas never reach a server.</p>
<div class="last-updated">Last updated: May 2026 · Written by <a href="/about">Anees Ur Rehman</a>, full-stack developer</div>
</section>
<div class="tool-card">
<div class="card-dots"><span></span><span></span><span></span></div>
<div class="tool-body">
<div class="sql-controls">
<button class="btn btn-primary" onclick="formatSQL()">Format / Beautify</button>
<button class="btn btn-ghost" onclick="minifySQL()">Minify</button>
<button class="btn btn-ghost" onclick="clearAll()">Clear</button>
<button class="btn btn-ghost" onclick="loadSample()">Sample</button>
<select id="indent-size">
<option value="2">2 spaces</option>
<option value="4" selected>4 spaces</option>
<option value="tab">Tab</option>
</select>
<label class="chk-label"><input type="checkbox" id="uppercase-kw" checked> Uppercase keywords</label>
</div>
<div class="sql-grid">
<div class="sql-pane">
<label>Input SQL</label>
<textarea id="sql-input" placeholder="Paste your SQL query here..." spellcheck="false"></textarea>
<div class="sql-stats"><span id="input-stats">0 lines, 0 chars</span></div>
</div>
<div class="sql-pane">
<label>Formatted Output</label>
<textarea id="sql-output" placeholder="Formatted SQL will appear here..." readonly spellcheck="false"></textarea>
<div class="sql-stats">
<span id="output-stats">0 lines, 0 chars</span>
<button class="btn btn-ghost" onclick="copyOutput()" style="padding:2px 10px;font-size:11px">Copy</button>
</div>
</div>
</div>
</div>
</div>
<div id="toast" style="position:fixed;bottom:30px;left:50%;transform:translateX(-50%);background:var(--accent);color:#000;padding:8px 20px;border-radius:var(--radius);font-size:13px;font-weight:600;opacity:0;transition:opacity .3s;pointer-events:none;z-index:999">Copied!</div>
<!-- =============================================================
LONG-FORM ARTICLE — comprehensive guide for E-E-A-T + ranking.
============================================================= -->
<article>
<p class="aeo-lead" style="font-size:16px;line-height:1.7;color:var(--text);max-width:760px;margin:24px auto 18px;padding:0 4px">
<strong>SQL formatting</strong> applies consistent indentation, keyword case, and line breaks to make complex queries readable. Different dialects have different rules — PostgreSQL preserves identifier case, MySQL is case-insensitive, BigQuery and Snowflake have their own keyword sets. This <strong>free SQL formatter</strong> handles ANSI, MySQL, PostgreSQL, BigQuery, and Snowflake dialects with CTE and window function support.
</p>
<section id="examples" style="max-width:760px;margin:24px auto 32px">
<h2 style="font-size:18px;margin-bottom:14px">Examples</h2>
<div style="background:var(--bg3);border:1px solid var(--border);border-radius:var(--radius);padding:16px;margin-bottom:12px">
<strong style="display:block;color:var(--accent);font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:1px;margin-bottom:6px">Simple SELECT§§Input: select id,name from users where active=1§§Formatted:§§SELECT id, name§§FROM users§§WHERE active = 1§§Keywords uppercase, one column per line for readability.</strong>
</div>
<div style="background:var(--bg3);border:1px solid var(--border);border-radius:var(--radius);padding:16px;margin-bottom:12px">
<strong style="display:block;color:var(--accent);font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:1px;margin-bottom:6px">Common Table Expression§§WITH recent_orders AS (§§ SELECT * FROM orders WHERE created_at > NOW() - INTERVAL "7 days"§§)§§SELECT customer_id, COUNT(*) FROM recent_orders GROUP BY customer_id;§§Formatters preserve CTE structure and indentation hierarchy.</strong>
</div>
<div style="background:var(--bg3);border:1px solid var(--border);border-radius:var(--radius);padding:16px;margin-bottom:12px">
<strong style="display:block;color:var(--accent);font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:1px;margin-bottom:6px">Window function§§SELECT name, salary,§§ RANK() OVER (PARTITION BY dept ORDER BY salary DESC) AS rank§§FROM employees;§§Window functions stay on a single logical line for readability.</strong>
</div>
</section>
<aside class="founder-note" style="max-width:760px;margin:24px auto 32px;padding:20px 24px;background:rgba(0,208,132,0.05);border-left:3px solid var(--accent);border-radius:6px;font-size:14px;line-height:1.7;color:var(--text2)"><div style="font-family:var(--mono);font-size:11px;color:var(--accent);letter-spacing:1.5px;text-transform:uppercase;margin-bottom:10px;font-weight:600">💡 Why I built this</div><p style="margin:0 0 12px">I built this after spending 20 minutes debugging a PostgreSQL CTE that worked in my IDE but broke when formatted by another tool — the formatter was MySQL-only and silently lowercased keywords PostgreSQL needs in specific cases. This formatter handles ANSI, MySQL, PostgreSQL, BigQuery, and Snowflake. CTEs, window functions, and array operators stay intact.</p><p style="margin:0;font-size:13px;color:var(--text3)">— <a href="/about" style="color:var(--accent);text-decoration:none">Anees Ur Rehman</a>, full-stack developer</p></aside>
<section class="article-section">
<h2>What is SQL formatting and why does it matter?</h2>
<p><strong>SQL formatting</strong> (or <em>beautifying</em>) is the practice of applying consistent indentation, line breaks, and casing to SQL queries so they are easier to read, review, and debug. While the SQL standard (<a href="https://en.wikipedia.org/wiki/SQL:2023" rel="noopener">ISO/IEC 9075</a>) doesn't mandate any particular layout — engines accept the same query as a single line or 50 — there are decades of community conventions that make code review faster, bug-spotting easier, and onboarding cheaper.</p>
<p>A well-formatted query communicates structure at a glance: the <code>SELECT</code> list, the <code>FROM</code> chain of joins, the <code>WHERE</code> predicates, the <code>GROUP BY</code> dimensions, the <code>HAVING</code> filters, and the <code>ORDER BY</code> sort. Compare these two equivalent queries:</p>
<div class="lang-block">
<div class="lang-block-header">unformatted</div>
<pre><code>SELECT u.id, u.email, count(o.id) AS orders, sum(o.total) AS revenue FROM users u LEFT JOIN orders o ON o.user_id=u.id WHERE u.created_at >'2026-01-01' AND u.deleted_at IS NULL GROUP BY u.id, u.email HAVING count(o.id)>0 ORDER BY revenue DESC LIMIT 100;</code></pre>
</div>
<div class="lang-block">
<div class="lang-block-header">formatted</div>
<pre><code>SELECT
u.id,
u.email,
COUNT(o.id) AS orders,
SUM(o.total) AS revenue
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
WHERE u.created_at > '2026-01-01'
AND u.deleted_at IS NULL
GROUP BY u.id, u.email
HAVING COUNT(o.id) > 0
ORDER BY revenue DESC
LIMIT 100;</code></pre>
</div>
<p>The formatted version has the same logic and identical execution plan, but pull-request reviewers can scan the join chain and the filters in seconds. When something breaks in production, the on-call engineer can read the query in their phone's <code>kubectl logs</code> output without unpacking 200 chars of compressed text.</p>
</section>
<section class="article-section">
<h2>How SQL formatters work under the hood</h2>
<p>A SQL formatter is a small compiler. The pipeline has three stages:</p>
<ul>
<li><strong>1. Lexer / tokenizer.</strong> Splits the input into tokens — keywords (<code>SELECT</code>, <code>FROM</code>), identifiers (<code>users</code>, <code>u</code>), operators (<code>=</code>, <code>></code>), literals (<code>'2026-01-01'</code>, <code>100</code>), comments, and whitespace. The tokenizer needs to know the dialect to recognize keywords correctly — <code>LIMIT</code> is a keyword in MySQL/Postgres but a function in SQL Server (<code>TOP</code> instead).</li>
<li><strong>2. Parser.</strong> Builds an Abstract Syntax Tree (AST) from the token stream, recognizing the structure: <code>SELECT</code> lists, <code>FROM</code> chains with joins, predicates, subqueries, CTEs, and so on. A robust parser handles dialect quirks like Postgres <code>RETURNING</code>, SQL Server <code>OUTPUT</code>, MySQL <code>ON DUPLICATE KEY</code>.</li>
<li><strong>3. Pretty-printer.</strong> Walks the AST and emits formatted SQL with the chosen indent width, comma style, keyword case, and line-break rules. This step decides whether <code>JOIN</code> keywords align with <code>FROM</code>, whether commas go before or after fields, whether short queries stay on one line, and so on.</li>
</ul>
<p>This tool uses a battle-tested SQL parser (the same approach as <code>sql-formatter</code> on npm and PgFormatter) and runs all three stages in your browser. No query ever leaves your machine — important when you're formatting queries that touch real customer data, contain hard-coded credentials, or expose schema names you'd rather not share.</p>
</section>
<section class="article-section">
<h2>SQL dialect differences — what to know</h2>
<p>"SQL" isn't one language. The 1992 ANSI SQL standard is the common ancestor, but every major engine has added features (and quirks) over decades. The five dialects this formatter handles cover >95% of real-world SQL.</p>
<table class="ref-table">
<thead>
<tr><th>Feature</th><th>MySQL</th><th>PostgreSQL</th><th>SQL Server</th><th>Oracle</th><th>SQLite</th></tr>
</thead>
<tbody>
<tr><td>Limit syntax</td><td><code>LIMIT n</code></td><td><code>LIMIT n</code></td><td><code>SELECT TOP n</code> / <code>OFFSET FETCH</code></td><td><code>FETCH FIRST n ROWS</code></td><td><code>LIMIT n</code></td></tr>
<tr><td>String concat</td><td><code>CONCAT()</code> only</td><td><code>||</code> or <code>CONCAT()</code></td><td><code>+</code> or <code>CONCAT()</code></td><td><code>||</code></td><td><code>||</code></td></tr>
<tr><td>Identifier quoting</td><td>Backticks <code>`tbl`</code></td><td>Double quotes <code>"tbl"</code></td><td>Brackets <code>[tbl]</code> or quotes</td><td>Double quotes</td><td>Backticks or quotes</td></tr>
<tr><td>Case-sensitivity (unquoted)</td><td>Database-config dependent</td><td>Folded to lowercase</td><td>Insensitive by default</td><td>Folded to UPPERCASE</td><td>Insensitive</td></tr>
<tr><td>Auto-increment</td><td><code>AUTO_INCREMENT</code></td><td><code>SERIAL</code> / <code>IDENTITY</code></td><td><code>IDENTITY(1,1)</code></td><td>Sequences + triggers</td><td><code>AUTOINCREMENT</code></td></tr>
<tr><td>Boolean type</td><td><code>TINYINT(1)</code></td><td><code>BOOLEAN</code></td><td><code>BIT</code></td><td>No native — use <code>NUMBER(1)</code></td><td><code>INTEGER</code></td></tr>
<tr><td>Insert + return</td><td>Two queries</td><td><code>INSERT ... RETURNING</code></td><td><code>OUTPUT INSERTED.*</code></td><td><code>RETURNING ... INTO</code></td><td><code>RETURNING</code> (3.35+)</td></tr>
<tr><td>Common Table Exprs (CTEs)</td><td><span class="yes">8.0+</span></td><td><span class="yes">Yes</span></td><td><span class="yes">Yes</span></td><td><span class="yes">Yes</span></td><td><span class="yes">3.8+</span></td></tr>
<tr><td>Window functions</td><td><span class="yes">8.0+</span></td><td><span class="yes">Yes</span></td><td><span class="yes">Yes</span></td><td><span class="yes">Yes</span></td><td><span class="yes">3.25+</span></td></tr>
<tr><td>JSON support</td><td><span class="yes">Yes (5.7+)</span></td><td><span class="yes">JSONB (best)</span></td><td><span class="yes">Yes (2016+)</span></td><td><span class="yes">JSON_TABLE</span></td><td><span class="yes">JSON1</span></td></tr>
</tbody>
</table>
<p>Pick the right dialect in the formatter dropdown — it changes how reserved words are recognized, how strings are quoted, and how identifiers are escaped. Formatting Postgres SQL with the MySQL setting can incorrectly uppercase or quote things.</p>
</section>
<section class="article-section">
<h2>Formatting style choices — pick once, apply everywhere</h2>
<p>Even with a fixed dialect, formatters expose dozens of style toggles. The four that matter most:</p>
<h3>1. Keyword case</h3>
<ul>
<li><strong>UPPERCASE</strong> (most common in dbt, traditional enterprise) — keywords stand out from identifiers, easy to spot in dense code review.</li>
<li><strong>lowercase</strong> (modern style, popular in startups, used by <a href="https://github.com/sqlfluff/sqlfluff" rel="noopener">SQLFluff</a> defaults) — looks cleaner, modern editors highlight keywords with color anyway.</li>
<li><strong>Preserve</strong> — leave the original case. Useful when reformatting legacy code without imposing a style.</li>
</ul>
<h3>2. Indent width</h3>
<p>4 spaces is the historical default. Modern teams often use 2 spaces to fit deeply-nested CTEs in a single screen. Tabs are rare in SQL but valid. Pick one site-wide; mixing is a code-review red flag.</p>
<h3>3. Comma placement</h3>
<ul>
<li><strong>Trailing comma</strong> (after the field): <code>SELECT a, b, c</code> — most common. Easy to type. Diff-noisy when adding fields (because the last line changes).</li>
<li><strong>Leading comma</strong> (before the field): <code>SELECT a<br> , b<br> , c</code> — diff-friendly but visually unusual outside data-warehouse teams.</li>
</ul>
<h3>4. JOIN style</h3>
<p>Modern SQL strongly prefers explicit <code>JOIN</code> with <code>ON</code> conditions over the legacy comma-and-<code>WHERE</code> style. Implicit joins are still valid but easy to miss when scanning, and join conditions get tangled with filter conditions.</p>
<div class="article-aside">
<strong>Team tip:</strong> commit a <code>.sqlfluff</code> or <code>sql-formatter.config.json</code> to your repo. Pin every style choice. Run formatting in CI. The PR comments about indentation will stop forever.
</div>
</section>
<section class="article-section">
<h2>SQL formatting in 8 toolchains</h2>
<h3>npm: sql-formatter</h3>
<div class="lang-block">
<div class="lang-block-header">node.js / typescript</div>
<pre><code>import { format } from 'sql-formatter';
const formatted = format(rawSQL, {
language: 'postgresql', // mysql | postgresql | tsql | plsql | sqlite | bigquery
keywordCase: 'upper',
tabWidth: 4,
useTabs: false,
linesBetweenQueries: 2,
});
</code></pre>
</div>
<h3>Python: sqlparse</h3>
<div class="lang-block">
<div class="lang-block-header">python</div>
<pre><code>import sqlparse
formatted = sqlparse.format(
raw_sql,
reindent=True,
keyword_case='upper',
indent_width=4,
)
</code></pre>
</div>
<h3>Python: SQLFluff (linter + formatter)</h3>
<div class="lang-block">
<div class="lang-block-header">bash</div>
<pre><code># Lint
sqlfluff lint queries/ --dialect postgres
# Auto-fix style violations
sqlfluff fix queries/ --dialect postgres
# Format only (no linting)
sqlfluff format query.sql --dialect postgres
</code></pre>
</div>
<h3>VS Code: SQL formatters</h3>
<div class="lang-block">
<div class="lang-block-header">vscode-extensions</div>
<pre><code>// Top extensions:
// - "SQL Formatter" (adpyke) — uses sql-formatter under the hood
// - "SQLFluff" — for dbt projects
// - "Prettier SQL VSCode" — Prettier-style formatting
// Keybind format-on-save in settings.json:
{
"editor.formatOnSave": true,
"[sql]": { "editor.defaultFormatter": "adpyke.vscode-sql-formatter" }
}
</code></pre>
</div>
<h3>JetBrains DataGrip / IntelliJ</h3>
<div class="lang-block">
<div class="lang-block-header">datagrip</div>
<pre><code>// Built-in formatter: Code → Reformat Code (Ctrl+Alt+L / Cmd+Opt+L)
// Settings → Editor → Code Style → SQL → [Dialect]
// Per-dialect rules. Sync via "Settings Repository" or .editorconfig
</code></pre>
</div>
<h3>PostgreSQL: pg_format / PgFormatter</h3>
<div class="lang-block">
<div class="lang-block-header">bash</div>
<pre><code># Install
brew install pgformatter # macOS
sudo apt install pgformatter # Debian/Ubuntu
# Format a file
pg_format -s 4 -u 1 query.sql > query.formatted.sql
# Pipe input
echo "select * from users where id=1;" | pg_format
</code></pre>
</div>
<h3>dbt: built-in formatting</h3>
<div class="lang-block">
<div class="lang-block-header">dbt</div>
<pre><code># dbt uses SQLFluff under the hood
# In your dbt project root, add .sqlfluff config:
[sqlfluff]
dialect = snowflake
templater = dbt
exclude_rules = L032
# Then run:
sqlfluff fix models/
</code></pre>
</div>
<h3>Bash one-liner via Docker</h3>
<div class="lang-block">
<div class="lang-block-header">bash</div>
<pre><code># If you don't want to install anything:
docker run --rm -i sqlfluff/sqlfluff:latest format - --dialect postgres < query.sql
# Or use Prettier with @prettier/plugin-sql
npx prettier --plugin=prettier-plugin-sql --parser=postgresql query.sql
</code></pre>
</div>
</section>
<section class="article-section">
<h2>Common SQL anti-patterns the formatter exposes</h2>
<p>Beautified SQL doesn't just look nice — it makes anti-patterns easier to spot. Here are the most common ones:</p>
<table class="ref-table">
<thead><tr><th>Anti-pattern</th><th>Why it's bad</th><th>Better</th></tr></thead>
<tbody>
<tr>
<td><code>SELECT *</code> in production</td>
<td>Breaks when columns added; sends unused data; obscures dependencies</td>
<td>Enumerate columns explicitly</td>
</tr>
<tr>
<td>Implicit joins (<code>FROM a, b WHERE</code>)</td>
<td>Easy to miss the join condition; mixing with explicit joins is a mess</td>
<td>Explicit <code>JOIN ... ON</code></td>
</tr>
<tr>
<td>Subqueries instead of CTEs</td>
<td>Hard to read deeply nested; can't reuse the same subquery twice</td>
<td>Use <code>WITH cte AS (...)</code> CTEs (modern SQL)</td>
</tr>
<tr>
<td>Cartesian product from missing <code>ON</code></td>
<td>Returns rows×rows; massive result sets, slow queries</td>
<td>Always provide a join condition; review join chains carefully</td>
</tr>
<tr>
<td>Functions on indexed columns in <code>WHERE</code></td>
<td><code>WHERE LOWER(email) = 'x'</code> can't use the index on <code>email</code></td>
<td>Use case-insensitive collation, or a functional index</td>
</tr>
<tr>
<td><code>OFFSET</code> for pagination at scale</td>
<td>O(N) — Postgres has to scan and skip rows. Slow past page 100</td>
<td>Cursor pagination using <code>WHERE id > last_seen_id</code></td>
</tr>
<tr>
<td><code>NOT IN</code> with <code>NULL</code> values</td>
<td>Returns nothing — three-valued logic gotcha</td>
<td><code>NOT EXISTS</code> or <code>LEFT JOIN ... WHERE x IS NULL</code></td>
</tr>
</tbody>
</table>
</section>
<section class="article-section">
<h2>Best SQL formatter for 2026 — what to compare</h2>
<p>Search results for "sql formatter online", "sql beautifier", "format sql query" return many tools but most ignore dialect (PostgreSQL <code>RETURNING</code>, MySQL <code>LIMIT</code>, SQL Server <code>TOP</code> all parsed differently). Three things separate the good from the noise: dialect awareness (correct keyword recognition for MySQL vs Postgres vs SQL Server), style configurability (keyword case, indent width, comma placement, JOIN style), and whether queries are processed locally or uploaded to a server. Here is how the most-used SQL formatters compare in 2026:</p>
<table class="ref-table">
<thead><tr><th>Tool</th><th>Dialects</th><th>Style options</th><th>Browser-only</th><th>Bulk & CLI</th><th>Cost</th></tr></thead>
<tbody>
<tr><td>FreeDevTool SQL Formatter</td><td>MySQL + PG + MSSQL + Oracle + SQLite</td><td>Case + indent + JOIN style</td><td>Yes</td><td>No</td><td>Free</td></tr>
<tr><td>sqlformat.org</td><td>Generic SQL</td><td>Limited</td><td>Server-side</td><td>API available</td><td>Free, ad-funded</td></tr>
<tr><td>poorsql.com</td><td>SQL Server biased</td><td>Style template</td><td>Server-side</td><td>Yes (paid)</td><td>Freemium</td></tr>
<tr><td>npm <code>sql-formatter</code></td><td>14+ dialects (PG, MySQL, MSSQL, BigQuery, Snowflake, etc.)</td><td>Full config</td><td>Local install</td><td>Yes (CLI)</td><td>Free, OSS</td></tr>
<tr><td>SQLFluff (Python)</td><td>15+ dialects, including dbt + Spark</td><td>Linter + formatter</td><td>Local install</td><td>Yes (CLI + CI)</td><td>Free, OSS</td></tr>
<tr><td>JetBrains DataGrip</td><td>All major dialects</td><td>Comprehensive</td><td>Local IDE</td><td>Yes (IDE)</td><td>Paid (~$199/yr)</td></tr>
</tbody>
</table>
<h3>How do I format SQL queries online without uploading them to a server?</h3>
<p>Paste any SQL into the input pane on this page. Formatting runs entirely in the browser via a JS implementation of the npm <code>sql-formatter</code> grammar — no upload, no server fetch. This matters because production queries often contain table names, column names, or hard-coded values (test data, customer IDs) that you don't want logged. Avoid online formatters that POST to a server endpoint (check DevTools Network tab on first format) — common pattern with sqlformat.org, poorsql.com, and most ad-funded "free SQL formatter" sites.</p>
<h3>What are the differences between MySQL, PostgreSQL, and SQL Server syntax?</h3>
<p>The 2026 dialect divergence has narrowed but still bites in formatting:</p>
<table class="ref-table">
<thead><tr><th>Feature</th><th>MySQL 8.4</th><th>PostgreSQL 18</th><th>SQL Server 2025</th></tr></thead>
<tbody>
<tr><td>Limit results</td><td><code>LIMIT 10</code></td><td><code>LIMIT 10</code> or <code>FETCH FIRST 10 ROWS</code></td><td><code>TOP 10</code> or <code>OFFSET ... FETCH NEXT</code></td></tr>
<tr><td>String concat</td><td><code>CONCAT(a, b)</code></td><td><code>a || b</code> or <code>CONCAT()</code></td><td><code>a + b</code> or <code>CONCAT()</code></td></tr>
<tr><td>Auto-increment</td><td><code>AUTO_INCREMENT</code></td><td><code>SERIAL</code> / <code>GENERATED AS IDENTITY</code></td><td><code>IDENTITY(1,1)</code></td></tr>
<tr><td>Insert returning</td><td>None (use last_insert_id())</td><td><code>RETURNING *</code></td><td><code>OUTPUT INSERTED.*</code></td></tr>
<tr><td>UPSERT</td><td><code>INSERT ... ON DUPLICATE KEY UPDATE</code></td><td><code>INSERT ... ON CONFLICT DO UPDATE</code></td><td><code>MERGE</code></td></tr>
<tr><td>UUIDv7 native</td><td>Helper function (8.4+)</td><td><code>uuidv7()</code> (PG 18 native)</td><td><code>NEWSEQUENTIALID()</code> (similar)</td></tr>
</tbody>
</table>
<p>Pick the right dialect dropdown so the formatter recognizes <code>RETURNING</code>, <code>TOP</code>, <code>MERGE</code>, and other dialect-specific keywords as keywords (uppercased) rather than identifiers (left as-is).</p>
<h3>SQL formatter alternative to sqlformat.org — 4 reasons developers switched</h3>
<ol>
<li><strong>Browser-only, no upload.</strong> sqlformat.org POSTs your query to a Python backend. Production queries with PII or unreleased schema names should never leave your browser.</li>
<li><strong>5 dialects with proper keyword recognition.</strong> Most online formatters use a generic SQL grammar that misformats <code>RETURNING</code> (PG), <code>TOP</code> (MSSQL), or <code>MERGE</code> (MSSQL/Oracle). This tool handles all five major dialects.</li>
<li><strong>Style options visible upfront.</strong> Keyword case, indent width, JOIN-on-newline are sliders/toggles at the top — not hidden behind a config file or "Settings" page.</li>
<li><strong>No ads, no rate limit.</strong> Free SQL formatters indexed by Google almost universally inject ads or cap requests per minute. This page has neither.</li>
</ol>
<p>Pair the SQL formatter with the <a href="/json-formatter">JSON Formatter</a> for API responses and migrations as JSONB, the <a href="/uuid-generator">UUID Generator</a> for UUIDv7 primary keys (PG 18 native), and the <a href="/generation-tools">Generation & Formatting Tools hub</a> for the broader formatter toolkit.</p>
<h2>SQL formatter best practices</h2>
<ul>
<li><strong>Format on save in your editor.</strong> The diff between formatted and unformatted SQL should never appear in a PR. Set up <code>editor.formatOnSave</code> for SQL files.</li>
<li><strong>Pin a config file.</strong> Commit <code>.sqlfluff</code>, <code>.sql-formatter</code>, or your IDE settings to the repo. Don't rely on each developer's local preferences.</li>
<li><strong>Run formatting in CI.</strong> Block PRs that don't match the agreed style. <code>sqlfluff lint --dialect postgres</code> is the easiest gate.</li>
<li><strong>Don't format auto-generated SQL.</strong> ORM-emitted queries (Hibernate, ActiveRecord, Sequelize) live in your logs, not your repo. Reformatting them just adds review noise.</li>
<li><strong>Format BEFORE committing.</strong> Reformatting committed code creates noisy diffs that bury real changes. Set up a pre-commit hook.</li>
<li><strong>Use <code>git blame</code>-friendly mode in massive reformats.</strong> Use <code>.git-blame-ignore-revs</code> to mark "format-only" commits so blame still shows real authors.</li>
<li><strong>Format inside string literals carefully.</strong> SQL embedded in JS/Python/Go strings often shouldn't be reformatted — multi-line raw strings preserve indentation. Most formatters skip these correctly; verify.</li>
</ul>
</section>
</article>
<!-- How to use + mistakes -->
<section class="use-cases">
<h2>How to use the SQL formatter</h2>
<p>Format SQL queries for readability — proper indentation, keyword casing, line breaks at clause boundaries. Supports MySQL, PostgreSQL, SQL Server, and Oracle dialect quirks. Runs locally; queries (including ones with sensitive data) never reach a server.</p>
<ul class="use-case-list">
<li><strong>1.</strong> Paste your query. Multi-statement scripts work too — separate with <code>;</code>.</li>
<li><strong>2.</strong> Pick the SQL dialect from the dropdown. Affects keyword recognition (<code>LIMIT</code> vs <code>TOP</code>), function names, and quoting style.</li>
<li><strong>3.</strong> Choose case style: UPPERCASE (default — keywords stand out in code review), lowercase (a more modern style), or preserve as-typed.</li>
<li><strong>4.</strong> Tune indentation (2/4 spaces or tabs) to match your team's style guide.</li>
<li><strong>5.</strong> Click "Format" — output appears below. Click "Minify" for the inverse, useful when embedding SQL into a string literal in code.</li>
</ul>
<h3>Common mistakes to avoid</h3>
<ul class="mistakes-list">
<li><strong>Formatting auto-generated SQL from ORMs.</strong> The output is rarely human-edited — formatting it just adds noise to PR diffs. Format only the queries you actually maintain.</li>
<li><strong>Mixing <code>JOIN</code> styles.</strong> Pick implicit (<code>FROM a, b WHERE</code>) or explicit (<code>FROM a JOIN b ON</code>) and stick to it. Mixing is a code-smell flagged by senior devs in review.</li>
<li><strong>Trusting <code>SELECT *</code>.</strong> Breaks when columns are added, slows queries by fetching unused data, and obscures what you actually depend on. Always enumerate columns in production code.</li>
<li><strong>Forgetting <code>WHERE</code> on <code>UPDATE</code>/<code>DELETE</code>.</strong> Without it, every row is touched. The classic outage. Many tools (DBeaver, MySQL Workbench) warn — don't dismiss.</li>
<li><strong>Using string interpolation instead of parameters.</strong> <code>WHERE id = ${userId}</code> is SQL injection waiting to happen. Always use parameterized queries (<code>?</code> placeholders or named parameters like <code>$1</code>, <code>:id</code>).</li>
<li><strong>Casing inconsistencies.</strong> Postgres folds unquoted identifiers to lowercase; MySQL is case-insensitive on Windows but case-sensitive on Linux. Quote identifiers if you care about case.</li>
</ul>
</section>
<section class="faq-section">
<h2>Frequently Asked Questions</h2>
<div class="faq-item"><div class="faq-q" onclick="toggleFaq(this)">What is SQL formatting and why should I format my SQL queries?<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg></div><div class="faq-a">SQL formatting restructures your code with consistent indentation, line breaks after major keywords, and proper keyword casing. Well-formatted SQL is significantly easier to debug, review in pull requests, and maintain over time. Most SQL style guides recommend uppercase keywords like SELECT, FROM, WHERE and consistent indentation for JOIN clauses, subqueries, and CASE expressions. This tool handles all of that automatically.</div></div>
<div class="faq-item"><div class="faq-q" onclick="toggleFaq(this)">Does this SQL formatter support different database dialects?<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg></div><div class="faq-a">This formatter handles standard SQL keywords shared across MySQL, PostgreSQL, SQL Server, Oracle, and SQLite. It recognizes major clauses including SELECT, FROM, WHERE, JOIN variants (INNER, LEFT, RIGHT, FULL, CROSS), GROUP BY, ORDER BY, HAVING, UNION, INSERT INTO, UPDATE, DELETE FROM, CREATE TABLE, ALTER TABLE, and more. Dialect-specific functions and syntax are preserved as-is during formatting.</div></div>
<div class="faq-item"><div class="faq-q" onclick="toggleFaq(this)">Is it safe to paste production SQL queries into an online formatter?<svg class="chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg></div><div class="faq-a">Yes. This tool runs entirely in your browser using client-side JavaScript. Your SQL queries never leave your machine — nothing is sent to a server, stored, or logged. You can disconnect from the internet and the formatter continues to work. This makes it safe for formatting queries containing sensitive table names, column names, or data values.</div></div>
</section>
<section class="related-section">
<h2>Related Tools</h2>
<div class="related-grid">
<a class="related-card" href="json-formatter"><div class="related-icon">{ }</div><div class="related-card-info"><div class="related-card-name">JSON Formatter</div><div class="related-card-desc">Pretty print and validate JSON</div></div></a>
<a class="related-card" href="css-minifier"><div class="related-icon">CSS</div><div class="related-card-info"><div class="related-card-name">CSS Minifier</div><div class="related-card-desc">Minify and beautify CSS code</div></div></a>
<a class="related-card" href="js-minifier"><div class="related-icon">JS</div><div class="related-card-info"><div class="related-card-name">JS Minifier</div><div class="related-card-desc">Minify and beautify JavaScript</div></div></a>
</div>
</section>
<section class="all-tools-section" aria-label="Browse all FreeDevTool developer tools">
<h2>Browse all 50 free developer tools</h2>
<p class="atc-sub">All tools run in your browser, no signup required, nothing sent to a server.</p>
<div class="all-tools-grid">
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">b64</div>
<div class="atc-cat-title"><h3>Encoding & Conversion</h3><span class="atc-cat-count">11 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/base64-encoder">Base64 Encoder / Decoder</a></li>
<li><a href="/base64-image">Image to Base64</a></li>
<li><a href="/byte-converter">Byte Converter (KB / MB / GB)</a></li>
<li><a href="/case-converter">Case Converter</a></li>
<li><a href="/hex-to-rgb">Hex to RGB / HSL</a></li>
<li><a href="/html-entity">HTML Entity Encoder</a></li>
<li><a href="/json-to-csv">JSON to CSV Converter</a></li>
<li><a href="/px-to-rem">PX to REM Converter</a></li>
<li><a href="/string-escape">String Escape / Unescape</a></li>
<li><a href="/url-encoder">URL Encoder / Decoder</a></li>
<li><a href="/yaml-to-json">YAML to JSON Converter</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">{ }</div>
<div class="atc-cat-title"><h3>Formatting & Generators</h3><span class="atc-cat-count">13 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/color-name">Color Name from Hex</a></li>
<li><a href="/color-picker">Color Palette Picker</a></li>
<li><a href="/css-box-shadow">CSS Box Shadow</a></li>
<li><a href="/css-gradient">CSS Gradient Generator</a></li>
<li><a href="/json-formatter">JSON Formatter / Validator</a></li>
<li><a href="/lorem-ipsum">Lorem Ipsum Generator</a></li>
<li><a href="/markdown-preview">Markdown Preview</a></li>
<li><a href="/password-generator">Password Generator</a></li>
<li><a href="/qr-generator">QR Code Generator</a></li>
<li><a href="/sql-formatter">SQL Formatter</a></li>
<li><a href="/uuid-generator">UUID Generator</a></li>
<li><a href="/word-to-markdown">Word to Markdown</a></li>
<li><a href="/xml-formatter">XML Formatter</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">JS</div>
<div class="atc-cat-title"><h3>Minifiers & DevOps</h3><span class="atc-cat-count">6 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/chmod-calculator">chmod Calculator</a></li>
<li><a href="/cron-parser">Cron Expression Parser</a></li>
<li><a href="/css-minifier">CSS Minifier</a></li>
<li><a href="/html-minifier">HTML Minifier</a></li>
<li><a href="/js-minifier">JavaScript Minifier</a></li>
<li><a href="/http-status">HTTP Status Codes</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">#</div>
<div class="atc-cat-title"><h3>Security & Hashing</h3><span class="atc-cat-count">3 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/hash-generator">Hash Generator (MD5, SHA)</a></li>
<li><a href="/jwt-decoder">JWT Decoder</a></li>
<li><a href="/jwt-generator">JWT Generator</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">.*</div>
<div class="atc-cat-title"><h3>Code & Text</h3><span class="atc-cat-count">8 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/ai-token-counter">AI Token Counter</a></li>
<li><a href="/char-counter">Character & Word Counter</a></li>
<li><a href="/git-cheatsheet">Git Commands Cheatsheet</a></li>
<li><a href="/number-base">Number Base Converter</a></li>
<li><a href="/regex-explainer">Regex Explainer</a></li>
<li><a href="/regex-tester">Regex Tester</a></li>
<li><a href="/text-diff">Text Diff Checker</a></li>
<li><a href="/wcag-contrast">WCAG Contrast Checker</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">IP</div>
<div class="atc-cat-title"><h3>Network & APIs</h3><span class="atc-cat-count">3 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/dns-lookup">DNS Lookup</a></li>
<li><a href="/http-request-builder">HTTP Request Builder</a></li>
<li><a href="/ip-lookup">IP Address Lookup</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">⏱</div>
<div class="atc-cat-title"><h3>Time & Dates</h3><span class="atc-cat-count">3 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/relative-time">Relative Time Calculator</a></li>
<li><a href="/timestamp-diff">Timestamp Diff</a></li>
<li><a href="/unix-timestamp-converter">Unix Timestamp Converter</a></li>
</ul>
</div>
<div class="atc-cat">
<div class="atc-cat-head">
<div class="atc-cat-icon">SEO</div>
<div class="atc-cat-title"><h3>SEO & Meta</h3><span class="atc-cat-count">3 tools</span></div>
</div>
<ul class="atc-list">
<li><a href="/meta-tag-generator">Meta Tag Generator</a></li>
<li><a href="/og-preview">Open Graph Preview</a></li>
<li><a href="/slug-generator">URL Slug Generator</a></li>
</ul>
</div>
</div>
</section>
</div>
<footer>
<div>© 2026 FreeDevTool — SQL Formatter & Beautifier</div>
<div class="footer-links"><a href="/all-tools">All Tools</a><a href="/about">About</a><a href="/privacy">Privacy Policy</a><a href="/terms">Terms of Use</a></div>
</footer>
<script>
const SQL_KW = ['SELECT','FROM','WHERE','JOIN','INNER JOIN','LEFT JOIN','RIGHT JOIN','FULL JOIN','FULL OUTER JOIN','CROSS JOIN','LEFT OUTER JOIN','RIGHT OUTER JOIN','ON','AND','OR','NOT','IN','EXISTS','BETWEEN','LIKE','IS NULL','IS NOT NULL','ORDER BY','GROUP BY','HAVING','LIMIT','OFFSET','UNION','UNION ALL','INTERSECT','EXCEPT','INSERT INTO','VALUES','UPDATE','SET','DELETE FROM','DELETE','CREATE TABLE','CREATE INDEX','CREATE VIEW','ALTER TABLE','DROP TABLE','DROP INDEX','DROP VIEW','ADD COLUMN','DROP COLUMN','MODIFY','CASE','WHEN','THEN','ELSE','END','AS','DISTINCT','ALL','TOP','INTO','IF','BEGIN','COMMIT','ROLLBACK','GRANT','REVOKE','WITH','RECURSIVE','OVER','PARTITION BY','ROWS','RANGE','FETCH','NEXT','ONLY','FOR','RETURNING','CASCADE','RESTRICT','REFERENCES','FOREIGN KEY','PRIMARY KEY','UNIQUE','CHECK','DEFAULT','INDEX','CONSTRAINT','TRIGGER','PROCEDURE','FUNCTION','DECLARE','CURSOR','OPEN','CLOSE','DEALLOCATE','EXEC','EXECUTE','USE','DATABASE','SCHEMA','TABLE','VIEW','TEMPORARY','TEMP','TRUNCATE','EXPLAIN','ANALYZE','VACUUM','REINDEX','CLUSTER'];
const MAJOR_CLAUSES = ['SELECT','FROM','WHERE','JOIN','INNER JOIN','LEFT JOIN','RIGHT JOIN','FULL JOIN','FULL OUTER JOIN','CROSS JOIN','LEFT OUTER JOIN','RIGHT OUTER JOIN','ORDER BY','GROUP BY','HAVING','LIMIT','OFFSET','UNION','UNION ALL','INTERSECT','EXCEPT','INSERT INTO','VALUES','UPDATE','SET','DELETE FROM','DELETE','CREATE TABLE','ALTER TABLE','DROP TABLE','WITH','RETURNING','ON'];
const MINOR_KW = ['AND','OR','WHEN','THEN','ELSE','END'];
function getIndent(){const v=document.getElementById('indent-size').value;return v==='tab'?'\t':' '.repeat(parseInt(v));}
function tokenize(sql){
const tokens=[];let i=0;
while(i<sql.length){
if(sql[i]==="'"||sql[i]==='"'){
const q=sql[i];let j=i+1;
while(j<sql.length&&sql[j]!==q){if(sql[j]==='\\')j++;j++;}
tokens.push({type:'string',value:sql.substring(i,j+1)});i=j+1;
}else if(sql[i]==='-'&&sql[i+1]==='-'){
let j=i;while(j<sql.length&&sql[j]!=='\n')j++;
tokens.push({type:'comment',value:sql.substring(i,j)});i=j;
}else if(sql[i]==='/'&&sql[i+1]==='*'){
let j=i+2;while(j<sql.length-1&&!(sql[j]==='*'&&sql[j+1]==='/'))j++;
tokens.push({type:'comment',value:sql.substring(i,j+2)});i=j+2;
}else if(sql[i]==='('){tokens.push({type:'paren',value:'('});i++;
}else if(sql[i]===')'){tokens.push({type:'paren',value:')'});i++;
}else if(sql[i]===','){tokens.push({type:'comma',value:','});i++;
}else if(sql[i]===';'){tokens.push({type:'semi',value:';'});i++;
}else if(/\s/.test(sql[i])){while(i<sql.length&&/\s/.test(sql[i]))i++;tokens.push({type:'ws',value:' '});
}else{
let j=i;while(j<sql.length&&!/[\s()',;"]/.test(sql[j])&&!(sql[j]==='-'&&sql[j+1]==='-')&&!(sql[j]==='/'&&sql[j+1]==='*'))j++;
tokens.push({type:'word',value:sql.substring(i,j)});i=j;
}
}
return tokens.filter(t=>t.type!=='ws'||false);
}
function formatSQL(){
const sql=document.getElementById('sql-input').value;
if(!sql.trim())return;
const uc=document.getElementById('uppercase-kw').checked;
const ind=getIndent();
const tokens=tokenize(sql).filter(t=>t.type!=='ws');
let result='',depth=0,newline=true;
function nl(){result+='\n'+ind.repeat(depth);newline=true;}
function addSpace(){if(!newline&&result.length>0&&!result.endsWith(' ')&&!result.endsWith('\n')&&!result.endsWith(ind))result+=' ';}
for(let i=0;i<tokens.length;i++){
const t=tokens[i];
if(t.type==='comment'){addSpace();result+=t.value;nl();continue;}
if(t.type==='string'){addSpace();result+=t.value;newline=false;continue;}
if(t.type==='semi'){result+=';';nl();nl();continue;}
if(t.type==='comma'){result+=',';nl();continue;}
if(t.type==='paren'){
if(t.value==='('){addSpace();result+='(';depth++;nl();}
else{depth=Math.max(0,depth-1);nl();result+=')';}
newline=false;continue;
}
if(t.type==='word'){
const upper=t.value.toUpperCase();
let matched='';
// Check multi-word keywords
if(i+1<tokens.length){
const next=tokens.slice(i+1).find(x=>x.type==='word');
if(next){
const combo=upper+' '+next.value.toUpperCase();
const combo3=i+2<tokens.length?(function(){const nn=tokens.slice(i+2).find(x=>x.type==='word');return nn?combo+' '+nn.value.toUpperCase():''})():'';
if(MAJOR_CLAUSES.includes(combo3))matched=combo3;
else if(MAJOR_CLAUSES.includes(combo))matched=combo;
}
}
if(!matched&&MAJOR_CLAUSES.includes(upper))matched=upper;
if(matched){
const words=matched.split(' ');
if(matched!=='ON'||depth===0){
if(!newline&&result.trim().length>0)nl();
}
const kw=uc?matched:matched.toLowerCase();
result+=kw;newline=false;
// Skip consumed tokens
let skip=words.length-1;
while(skip>0&&i+1<tokens.length){i++;if(tokens[i].type==='word')skip--;}
continue;
}
if(MINOR_KW.includes(upper)){
nl();result+=uc?upper:upper.toLowerCase();newline=false;continue;
}
// Regular word
addSpace();
const isKW=SQL_KW.includes(upper);
result+=isKW&&uc?upper:t.value;
newline=false;
}
}
document.getElementById('sql-output').value=result.trim();
updateStats();
}
function minifySQL(){
const sql=document.getElementById('sql-input').value;
if(!sql.trim())return;
const tokens=tokenize(sql).filter(t=>t.type!=='ws'&&t.type!=='comment');
let result='';
for(let i=0;i<tokens.length;i++){
const t=tokens[i];
if(t.type==='word'||t.type==='string'){
if(result.length>0&&!result.endsWith(' ')&&!result.endsWith('(')&&!result.endsWith(','))result+=' ';
result+=t.value;
}else{result+=t.value;}
}
document.getElementById('sql-output').value=result.replace(/\s+/g,' ').trim();
updateStats();
}
function loadSample(){
document.getElementById('sql-input').value=`SELECT u.id, u.name, u.email, COUNT(o.id) AS order_count, SUM(o.total) AS total_spent FROM users u INNER JOIN orders o ON u.id = o.user_id LEFT JOIN addresses a ON u.id = a.user_id WHERE u.created_at >= '2024-01-01' AND u.status = 'active' AND o.total > 50 GROUP BY u.id, u.name, u.email HAVING COUNT(o.id) > 3 ORDER BY total_spent DESC LIMIT 100 OFFSET 0;`;
formatSQL();
}
function clearAll(){document.getElementById('sql-input').value='';document.getElementById('sql-output').value='';updateStats();}
function copyOutput(){const v=document.getElementById('sql-output').value;if(!v)return;navigator.clipboard.writeText(v);const t=document.getElementById('toast');t.style.opacity='1';setTimeout(()=>t.style.opacity='0',1500);}
function updateStats(){
const i=document.getElementById('sql-input').value,o=document.getElementById('sql-output').value;
document.getElementById('input-stats').textContent=(i?i.split('\n').length:0)+' lines, '+i.length+' chars';
document.getElementById('output-stats').textContent=(o?o.split('\n').length:0)+' lines, '+o.length+' chars';
}
document.getElementById('sql-input').addEventListener('input',updateStats);
function toggleFaq(el){el.parentElement.classList.toggle('open');}
</script>
</body>
</html>