ClickHouse 2021年1～2月新機能

# ClickHouse 2021年1～2月新機能

Release notes からピックアップして新機能を紹介します。

リリースノート全体はこちらで見れます。
https://github.com/ClickHouse/ClickHouse/blob/master/CHANGELOG.md

## v21.1.2.15-stable 2021-01-18 で追加

### REPLACE TABLE / CREATE OR REPLACE TABLE

REPLACE TABLE / CREATE OR REPLACE TABLE 文で、atomicにテーブルを入れ替えられるようになりました。

今までは

```sql
CREATE TABLE myNewTable AS myOldTable;
INSERT INTO myNewTable SELECT * FROM myOldTable WHERE CounterID <12345;
DROP TABLE myOldTable;
RENAME TABLE myNewTable TO myOldTable;
```

でしたが、以下のように書けるようになりました。

```sql
REPLACE TABLE myOldTable SELECT * FROM myOldTable WHERE CounterID <12345;
```

ただし、データベースの種別がAtomicでないと使えません。

最近のバージョンで新規に作成したデータベースは、デフォルトでAtomicになりますが、以前のバージョンで作ったものは Ordinary かもしれません。
以下のSQLで確認できます。

```sql
SELECT * FROM system.databases
```

Ordinary から Atomic に簡単に変換する方法は用意されていないようなので、移行したい場合は新しくデータベースを作り、テーブルを移す必要がありそうです。

### accurateCastOrNull関数

ClickHouseでは、性能のために、デフォルトでCASTしたときにオーバーフロー等が考慮されません。
範囲内か判定したい場合にこの新しい関数が使えます。

```sql
SELECT accurateCastOrNull(-1, 'UInt8')

┌─accurateCastOrNull(-1, 'UInt8')─┐
│                            ᴺᵁᴸᴸ │
└─────────────────────────────────┘

SELECT cast(-1, 'UInt8')

┌─cast(-1, 'UInt8')─┐
│               255 │
└───────────────────┘
```

### toModifiedJulianDay / fromModifiedJulianDay / toModifiedJulianDayOrNull / fromModifiedJulianDayOrNull関数

ClickHouseの日付は、1970年以降の範囲しか扱えません。
この関数で文字列での日付と Modified Julian Day number を相互変換することができるので、0000～9999年の範囲で日数計算ができるようになります。

```sql
SELECT fromModifiedJulianDay(toModifiedJulianDay('1950-01-01') + 20000)

┌─fromModifiedJulianDay(plus(toModifiedJulianDay('1950-01-01'), 20000))─┐
│ 2004-10-04                                                            │
└───────────────────────────────────────────────────────────────────────┘
```

こちらは当社開発者からプルリクエストした関数になります。

### clickhouse-client の queries-file オプション

SQLを記入したファイルを指定して実行できるようになりました。


### Map型

新しくMap型が追加されました。
まだexperimental扱いなので、設定を変えないと利用できません。

動的に変わる項目を管理する場合に便利に使えると思います。

https://clickhouse.tech/docs/en/sql-reference/data-types/map/

```sql
SET allow_experimental_map_type = 1

Ok.

CREATE TABLE table_map
(
    `user` Map(String, String)
)
ENGINE = MergeTree
ORDER BY tuple()

Ok.

INSERT INTO table_map
VALUES ({'name': 'mikage'}), ({'name': 'tomomi', 'email':'tomomi@example.com'});

Ok.

SELECT * FROM table_map

┌─user───────────────────────────────────────────┐
│ {'name':'mikage'}                              │
│ {'name':'tomomi','email':'tomomi@example.com'} │
└────────────────────────────────────────────────┘

SELECT
    user['name'],
    user['email']
FROM table_map

┌─arrayElement(user, 'name')─┬─arrayElement(user, 'email')─┐
│ mikage                     │                             │
│ tomomi                     │ tomomi@example.com          │
└────────────────────────────┴─────────────────────────────┘
```

## v21.2.2.8-stable 2021-02-07 で追加

### PostgreSQLとの連携

mysqlには直接接続できますが、同じようにpostgresqlにも接続できるようになりました。

使い方はMySQLと同様です。
（記事作成時点では、まだドキュメントには書かれてないようです・・・）

```sql
SELECT * ROM mysql('host:port', 'database', 'table', 'user', 'password'[, replace_query, 'on_duplicate_clause']);

SELECT * FROM postgresql('host:port', 'database', 'table', 'user', 'password');
```