{#alter-label-alter-vlabel-and-alter-elabel}
# ALTER VLABEL과 ALTER ELABEL
레이블의 이름을 바꾸고, 저장 방식을 바꾸고, 부모를 붙이거나 떼고, 인덱스를 끄고, 승격된 타입
컬럼을 추가하거나 제거합니다.
{#alter-label-synopsis}
## 개요
ALTER VLABEL[IF EXISTS]label_nameaction[, ...] ALTER VLABEL[IF EXISTS]label_nameRENAME TOnew_label_name
ALTER ELABEL[IF EXISTS]label_nameaction[, ...] ALTER ELABEL[IF EXISTS]label_nameRENAME TOnew_label_name
where action is one of:
ADD[COLUMN]promoted_property DROP[COLUMN]column_name[CASCADE|RESTRICT] DISABLE INDEX SET STORAGE{PLAIN|EXTERNAL|EXTENDED|MAIN} SET TABLESPACEtablespace_name SET{LOGGED|UNLOGGED} CLUSTER ONindex_name SET WITHOUT CLUSTER INHERITparent_label NO INHERITparent_label REPLICA IDENTITY{DEFAULT|USING INDEXindex_name|FULL|NOTHING} OWNER TOrole_specification
굵게 키워드 · 기울임 직접 채우는 자리 · [ ] 생략 가능 · ... 반복 가능. 구문 표기 규약을 참고하십시오.
{#alter-label-description}
## 설명
`ALTER VLABEL`은 정점 레이블에, `ALTER ELABEL`은 간선 레이블에 작용합니다. 키워드를 빼면 두 문장은
같습니다. **위에 나열한 모든 동작이 두 종류 모두에서 받아들여집니다.** 다른 것은 그 동작이 작용할
대상을 각 레이블 종류가 무엇으로 갖고 있는가입니다.
- 레이블이 만들어질 때 함께 생기는 인덱스가 다릅니다. 정점 레이블에는 `id`에 대한 기본 키가 생기고,
간선 레이블에는 `(start, "end")`와 `("end", start)`에 걸린 btree 인덱스와 `id`에 걸린 BRIN
인덱스가 생깁니다. `DISABLE INDEX`는 어느 쪽이든 그 레이블의 모든 인덱스를 무효로 만들므로, 갓
만든 정점 레이블에서는 무효로 만들 것이 하나이고 간선 레이블에서는 셋입니다. `CLUSTER ON`도
고를 수 있는 이름이 다릅니다.
- `DROP COLUMN`이 거부하는 구조 컬럼은 정점 레이블에서 `id`와 `properties`이고, 간선 레이블에는
`start`와 `end`가 더해집니다.
- `INHERIT`와 `NO INHERIT`는 그 레이블과 같은 종류이고 같은 그래프에 있는 부모를 요구합니다.
레이블은 `graph_path`가 지정한 그래프에서 찾습니다. 그 이름은 수식할 수 없습니다.
- `RENAME TO`는 그 자체로 하나의 형태입니다. 다른 어떤 동작과도 함께 쓸 수 없고, 여러 동작을 나열한
목록에 들어갈 수도 없습니다.
- 한 문장의 여러 동작은 쉼표로 구분하며 적은 순서대로 적용됩니다.
- 기반 레이블인 `ag_vertex`와 `ag_edge`는 아예 변경할 수 없습니다.
- `ALTER VLABEL`은 간선 레이블을 거부하고 `ALTER ELABEL`은 정점 레이블을 거부합니다.
대신 `ALTER TABLE`로 레이블의 모양을 바꾸는 것은 `enable_graph_ddl`을 켜 두지 않으면 거부됩니다.
그래프 카탈로그가 레이블의 컬럼을 설명하는데, `ALTER TABLE`은 그것을 갱신하지 않습니다. 그 관문에
대해서는 [그래프가 어떻게 저장되는가](#graph-on-postgresql-what-is-deliberately-closed-off)가
다룹니다.
{#alter-label-parameters}
## 매개변수
IF EXISTS
: 그 레이블이 없을 때 오류가 아니라 알림을 냅니다.
label_name
: 변경할 레이블이며, `graph_path`가 지정한 그래프 안에서 찾습니다.
RENAME TO new_label_name
: 레이블에 새 이름을 줍니다. 정점과 간선은 자기 id를 유지하므로, 이름을 바꾸기 전에 만든 행에
대해서도 `label()`이 새 이름을 보고합니다. 그 테이블의 시퀀스와 인덱스는 처음 받은 이름을
유지하므로, `CLUSTER ON`을 쓰기 전에 그것을 확인하십시오.
ADD [ COLUMN ] promoted_property
: 승격된 타입 컬럼을 추가하고 이미 있는 행에서 그것을 채웁니다. `promoted_property`는
[`CREATE VLABEL`](#create-vlabel-promoted-properties)과 같은 세 형태를 받고 제한도 같습니다. 그
레이블에서 이미 승격된 속성은 거부되며, 한 문장에서 같은 키를 두 번 승격하는 것도 거부됩니다.
DROP [ COLUMN ] column_name [ CASCADE | RESTRICT ]
: 컬럼을 지우고, 승격된 속성이라면 그 대응 관계도 잊습니다. 레이블의 구조 컬럼은 거부됩니다. 지운
컬럼에 걸려 있던 인덱스도 함께 사라집니다.
DISABLE INDEX
: 그 레이블의 모든 인덱스를 무효로 표시해, 대량 적재가 그것을 유지하지 않게 합니다. 읽기와 쓰기는
계속 동작하고 플래너는 무효 인덱스를 무시합니다. `ENABLE INDEX`는 없습니다. 되돌아가는 길은
[`REINDEX VLABEL`](reindex.md)입니다.
SET STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN }
: 레이블의 `properties` 컬럼의 저장 방식을 정합니다. 이 방식이 큰 속성 맵을 인라인으로 둘지 그
테이블의 TOAST 관계에 둘지, 그리고 압축할지를 결정합니다. 레이블은 `EXTENDED`로 시작하며, 그것은
인라인이 아니면서 압축하는 방식입니다. 이 문장은 이후 쓰기에 대한 전략을 바꿀 뿐, 이미 저장된
것을 다시 쓰지는 않습니다.
SET TABLESPACE tablespace_name
: 레이블의 테이블을 다른 테이블스페이스로 옮깁니다. 그 인덱스는 있던 자리에 남습니다.
SET { LOGGED | UNLOGGED }
: 레이블 테이블의 미리 쓰기 로깅을 켜거나 끕니다. 그 레이블의 id 시퀀스도 함께 영속성이
바뀝니다.
CLUSTER ON index_name
: 나중의 `CLUSTER`가 쓸 인덱스로 어떤 인덱스를 기록해 둡니다. 지금 무언가를 재배열하지는
않습니다.
SET WITHOUT CLUSTER
: 그 기록을 잊습니다.
INHERIT parent_label
: 그 레이블을 같은 그래프의 같은 종류 레이블의 자식으로 붙여, 부모에 대한 패턴이 이 레이블의 행에도
일치하기 시작하게 합니다.
NO INHERIT parent_label
: 그 관계를 제거합니다.
REPLICA IDENTITY { DEFAULT | USING INDEX index_name | FULL | NOTHING }
: 논리 복제를 위해, 쓰기가 행을 식별하려고 WAL에 기록하는 이전 값을 무엇으로 할지 고릅니다.
OWNER TO role_specification
: 그 레이블을 다른 롤에게 넘깁니다. 롤 이름, `CURRENT_ROLE`, `CURRENT_USER`, `SESSION_USER` 중
하나를 씁니다.
{#alter-label-examples}
## 예제
예제는 [예제 데이터셋](../../get_started/example-dataset.md)을 쓰지 않고 자체 그래프인
`catalogue`를 만들고, 끝에서 그것을 지웁니다.
```cypher
CREATE GRAPH catalogue;
SET graph_path = catalogue;
CREATE VLABEL film;
CREATE (:film {title: 'Arrival', year: 2016}), (:film {title: 'Dune', year: 2021});
```
{#alter-label-rename-a-label}
### 레이블 이름 바꾸기
```cypher
ALTER VLABEL film RENAME TO movie;
```
```psql
\dGl catalogue.mov*
```
```
List of labels
Graph | Name | Type | Owner
-----------+-------+--------+-------
catalogue | movie | vertex | agens
(1 row)
```
행도 함께 따라왔습니다:
```cypher
MATCH (m:movie) RETURN count(m) AS movies;
```
```
movies
--------
2
(1 row)
```
시퀀스와 기본 키는 여전히 옛 이름을 지니고 있습니다:
```psql
\d catalogue.movie
```
```
Table "catalogue.movie"
Column | Type | Collation | Nullable | Default
------------+---------+-----------+----------+----------------------------------------------------------------------------------------------
id | graphid | | not null | graphid(graph_labid('catalogue.movie'::cstring), nextval('catalogue.film_id_seq'::regclass))
properties | jsonb | | not null | jsonb_build_object()
Indexes:
"film_pkey" PRIMARY KEY, btree (id)
Inherits: catalogue.ag_vertex
```
그래서 `ALTER VLABEL movie CLUSTER ON movie_pkey`는
`index "movie_pkey" for table "movie" does not exist`로 실패하고, 써야 할 이름은 `film_pkey`입니다.
{#alter-label-turn-a-labels-indexes-off-for-a-bulk-load}
### 대량 적재를 위해 레이블의 인덱스 끄기
```cypher
ALTER VLABEL movie DISABLE INDEX;
```
```psql
\d catalogue.movie
```
```
Table "catalogue.movie"
Column | Type | Collation | Nullable | Default
------------+---------+-----------+----------+----------------------------------------------------------------------------------------------
id | graphid | | not null | graphid(graph_labid('catalogue.movie'::cstring), nextval('catalogue.film_id_seq'::regclass))
properties | jsonb | | not null | jsonb_build_object()
Indexes:
"film_pkey" PRIMARY KEY, btree (id) INVALID
Inherits: catalogue.ag_vertex
```
행을 적재하고, 그다음 인덱스를 다시 만듭니다:
```cypher
REINDEX VLABEL movie;
```
```
REINDEX
```
{#alter-label-promote-a-property-on-a-label-that-already-holds-rows}
### 행이 이미 있는 레이블에서 속성 승격하기
```cypher
ALTER VLABEL movie ADD COLUMN year int GENERATED;
```
```psql
\d catalogue.movie
```
```
Table "catalogue.movie"
Column | Type | Collation | Nullable | Default
------------+---------+-----------+----------+-----------------------------------------------------------------------------------------------
id | graphid | | not null | graphid(graph_labid('catalogue.movie'::cstring), nextval('catalogue.film_id_seq'::regclass))
properties | jsonb | | not null | jsonb_build_object()
year | integer | | | generated always as (ag_property_text(properties, 'year'::text, 'n'::"char")::integer) stored
Indexes:
"film_pkey" PRIMARY KEY, btree (id)
Inherits: catalogue.ag_vertex
```
이미 있는 행이 채워지므로, 그 문장이 돌아오는 순간 컬럼은 이미 완전합니다:
```sql
SELECT year FROM catalogue.movie ORDER BY year;
```
```
year
------
2016
2021
(2 rows)
```
{#alter-label-look-up-what-a-label-promotes}
### 레이블이 무엇을 승격했는지 조회하기
`ag_label_property`가 속성 키를 그것을 대신해 답하는 컬럼에 대응시킵니다:
```cypher
ALTER VLABEL movie ADD COLUMN released text GENERATED (releaseDate);
```
```sql
SELECT p.propname, p.attnum FROM pg_catalog.ag_label_property p
JOIN pg_catalog.ag_label l ON l.oid = p.laboid
JOIN pg_catalog.ag_graph g ON g.oid = l.graphid
WHERE g.graphname = 'catalogue' AND l.labname = 'movie' ORDER BY p.attnum;
```
```
propname | attnum
-------------+--------
year | 3
releasedate | 4
(2 rows)
```
`attnum`은 그 테이블에서 컬럼의 위치입니다. 컬럼 이름까지 원한다면 그것으로 `pg_attribute`와
조인하십시오. 키를 명시하는 형태를 썼다면 그 둘이 다릅니다.
{#alter-label-drop-a-promoted-column}
### 승격된 컬럼 지우기
```cypher
ALTER VLABEL movie DROP COLUMN released;
```
그 대응 관계도 컬럼과 함께 사라집니다:
```sql
SELECT p.propname, p.attnum FROM pg_catalog.ag_label_property p
JOIN pg_catalog.ag_label l ON l.oid = p.laboid
JOIN pg_catalog.ag_graph g ON g.oid = l.graphid
WHERE g.graphname = 'catalogue' AND l.labname = 'movie' ORDER BY p.attnum;
```
```
propname | attnum
----------+--------
year | 3
(1 row)
```
`releasedate`를 읽으면 `properties`로 돌아갑니다. `properties`에서 지워진 것은 없습니다.
{#alter-label-change-how-the-property-map-is-stored}
### 속성 맵의 저장 방식 바꾸기
```cypher
ALTER VLABEL movie SET STORAGE external;
```
어느 컬럼을 예상했든, 그 방식은 `properties`에 설정됩니다:
```sql
SELECT attname, attstorage FROM pg_attribute
WHERE attrelid = 'catalogue.movie'::regclass AND attnum > 0 AND NOT attisdropped;
```
```
attname | attstorage
------------+------------
id | p
properties | e
year | p
(3 rows)
```
{#alter-label-attach-and-detach-a-parent}
### 부모 붙이고 떼기
```cypher
CREATE VLABEL work;
ALTER VLABEL movie INHERIT work;
```
```psql
\dGv catalogue.movie
```
```
List of labels
Graph | Name | Type | Owner
-----------+-------+--------+-------
catalogue | movie | vertex | agens
(1 row)
Vertex label "catalogue.movie"
--
Inherits: catalogue.ag_vertex,
catalogue.work
```
이제 `movie`에는 부모가 둘입니다. 처음부터 있던 기반 레이블과 `work`입니다. 떼어 내도 기반 레이블은
그대로입니다:
```cypher
ALTER VLABEL movie NO INHERIT work;
```
```
ALTER VLABEL
```
{#alter-label-refusals-worth-recognizing}
### 알아 둘 만한 거부 사례
구조 컬럼은 지울 수 없습니다:
```cypher
ALTER VLABEL movie DROP COLUMN properties;
```
```
ERROR: cannot drop column "properties" of graph label "movie"
HINT: It is a structural column of the graph label.
```
추가하는 컬럼은 `properties`에서 생성되는 것이어야 합니다:
```cypher
ALTER VLABEL movie ADD COLUMN rank int;
```
```
ERROR: a non-generated promoted column is not supported yet
HINT: Use GENERATED to mirror the property from the jsonb bag.
```
이미 승격된 속성을 두 번 승격할 수는 없습니다:
```cypher
ALTER VLABEL movie ADD COLUMN yr2 int GENERATED (year);
```
```
ERROR: property "year" is already promoted on graph label "movie"
HINT: Drop the existing promoted column first, or promote the property to a different column name.
```
기반 레이블은 부모로든 대상으로든 손댈 수 없습니다:
```cypher
ALTER VLABEL movie INHERIT ag_vertex;
```
```
ERROR: cannot ALTER inheritance with base label
```
```cypher
ALTER VLABEL ag_vertex SET STORAGE main;
```
```
ERROR: ALTER base vertex label is prohibited
```
각 문장은 한 종류의 레이블에만 작용합니다:
```cypher
CREATE ELABEL directed;
ALTER VLABEL directed RENAME TO helmed;
```
```
ERROR: RENAME VLABEL cannot RENAME edge label
```
그리고 `RENAME TO`는 홀로 섭니다:
```cypher
ALTER VLABEL movie RENAME TO film, SET STORAGE main;
```
```
ERROR: syntax error at or near ","
LINE 1: ALTER VLABEL movie RENAME TO film, SET STORAGE main;
^
```
`enable_graph_ddl`이 꺼져 있는 동안에는 SQL로 레이블의 테이블 모양을 바꾸는 것이 거부됩니다:
```sql
ALTER TABLE catalogue.movie ADD COLUMN rank int;
```
```
ERROR: cannot add a column to graph label "movie" with ALTER TABLE
HINT: Use ALTER VLABEL or ALTER ELABEL instead, which keeps the graph catalog in step.
```
마지막으로 예제가 만든 그래프를 지웁니다:
```cypher
DROP GRAPH catalogue CASCADE;
```
{#alter-label-notes}
## 참고
`SET STORAGE`는 다섯이 아니라 네 개의 키워드를 받습니다. `DEFAULT`는 예약어이고 여기서는 구문
오류입니다. 레이블이 처음 갖는 방식으로 돌아가려면 `SET STORAGE extended`로 쓰십시오. 알 수 없는
단어는 `invalid storage type "..."`으로 보고됩니다.
`IF EXISTS` 알림은 두 형태에서 다릅니다. `RENAME TO`는
`label "nosuch" does not exist, skipping`을, 동작 목록은
`graph label "nosuch" does not exist, skipping`을 냅니다. 그다음 둘 다 성공을 보고하고 아무것도 하지
않습니다.
{#alter-label-compatibility}
## 호환성
{#alter-label-isoiec-39075-gql}
### ISO/IEC 39075 (GQL)
GQL에는 레이블을 변경하는 문장이 없습니다. 변경할 레이블이 없기 때문입니다. 요소 타입은 그래프
타입에 속하고, 그래프 타입은 통째로 만들어지고 지워집니다(``, §12.6).
레이블 이름 바꾸기, 속성 승격, 인덱스 끄기에 대응하는 것이 GQL에는 없습니다. 그래프 타입은
[GQL 적합성 표](../../appendix/gql-conformance.md)에 계획으로 기록돼 있습니다.
{#alter-label-postgresql}
### PostgreSQL
여기 있는 모든 동작은 `ALTER TABLE`의 동작이고, 각각 거기서와 같은 뜻이며 두 가지만 조정됐습니다.
`SET STORAGE`는 컬럼을 지정하지 않습니다. 저장 방식을 고를 만한 컬럼은 `properties` 하나뿐이므로 그
컬럼에 적용됩니다. `DISABLE INDEX`에는 `ALTER TABLE` 대응물이 아예 없습니다. 그것은 레이블의 인덱스를
무효로 표시하는데, SQL에서는 `CREATE INDEX CONCURRENTLY`를 중단시키는 것 말고는 그렇게 만들 방법이
없습니다.
반대 방향으로는, 레이블의 테이블에 대한 `ALTER TABLE`이 그 모양을 바꾸는 동작에 대해서는
`enable_graph_ddl`을 켜 두지 않으면 거부됩니다. 컬럼을 추가하거나 지우거나 타입을 바꾸는 것이 그런
동작입니다. 위의 예제가 그 거부를 보여 줍니다. 이 페이지의 동작들은 그 설정을 결코 필요로 하지
않습니다. 그래프 카탈로그를 스스로 갱신하기 때문입니다.
{#alter-label-see-also}
## 관련 항목
- [`CREATE VLABEL`](create-vlabel.md)
- [`CREATE ELABEL`](create-elabel.md)
- [`DROP VLABEL`·`DROP ELABEL`](drop-label.md)
- [`REINDEX VLABEL`·`REINDEX ELABEL`](reindex.md)
- [속성을 컬럼으로 승격하기](../../querying/typed-columns.md)
- [레이블 상속](../../concepts/label-inheritance.md)