【PostgreSQL】変数への値の代入を禁止する「CONSTANT」と、変数へ値を代入する「:=」を併記できるのはなぜ？

OSS-DB Silver 取得に向けて勉強中です。

『OSS教科書 OSS-DB Silver ver.2.0対応(翔泳社)』（緑本）と
『徹底攻略OSS-DB Silver 問題集 ver2.0対応(インプレス)』（黒本）
に取り組んでいます。

CONSTANTの使い方について疑問を持ったので、
記事にしながら疑問解消しようと思います。

# 先に結論

Ｑ：変数への値の代入を禁止する「CONSTANT」と、変数へ値を代入する「:=」を併記できるのはなぜ？

Ａ：
「CONSTANT」の役割は「初期値以外の代入を禁止する」ことだから。
単に値の代入を禁止しているのではない。「初期値」を定め、そこからの変更を認めていない、ということ。
  

# 疑問

黒本10章問32(p226)中のSQLの意味を調べるために引いた緑本p243に、下記のようにありました。
>CONSTANTを付与すると、その変数への値の代入は禁止されます。
変数へ値を代入する際には「:=」という書式を使います。
（引用元：緑本　8章SQLとオブジェクト　8-12関数とプロシージャ　p243）

問32にはCONSTANTは登場しませんが、気になるので調べてみます。

↓
この時点で私は

CONSTANTを付与すると、その変数への値の代入は禁止されるのだから、
CONSTANTを使ったときには、「:=」は併用できないのだろう

と思いました。しかし、ドキュメントでCONSTANTの解説＆使用例を確認すると

>CONSTANTオプションにより、そのブロック内でその値が不変になるように、その変数への初期化後の代入は禁止されます。
（中略）
例：
quantity integer DEFAULT 32;
url varchar := 'http://mysite.com';
user_id **CONSTANT integer := 10;**
（引用元：[PostgreSQL 11.5文書　第43章 PL/pgSQL - SQL手続き言語	43.3. 宣言](https://www.postgresql.jp/document/11/html/plpgsql-declarations.html#PLPGSQL-DECLARATION-PARAMETERS)）

とありました。
「CONSTANT」と「:=」が併用されています。

**疑問：変数への値の代入を禁止する「CONSTANT」と、変数へ値を代入する「:=」を併記できるのはなぜ？**

「変数の代入」自体について、私が全く理解でいていないのだろうな、という予感がしています。
とにもかくにも、調べつつ理解していこうと思います。

# 変数宣言の構文と例

変数宣言の一般的な構文↓
>name [ CONSTANT ] type [ COLLATE collation_name ] [ NOT NULL ] [ { DEFAULT | := | = } expression ];

変数宣言の例↓
>quantity integer DEFAULT 32;
url varchar := 'http://mysite.com';
user_id **CONSTANT integer := 10;**
（引用元：[PostgreSQL 11.5文書　第43章 PL/pgSQL - SQL手続き言語	43.3.宣言](https://www.postgresql.jp/document/11/html/plpgsql-declarations.html#PLPGSQL-DECLARATION-PARAMETERS)）

# 読み解く（何言語？意味は？）
**Ｑ1：この構文は何言語？**

**Ａ：PL/pgSQL**

PL/pgSQLとは・・・
PostgreSQLデータベースシステム用の読み込み可能な手続き言語。
PLはProcedural Language（手続き型言語）の略。

SQLは基本的には1行で完結するので、手続的なプログラムを書くのは難しい言語。
そのSQLに手続き的な処理を可能にさせるための言語がPL/pgSQL。
（参考：『わたしとぼくのPL/pgSQL』）
（参考：[PostgreSQL 11.5文書 第43章 PL/pgSQL - SQL手続き言語　43.3.宣言](https://www.postgresql.jp/document/11/html/plpgsql-overview.html)）

**Ｑ2：この例文、どこで使う？**
関数の構造（基本形）は以下の通り。

DECLARE
 変数の宣言
BEGIN
 関数の処理記述
END;

上記の「変数の宣言」に入るのが、例文。

**Ｑ3：この例文の意味は？**

**Ａ：以下の通り**

`quantity integer DEFAULT 32;`
変数名はquantity。
数値データ型は整数（integer)。
デフォルト値は32。

`url varchar := 'http://mysite.com';`
変数名はurl。
文字データ型は上限付き可変長（varchar)。
変数に代入する値は'http://mysite.com'。

`user_id CONSTANT integer := 10;`
変数名はuser_id。
この変数への値の代入は禁止。　**←疑問の該当箇所！**
数値データ型は整数（integer)。
変数に代入する値は10。　**←疑問の該当箇所！**

# 「代入禁止」と「代入する数値は10」が併記されるのはなぜ？
`user_id  integer := 10;`
「CONSTANT」（この変数への値の代入は禁止）
と宣言しておきながら、直後に
「:= 10」（変数に代入する値は10）
と宣言している、というのはなぜなのでしょうか？

「代入する値は「10」で、その後他の値を代入することは認めない」という意味なのでしょうか？
だとしたら、「DEFAULT」で良いはずです。DEFAULTとの違いは何なのでしょうか？

ドキュメントにこうありました。
>DEFAULT句が指定された場合、ブロックに入った時に変数に代入される初期値を指定します。 DEFAULT句が指定されない場合、変数はSQLのNULL値に初期化されます。 
CONSTANTオプションにより、そのブロック内でその値が不変になるように、その変数への初期化後の代入は禁止されます。 
（引用元：[PostgreSQL 11.5文書 第43章 PL/pgSQL - SQL手続き言語　43.3.宣言](https://www.postgresql.jp/document/11/html/plpgsql-overview.html)）

つまり

・「代入する値は「10」で、その後他の値を代入することは認めない」という意味なのでしょうか？
→Yes。最初に1回だけ値を指定して、その後は代入する値を変更できなくなる、ということ。

・だとしたら、「DEFAULT」で良いはずです。DEFAULTとの違いは何なのでしょうか？
→DEFAULTではダメ。DEFAULTは、初期値。ずっと固定される値ではなく、あくまで最初だけの値。

解決です！

# 余談　ブロックって何？
ドキュメントに出てきた「ブロック」って何を指すのでしょうか？

>PL/pgSQLはブロック構造の言語です。 関数本体のテキスト全体はブロックでなければなりません。 
ブロックは以下のように定義されます。
```:PL/pgSQL
[ <<label>> ]
[ DECLARE
    declarations ]
BEGIN
    statements
END [ label ];
```
（引用元：[PostgreSQL 11.5文書 第43章 PL/pgSQL - SQL手続き言語　43.2.PL/pgSQLの構造](https://www.postgresql.jp/document/11/html/plpgsql-structure.html)）

つまり、「関数の変数宣言～関数処理完了（END;）」までの一連のまとまりを「ブロック」と言う。

# 参考
・[『わたしとぼくのPL/pgSQL (技術の泉シリーズ（NextPublishing）) Kindle版』目黒 聖](https://www.amazon.co.jp/gp/product/B07NQGNFDP/ref=dbs_a_def_rwt_hsch_vapi_tkin_p1_i2)