<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Self-Join on Tarragon</title><link>https://tarrragon.github.io/blog/tags/self-join/</link><description>Recent content in Self-Join on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Mon, 31 Aug 2026 00:00:00 +0800</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/self-join/index.xml" rel="self" type="application/rss+xml"/><item><title>SQL.7 表的出現與別名：表名的指稱、別名的作用範圍與自連接</title><link>https://tarrragon.github.io/blog/backend/01-database/sql/table-occurrence-and-alias/</link><pubDate>Mon, 31 Aug 2026 00:00:00 +0800</pubDate><guid>https://tarrragon.github.io/blog/backend/01-database/sql/table-occurrence-and-alias/</guid><description>&lt;p>&lt;code>FROM&lt;/code> 裡寫下的表名指的是那張表在這個查詢裡的一次出現，而那個名字是這次出現的稱呼。標準把這件事叫 table reference，關聯演算（relational calculus）裡的傳統名稱是 range variable，各家文件裡也常寫成 correlation name——三個名字說的是同一件事。同一張表因此可以出現兩次、各自扮演不同角色——這就是自連接。&lt;/p>
&lt;p>一張表只出現一次的時候，這個區別沒有作用。出現兩次就有：兩次出現共用同一個名字，引擎分不出某個欄位屬於哪一次，於是擋下來。&lt;/p>
&lt;p>引擎把這件事講得很明白，而擋下來的時機分兩種。PostgreSQL 與 DuckDB 看到重複的名字就停，訊息分別是 &lt;code>table name &amp;quot;訂單&amp;quot; specified more than once&lt;/code> 與 &lt;code>Duplicate alias &amp;quot;訂單&amp;quot; in query!&lt;/code>；SQLite 讓查詢往下走，等到某個欄位引用無從分辨時才回 &lt;code>ambiguous column name&lt;/code>。&lt;strong>表名本身就是預設的別名&lt;/strong>，所以同一張表的兩次出現共用同一個名字時，等於兩次出現叫同一個稱呼，之後每一次引用都無從分辨。&lt;/p>
&lt;h2 id="兩張表共用欄名時的欄位歸屬">兩張表共用欄名時的欄位歸屬&lt;/h2>
&lt;p>欄位的歸屬要靠名字決定，所以兩張不同的表共用一個欄名時同樣分不開。書店的顧客表與訂單表都有 &lt;code>顧客編號&lt;/code>：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="k">SELECT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">顧客編號&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">FROM&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">顧客&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">LEFT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">JOIN&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">訂單&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">ON&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">訂單&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="err">顧客編號&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">顧客&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="err">顧客編號&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">-- MySQL: ERROR 1052: Column &amp;#39;顧客編號&amp;#39; in field list is ambiguous
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="c1">-- SQLite: ambiguous column name: 顧客編號
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="c1">-- DuckDB: Ambiguous reference to column name &amp;#34;顧客編號&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>id&lt;/code> 是這件事最常撞到的欄位名，因為多數表都有一個。&lt;strong>連接之後每個欄位引用都要能追回它屬於哪一次出現&lt;/strong>，加上表名或別名當前綴就解決。&lt;/p>
&lt;p>自連接只是這個規則的極端情形：兩次出現連表名都一樣，所以連前綴都救不了，非取別名不可。&lt;/p>
&lt;p>表一多，要判讀的就變成每個 &lt;code>ON&lt;/code> 引用得到哪些出現——寫在它上面的那些出現都已經併進左運算元，寫在它下面的還沒進來。&lt;a href="https://tarrragon.github.io/blog/backend/01-database/sql/join-left-operand-accumulates/" data-link-title="SQL.4 鏈式連接的左運算元：累積方式與外連接的保護範圍" data-link-desc="每個 JOIN 的左運算元由哪些表合成、ON 因此引用得到哪些欄位、LEFT 與 RIGHT 各自保護哪些列，以及 WHERE 引用鏈尾的表時哪些列會被撤掉保護">SQL.4 鏈式連接的左運算元&lt;/a> 寫左運算元隨著往下走而變大的過程。&lt;/p>
&lt;h2 id="用別名分開同一張表的兩次出現">用別名分開同一張表的兩次出現&lt;/h2>
&lt;p>訂單表裡的兩張單都掛在佳穎名下。要找出同一位顧客的訂單先後配對——哪一張在前、哪一張在後。這件事需要把訂單表的兩列擺在一起比較，而一列一列處理的查詢做不到，除非讓訂單表出現兩次：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="k">SELECT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">早&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="err">訂單編號&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">早&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="err">下單日&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">晚&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="err">訂單編號&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">晚&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="err">下單日&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">FROM&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">訂單&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">AS&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">早&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">JOIN&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">訂單&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">AS&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">晚&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">ON&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">早&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="err">顧客編號&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">晚&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="err">顧客編號&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">AND&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">早&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="err">下單日&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">晚&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="err">下單日&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">-- 101 | 2026-03-02 | 102 | 2026-03-09&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>早&lt;/code> 與 &lt;code>晚&lt;/code> 是同一張表的兩次出現。連接條件在做兩件事：&lt;code>顧客編號&lt;/code> 相同把配對限制在同一個人身上，&lt;code>下單日&lt;/code> 的大小關係決定哪一次出現扮演「早」、哪一次扮演「晚」。&lt;/p>
&lt;p>&lt;strong>條件裡的第二項是這個寫法的重點。&lt;/strong> 少了它，每張訂單會跟同一位顧客的每張訂單配對一次，包括跟自己配。加上嚴格的大小比較之後，每一對只留下一個方向，而同一張訂單跟它自己組成的那一對，因為兩邊日期相等也被排除。同一位顧客有三張訂單時，每兩張各配一次，不多不少：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-sql" data-lang="sql">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1">-- 拿掉日期的比較，只留顧客編號相同
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">SELECT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">早&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="err">訂單編號&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">晚&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="err">訂單編號&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">FROM&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">訂單&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">AS&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">早&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">JOIN&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">訂單&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">AS&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">晚&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">ON&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">早&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="err">顧客編號&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">晚&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="err">顧客編號&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">-- 共用資料：101|101、101|102、102|101、102|102（兩個方向各一次，加上各自跟自己配）
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">-- 日期的比較放回去
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">SELECT&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">早&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="err">訂單編號&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">晚&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="err">訂單編號&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">FROM&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">訂單&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">AS&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">早&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">JOIN&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">訂單&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">AS&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">晚&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">ON&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">早&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="err">顧客編號&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">晚&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="err">顧客編號&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">AND&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">早&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="err">下單日&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="err">晚&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="err">下單日&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="c1">-- 共用資料：101|102
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="c1">-- 佳穎多一張 103（下單日 2026-03-15）之後：101|102、101|103、102|103&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="自連接的適用問題前後配對同組比較與層級關係">自連接的適用問題：前後配對、同組比較與層級關係&lt;/h2>
&lt;p>自連接處理的是&lt;strong>同一批資料裡兩筆資料之間的關係&lt;/strong>——兩列，不是兩個欄位。一列一列的處理看不到這種關係，因為每一列在被判斷的時候不知道其他列長什麼樣子。&lt;/p>
&lt;p>自連接常見的形態有三種。&lt;strong>前後配對&lt;/strong>：同一位顧客的訂單先後配對，把時間上相鄰或有先後關係的兩列擺在一起。&lt;strong>同組比較&lt;/strong>：找出訂單金額高於同一位顧客其他訂單的那些，比較的對象是同一張表裡的兄弟列。&lt;strong>層級關係&lt;/strong>：一張員工表裡每個人有一個主管欄位指向同一張表的另一列，要把人與他的主管一起列出來時，員工表出現兩次，一次當員工、一次當主管。&lt;/p>
&lt;p>前後配對、同組比較與層級關係三種的共同點是&lt;strong>要比較的兩列住在同一張表裡&lt;/strong>。需不需要自連接由兩個獨立的問題決定：這個問題要不要拿一列去跟同一張表的另一列比——不比的問題不屬於這一族；以及要不要把另一列的欄位輸出出來——這個問題決定族裡選哪一種寫法。&lt;/p>
&lt;p>要不要輸出另一列的欄位，就是 &lt;a href="https://tarrragon.github.io/blog/backend/01-database/sql/in-exists-join/" data-link-title="SQL.8 IN、EXISTS 與 JOIN：列數、可取用的欄位與 NULL 的處理" data-link-desc="同一個「找出有對應資料的那些」的問題用成員判斷、存在性判斷與連接各寫一次的結果，選用的判斷標準，以及子查詢含 NULL 時 NOT IN 與 NOT EXISTS 的分岔">SQL.8 IN、EXISTS 與 JOIN：列數、可取用的欄位與 NULL 的處理&lt;/a> 那條判斷標準——自連接也是一種 &lt;code>JOIN&lt;/code>，所以它同樣適用。只是判斷「有沒有另一列符合條件」而不輸出它，用 &lt;code>EXISTS&lt;/code> 比自連接省一次配對展開；要把兩列並排列出來（像上面的訂單先後配對），才非自連接不可。&lt;/p></description><content:encoded><![CDATA[<p><code>FROM</code> 裡寫下的表名指的是那張表在這個查詢裡的一次出現，而那個名字是這次出現的稱呼。標準把這件事叫 table reference，關聯演算（relational calculus）裡的傳統名稱是 range variable，各家文件裡也常寫成 correlation name——三個名字說的是同一件事。同一張表因此可以出現兩次、各自扮演不同角色——這就是自連接。</p>
<p>一張表只出現一次的時候，這個區別沒有作用。出現兩次就有：兩次出現共用同一個名字，引擎分不出某個欄位屬於哪一次，於是擋下來。</p>
<p>引擎把這件事講得很明白，而擋下來的時機分兩種。PostgreSQL 與 DuckDB 看到重複的名字就停，訊息分別是 <code>table name &quot;訂單&quot; specified more than once</code> 與 <code>Duplicate alias &quot;訂單&quot; in query!</code>；SQLite 讓查詢往下走，等到某個欄位引用無從分辨時才回 <code>ambiguous column name</code>。<strong>表名本身就是預設的別名</strong>，所以同一張表的兩次出現共用同一個名字時，等於兩次出現叫同一個稱呼，之後每一次引用都無從分辨。</p>
<h2 id="兩張表共用欄名時的欄位歸屬">兩張表共用欄名時的欄位歸屬</h2>
<p>欄位的歸屬要靠名字決定，所以兩張不同的表共用一個欄名時同樣分不開。書店的顧客表與訂單表都有 <code>顧客編號</code>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="err">顧客編號</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="err">顧客</span><span class="w"> </span><span class="k">LEFT</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="err">訂單</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="err">訂單</span><span class="p">.</span><span class="err">顧客編號</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="err">顧客</span><span class="p">.</span><span class="err">顧客編號</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="w"></span><span class="c1">-- MySQL:  ERROR 1052: Column &#39;顧客編號&#39; in field list is ambiguous
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="c1">-- SQLite: ambiguous column name: 顧客編號
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1">-- DuckDB: Ambiguous reference to column name &#34;顧客編號&#34;</span></span></span></code></pre></div><p><code>id</code> 是這件事最常撞到的欄位名，因為多數表都有一個。<strong>連接之後每個欄位引用都要能追回它屬於哪一次出現</strong>，加上表名或別名當前綴就解決。</p>
<p>自連接只是這個規則的極端情形：兩次出現連表名都一樣，所以連前綴都救不了，非取別名不可。</p>
<p>表一多，要判讀的就變成每個 <code>ON</code> 引用得到哪些出現——寫在它上面的那些出現都已經併進左運算元，寫在它下面的還沒進來。<a href="/blog/backend/01-database/sql/join-left-operand-accumulates/" data-link-title="SQL.4 鏈式連接的左運算元：累積方式與外連接的保護範圍" data-link-desc="每個 JOIN 的左運算元由哪些表合成、ON 因此引用得到哪些欄位、LEFT 與 RIGHT 各自保護哪些列，以及 WHERE 引用鏈尾的表時哪些列會被撤掉保護">SQL.4 鏈式連接的左運算元</a> 寫左運算元隨著往下走而變大的過程。</p>
<h2 id="用別名分開同一張表的兩次出現">用別名分開同一張表的兩次出現</h2>
<p>訂單表裡的兩張單都掛在佳穎名下。要找出同一位顧客的訂單先後配對——哪一張在前、哪一張在後。這件事需要把訂單表的兩列擺在一起比較，而一列一列處理的查詢做不到，除非讓訂單表出現兩次：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="err">早</span><span class="p">.</span><span class="err">訂單編號</span><span class="p">,</span><span class="w"> </span><span class="err">早</span><span class="p">.</span><span class="err">下單日</span><span class="p">,</span><span class="w"> </span><span class="err">晚</span><span class="p">.</span><span class="err">訂單編號</span><span class="p">,</span><span class="w"> </span><span class="err">晚</span><span class="p">.</span><span class="err">下單日</span><span class="w">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="err">訂單</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="err">早</span><span class="w">
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="w"></span><span class="k">JOIN</span><span class="w"> </span><span class="err">訂單</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="err">晚</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="err">早</span><span class="p">.</span><span class="err">顧客編號</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="err">晚</span><span class="p">.</span><span class="err">顧客編號</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="err">早</span><span class="p">.</span><span class="err">下單日</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="err">晚</span><span class="p">.</span><span class="err">下單日</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="w"></span><span class="c1">-- 101 | 2026-03-02 | 102 | 2026-03-09</span></span></span></code></pre></div><p><code>早</code> 與 <code>晚</code> 是同一張表的兩次出現。連接條件在做兩件事：<code>顧客編號</code> 相同把配對限制在同一個人身上，<code>下單日</code> 的大小關係決定哪一次出現扮演「早」、哪一次扮演「晚」。</p>
<p><strong>條件裡的第二項是這個寫法的重點。</strong> 少了它，每張訂單會跟同一位顧客的每張訂單配對一次，包括跟自己配。加上嚴格的大小比較之後，每一對只留下一個方向，而同一張訂單跟它自己組成的那一對，因為兩邊日期相等也被排除。同一位顧客有三張訂單時，每兩張各配一次，不多不少：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">-- 拿掉日期的比較，只留顧客編號相同
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> </span><span class="err">早</span><span class="p">.</span><span class="err">訂單編號</span><span class="p">,</span><span class="w"> </span><span class="err">晚</span><span class="p">.</span><span class="err">訂單編號</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="err">訂單</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="err">早</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="k">JOIN</span><span class="w"> </span><span class="err">訂單</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="err">晚</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="err">早</span><span class="p">.</span><span class="err">顧客編號</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="err">晚</span><span class="p">.</span><span class="err">顧客編號</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w"></span><span class="c1">-- 共用資料：101|101、101|102、102|101、102|102（兩個方向各一次，加上各自跟自己配）
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w"></span><span class="c1">-- 日期的比較放回去
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> </span><span class="err">早</span><span class="p">.</span><span class="err">訂單編號</span><span class="p">,</span><span class="w"> </span><span class="err">晚</span><span class="p">.</span><span class="err">訂單編號</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="err">訂單</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="err">早</span><span class="w">
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="w"></span><span class="k">JOIN</span><span class="w"> </span><span class="err">訂單</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="err">晚</span><span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="err">早</span><span class="p">.</span><span class="err">顧客編號</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="err">晚</span><span class="p">.</span><span class="err">顧客編號</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="err">早</span><span class="p">.</span><span class="err">下單日</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="err">晚</span><span class="p">.</span><span class="err">下單日</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="w"></span><span class="c1">-- 共用資料：101|102
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1">-- 佳穎多一張 103（下單日 2026-03-15）之後：101|102、101|103、102|103</span></span></span></code></pre></div><h2 id="自連接的適用問題前後配對同組比較與層級關係">自連接的適用問題：前後配對、同組比較與層級關係</h2>
<p>自連接處理的是<strong>同一批資料裡兩筆資料之間的關係</strong>——兩列，不是兩個欄位。一列一列的處理看不到這種關係，因為每一列在被判斷的時候不知道其他列長什麼樣子。</p>
<p>自連接常見的形態有三種。<strong>前後配對</strong>：同一位顧客的訂單先後配對，把時間上相鄰或有先後關係的兩列擺在一起。<strong>同組比較</strong>：找出訂單金額高於同一位顧客其他訂單的那些，比較的對象是同一張表裡的兄弟列。<strong>層級關係</strong>：一張員工表裡每個人有一個主管欄位指向同一張表的另一列，要把人與他的主管一起列出來時，員工表出現兩次，一次當員工、一次當主管。</p>
<p>前後配對、同組比較與層級關係三種的共同點是<strong>要比較的兩列住在同一張表裡</strong>。需不需要自連接由兩個獨立的問題決定：這個問題要不要拿一列去跟同一張表的另一列比——不比的問題不屬於這一族；以及要不要把另一列的欄位輸出出來——這個問題決定族裡選哪一種寫法。</p>
<p>要不要輸出另一列的欄位，就是 <a href="/blog/backend/01-database/sql/in-exists-join/" data-link-title="SQL.8 IN、EXISTS 與 JOIN：列數、可取用的欄位與 NULL 的處理" data-link-desc="同一個「找出有對應資料的那些」的問題用成員判斷、存在性判斷與連接各寫一次的結果，選用的判斷標準，以及子查詢含 NULL 時 NOT IN 與 NOT EXISTS 的分岔">SQL.8 IN、EXISTS 與 JOIN：列數、可取用的欄位與 NULL 的處理</a> 那條判斷標準——自連接也是一種 <code>JOIN</code>，所以它同樣適用。只是判斷「有沒有另一列符合條件」而不輸出它，用 <code>EXISTS</code> 比自連接省一次配對展開；要把兩列並排列出來（像上面的訂單先後配對），才非自連接不可。</p>
<p><strong>省下的量由配對會不會膨脹決定，所以這條判斷標準要連著連接鍵唯不唯一一起看。</strong> 連接鍵在對面那一次出現裡唯一的時候，一列只配得到一列，兩種寫法產出的列數相同，<code>EXISTS</code> 省下的是零——那時選哪一個回到讀起來哪一個貼合意圖。一列配得到多列的時候展開才會發生，而那正是 <a href="/blog/backend/01-database/sql/join-changes-rows-and-nulls/" data-link-title="SQL.6 連接之後的列數與空缺：列數膨脹、外連接補的 NULL 與三值邏輯" data-link-desc="連接讓聚合多算的機制與計數、加總、平均、中位數各自的修法，以及外連接補出來的 NULL 在 count、等號比較、NOT IN 與 NOT EXISTS 上的行為">SQL.6 連接之後的列數與空缺：列數膨脹、外連接補的 NULL 與三值邏輯</a> 寫的列數膨脹。判斷的動作是問這個連接鍵在對面那一次出現裡唯不唯一，而唯一與否要由<a href="/blog/backend/01-database/sql/knowledge-cards/constraint/" data-link-title="Constraint（約束）" data-link-desc="看到「這個保證要來自約束而不是來自習慣」，或想確認某一欄會不會出現 NULL 時，查這一層由誰擋">約束</a>回答，不由現在這批資料回答。</p>
<p><strong>同組比較最常見的題型是每組最大值，而它套用「要不要輸出另一列的欄位」這條判斷標準時，答案是不輸出。</strong> 「找出每位顧客金額最高的訂單」輸出的是那張訂單自己的欄位，同顧客的其他訂單只拿來比大小，所以寫成 <code>NOT EXISTS</code> 就夠。前後配對的「找出每筆訂單與同顧客下一筆的差額」則要用到另一列的金額，那就非自連接不可。</p>
<p>每組最大值的條件是比大小，而比大小自己會帶出兩個邊界：<strong>並列的最大值</strong>與<strong>可為空的比較欄</strong>。<code>NOT EXISTS</code> 會把並列的那幾筆全部留下，要只留一筆得另外加一個決勝的條件，通常取編號最小的那筆。<code>NULL</code> 跟誰比都判不成真，所以「同顧客裡沒有比它大的」對金額是 <code>NULL</code> 的那一張恆成立，它會被選成最大；要排除它，<code>IS NOT NULL</code> 得寫在外層查詢——子查詢裡的比較對它本來就判不成真，寫在那裡攔不住（機制見 <a href="/blog/backend/01-database/sql/join-changes-rows-and-nulls/" data-link-title="SQL.6 連接之後的列數與空缺：列數膨脹、外連接補的 NULL 與三值邏輯" data-link-desc="連接讓聚合多算的機制與計數、加總、平均、中位數各自的修法，以及外連接補出來的 NULL 在 count、等號比較、NOT IN 與 NOT EXISTS 上的行為">SQL.6 連接之後的列數與空缺：列數膨脹、外連接補的 NULL 與三值邏輯</a>）。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">-- 每位顧客金額最高的訂單：同顧客裡找不到比它大的那一張
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> </span><span class="n">o</span><span class="p">.</span><span class="err">訂單編號</span><span class="p">,</span><span class="w"> </span><span class="n">o</span><span class="p">.</span><span class="err">金額</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="err">訂單</span><span class="w"> </span><span class="n">o</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="w"></span><span class="k">WHERE</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">EXISTS</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="w">  </span><span class="k">SELECT</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="err">訂單</span><span class="w"> </span><span class="n">i</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="w">  </span><span class="k">WHERE</span><span class="w"> </span><span class="n">i</span><span class="p">.</span><span class="err">顧客編號</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">o</span><span class="p">.</span><span class="err">顧客編號</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">i</span><span class="p">.</span><span class="err">金額</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="n">o</span><span class="p">.</span><span class="err">金額</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="w"></span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="w"></span><span class="c1">-- 共用資料：102 | 500
</span></span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1">-- 佳穎多一張 103（金額 500）之後：102 | 500、103 | 500（並列的兩張都留下）
</span></span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1">-- 佳穎多一張 104（金額 NULL）之後：102 | 500、104 | NULL（NULL 那一張被選成最大）
</span></span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="w"></span><span class="c1">-- 決勝的條件：金額相同時，編號較小的那一張也算「比它大」
</span></span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> </span><span class="n">o</span><span class="p">.</span><span class="err">訂單編號</span><span class="p">,</span><span class="w"> </span><span class="n">o</span><span class="p">.</span><span class="err">金額</span><span class="w">
</span></span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="err">訂單</span><span class="w"> </span><span class="n">o</span><span class="w">
</span></span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="w"></span><span class="k">WHERE</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">EXISTS</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="w">  </span><span class="k">SELECT</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="err">訂單</span><span class="w"> </span><span class="n">i</span><span class="w">
</span></span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="w">  </span><span class="k">WHERE</span><span class="w"> </span><span class="n">i</span><span class="p">.</span><span class="err">顧客編號</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">o</span><span class="p">.</span><span class="err">顧客編號</span><span class="w">
</span></span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="w">    </span><span class="k">AND</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="p">.</span><span class="err">金額</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="n">o</span><span class="p">.</span><span class="err">金額</span><span class="w"> </span><span class="k">OR</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="p">.</span><span class="err">金額</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">o</span><span class="p">.</span><span class="err">金額</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">i</span><span class="p">.</span><span class="err">訂單編號</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">o</span><span class="p">.</span><span class="err">訂單編號</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="ln">19</span><span class="cl"><span class="w"></span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="w"></span><span class="c1">-- 佳穎多一張 103（金額 500）之後：102 | 500
</span></span></span><span class="line"><span class="ln">21</span><span class="cl"><span class="c1"></span><span class="w">
</span></span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="w"></span><span class="c1">-- 排除金額是 NULL 的那一張：條件寫在外層
</span></span></span><span class="line"><span class="ln">23</span><span class="cl"><span class="c1"></span><span class="k">SELECT</span><span class="w"> </span><span class="n">o</span><span class="p">.</span><span class="err">訂單編號</span><span class="p">,</span><span class="w"> </span><span class="n">o</span><span class="p">.</span><span class="err">金額</span><span class="w">
</span></span></span><span class="line"><span class="ln">24</span><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="err">訂單</span><span class="w"> </span><span class="n">o</span><span class="w">
</span></span></span><span class="line"><span class="ln">25</span><span class="cl"><span class="w"></span><span class="k">WHERE</span><span class="w"> </span><span class="n">o</span><span class="p">.</span><span class="err">金額</span><span class="w"> </span><span class="k">IS</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">NULL</span><span class="w">
</span></span></span><span class="line"><span class="ln">26</span><span class="cl"><span class="w">  </span><span class="k">AND</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">EXISTS</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="ln">27</span><span class="cl"><span class="w">    </span><span class="k">SELECT</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="err">訂單</span><span class="w"> </span><span class="n">i</span><span class="w">
</span></span></span><span class="line"><span class="ln">28</span><span class="cl"><span class="w">    </span><span class="k">WHERE</span><span class="w"> </span><span class="n">i</span><span class="p">.</span><span class="err">顧客編號</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">o</span><span class="p">.</span><span class="err">顧客編號</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="n">i</span><span class="p">.</span><span class="err">金額</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="n">o</span><span class="p">.</span><span class="err">金額</span><span class="w">
</span></span></span><span class="line"><span class="ln">29</span><span class="cl"><span class="w">  </span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="ln">30</span><span class="cl"><span class="w"></span><span class="c1">-- 佳穎多一張 104（金額 NULL）之後：102 | 500
</span></span></span><span class="line"><span class="ln">31</span><span class="cl"><span class="c1">-- 同一句改寫進子查詢（AND i.金額 IS NOT NULL）：仍回 102 | 500、104 | NULL</span></span></span></code></pre></div><h2 id="表只出現一次時別名的作用">表只出現一次時別名的作用</h2>
<p>同一張表只出現一次的時候，別名的作用是縮短欄位引用。長表名在有三四張表的查詢裡會讓每個欄位引用都變得很長，取一個短別名之後可讀性差很多。</p>
<p>而作用不只是省字。取了別名之後原本的表名在這個查詢裡就不再是它的稱呼，三個引擎都會擋下來：PostgreSQL 回 <code>invalid reference to FROM-clause entry for table &quot;訂單&quot;</code> 並附上一句提示要改用別名，SQLite 回 <code>no such column</code>，DuckDB 回 <code>Referenced table &quot;訂單&quot; not found</code>。<code>FROM 訂單 AS 早</code> 宣告的是「這次出現叫早」，而宣告過後就只有這一個稱呼。</p>
<h2 id="別名的取名標示這次出現扮演的角色">別名的取名：標示這次出現扮演的角色</h2>
<p>自連接的兩次出現在問題裡扮演不同角色，而別名是查詢裡唯一標示角色的地方。同一位顧客的訂單先後配對：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">SELECT</span><span class="w"> </span><span class="err">早</span><span class="p">.</span><span class="err">訂單編號</span><span class="p">,</span><span class="w"> </span><span class="err">晚</span><span class="p">.</span><span class="err">訂單編號</span><span class="p">,</span><span class="w"> </span><span class="err">晚</span><span class="p">.</span><span class="err">金額</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="err">早</span><span class="p">.</span><span class="err">金額</span><span class="w">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="w"></span><span class="k">FROM</span><span class="w"> </span><span class="err">訂單</span><span class="w"> </span><span class="err">早</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="err">訂單</span><span class="w"> </span><span class="err">晚</span><span class="w">
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="w">  </span><span class="k">ON</span><span class="w"> </span><span class="err">晚</span><span class="p">.</span><span class="err">顧客編號</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="err">早</span><span class="p">.</span><span class="err">顧客編號</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="err">晚</span><span class="p">.</span><span class="err">下單日</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="err">早</span><span class="p">.</span><span class="err">下單日</span><span class="p">;</span></span></span></code></pre></div><p>把兩個別名換成 <code>a</code> 與 <code>b</code>，查詢的行為一模一樣，而 <code>b.金額 - a.金額</code> 這一行要回頭看 <code>ON</code> 才知道哪一個是後來那張單。判斷標準落在這裡：<strong>讀到用它的那一行時，方向自己說得出來。</strong> 名字取得對的時候，<code>晚.金額 - 早.金額</code> 讀起來就是它的意思。</p>
<p>引擎對這個名字沒有意見。把兩個別名對調，條件也跟著對調：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sql" data-lang="sql"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">FROM</span><span class="w"> </span><span class="err">訂單</span><span class="w"> </span><span class="err">晚</span><span class="w"> </span><span class="k">JOIN</span><span class="w"> </span><span class="err">訂單</span><span class="w"> </span><span class="err">早</span><span class="w">
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="w">  </span><span class="k">ON</span><span class="w"> </span><span class="err">早</span><span class="p">.</span><span class="err">顧客編號</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="err">晚</span><span class="p">.</span><span class="err">顧客編號</span><span class="w"> </span><span class="k">AND</span><span class="w"> </span><span class="err">早</span><span class="p">.</span><span class="err">下單日</span><span class="w"> </span><span class="o">&gt;</span><span class="w"> </span><span class="err">晚</span><span class="p">.</span><span class="err">下單日</span></span></span></code></pre></div><p>叫「早」的那一次出現拿到的是後來那張單。查詢照跑，結果與上面那一段相同，而每一個名字都指反了。別名因此也是一種<a href="/blog/backend/01-database/sql/declared-intent-vs-behaviour/" data-link-title="SQL.20 關鍵字的宣告與引擎的行為：宣告落空的形態與查證" data-link-desc="LEFT JOIN、CROSS JOIN、DISTINCT、COALESCE 與表的別名各自對讀的人宣告了什麼、宣告落空時下一個修改的人付出什麼代價，以及把關鍵字換成最弱的版本再跑一次的查證動作">宣告</a>——它說明這次出現代表什麼，兌現與否由寫的人負責。</p>
<h2 id="表的別名與欄位別名各自可用的時機">表的別名與欄位別名各自可用的時機</h2>
<p><code>SELECT</code> 裡的 <code>AS</code> 替算出來的欄位取名，<code>FROM</code> 裡的 <code>AS</code> 替表的一次出現取名。兩者的作用範圍不同，可用的時機也不同。</p>
<p>表的別名在 <code>FROM</code> 那一步就成立，所以 <code>WHERE</code>、<code>GROUP BY</code>、<code>ON</code> 全部用得到它。欄位別名到 <code>SELECT</code> 那一步才誕生，所以 <code>WHERE</code> 照語意模型用不到。兩個 <code>AS</code> 長得一樣而落在求值順序的兩端。</p>
<p>某些引擎讓 <code>WHERE</code> 用得到欄位別名，那是引擎的放寬，不是模型的規定。<a href="/blog/backend/01-database/sql/clause-evaluation-order/" data-link-title="SQL.2 子句的求值順序：每一步可用的欄位、語意模型擋下的寫法與各家引擎放寬的寫法" data-link-desc="從 FROM 到 LIMIT 每一步可用的欄位與值、聚合放進 WHERE、別名用在 WHERE 與列的條件放進 HAVING 在各家引擎上的結果，以及這幾種寫法換引擎時的表現">SQL.2 子句的求值順序</a> 走過每一步能用到哪些欄位與值，並把模型層擋得住的限制與各家引擎自己放寬的分開——表的別名不在它的範圍裡，因為別名在 <code>FROM</code> 那一步就成立了。</p>
]]></content:encoded></item></channel></rss>