【PostgreSQL】VIEWやPROCEDUREを一括削除するSQL

# はじめに
とあるスキーマのVIEWだけを全削除したいときに作った雑なSQLについて書き残しておこうと思います。

ワンクリックで全消しとはいきませんが、カスタマイズも簡単で事前にどの表が消えるのか確認しやすいので、意外と使えるんじゃないですかね？

# 環境
・Windows10
・PostgreSQL 16.2
・A5M2 2.20.1

# VIVEを削除するSQL
作ったSQLがコレ。
A5M2でCREATE PROCEDUREせずに実行したかったので無名ブロックの`DO$$ $$`を使用していますが、コマンドプロンプトでpsqlを使って実行する場合は消した方がよさげ？
```plsql:VIVE一括削除.sql
DO
$outer$
DECLARE
  -- 変数宣言
  sSqlText  text;
  sSchema   varchar = 'sudare';  -- 削除したい対象があるスキーマ名
  
  -- カーソルの宣言
  DELETE_VIEW_CS CURSOR FOR
  select viewname
  from pg_catalog.pg_views 
  where schemaname = sSchema;

-- 実行開始
BEGIN
    FOR DVCS IN DELETE_VIEW_CS LOOP
     -- SQL生成
     sSqlText := 'DROP VIEW ' || DVCS.viewname || ' CASCADE';
     
     -- SQL実行
     execute sSqlText;
     
     -- 明示的コミット
     COMMIT;
    END LOOP;
END;
$outer$ language plpgsql;
```

`CASCADE`で依存関係にある表を自動的に削除している影響で `view "" does not exist` というエラーで止まる可能性があります。が、明示的な`COMMIT`で止まる前の処理は反映されているので処理された分は消去されています。
何度も実行すれば、いずれVIEWが全部消えるでしょう（ゴリ押し）

:::note warn
VIVEを削除するSQLですので、事前にカーソル宣言部のSELECT文を実行するなどして消去されるVIVEを確認しておきましょう。
間違って消しちゃっても責任取れないよ～。
:::


# 説明
## カーソル宣言
カーソルを宣言しています。
ここでSELECTされる`viewname`が削除されます。カスタマイズしたい場合はWhere句をイジったりするといいです。
実行する前にこのSELECT文だけ個別に実行することで消去される表を事前に確認できます。ここがお気に入りポイントですね。

ちなみに、参照している`pg_views`はシステムカタログといって内部的な情報を格納している場所です。
詳しく知らない方は `select * from pg_catalog.pg_views` で一度見てみるといいでしょう。

```plsql:カーソル宣言
-- カーソルの宣言
[カーソル名] CURSOR FOR
 select viewname
 from pg_catalog.pg_views 
 where schemaname = [スキーマ名;]
 [その他条件];
```

https://www.postgresql.jp/docs/9.4/catalogs.html

## 実行部分
カーソル結果に対してLOOPすることで 【SQL文を生成→DROP実行→コミット】 を繰り返し、VIEWを削除しています。
`CASCADE`で依存関係にある表を自動削除しているため、『表が見つかりません!（CASCADEで先に削除した為）』というエラーが出る可能性があります。ですが、明示的COMMITのお陰でロールバックせず実行された処理は反映されています。

もっとスマートにSQLを書けたらエラーに掛からずに済むのかもしれませんが…。
```plsql:DROP VIEW実行
-- 実行開始
BEGIN
    FOR [レコード型変数名] IN [カーソル名] LOOP
     -- SQL生成
     sSqlText := 'DROP VIEW ' || [レコード型変数名].viewname || ' CASCADE';
     
     -- SQL実行
     execute sSqlText;
     
     -- 明示的コミット
     COMMIT;
    END LOOP;
END;
```
`FOR RECORD型変数名 IN カーソル名 LOOP 処理内容 END LOOP;`の形にすることでカーソルを自動で開いて自動で閉じることができます。

https://qiita.com/ebichan_88/items/1effb09fbc458276ea51#%E3%82%AB%E3%83%BC%E3%82%BD%E3%83%AB%E7%B5%90%E6%9E%9C%E3%81%AB%E5%AF%BE%E3%81%99%E3%82%8B%E3%83%AB%E3%83%BC%E3%83%97%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6

# その他応用（TABLE・PROCEDURE・FUNCTION）
テーブルもこんな感じやればできると思います。`CASCADE`で依存関係にあるVIEWも消えるので注意してね。
```plsql:TABLE版
DO
$outer$
DECLARE
  sSqlText  text;
  sSchema   varchar = 'sudare'; 
  
  -- カーソル宣言
  DELETE_TABLE_CS CURSOR FOR
  select tablename
  from pg_catalog.pg_tables 
  where schemaname = sSchema;
  
 BEGIN
    FOR DTCS IN DELETE_TABLE_CS LOOP
    
     sSqlText := 'DROP TABLE ' || DTCS.tablename || ' CASCADE';
     execute sSqlText;
     COMMIT;
    END LOOP;
 END;
$outer$ language plpgsql;
```


プロシージャとファンクション版はこんな感じ？実際に動かしてないから上手くいくかは知らないです。

実行は自己責任でオナシャス。
```plsql:PROCEDURE版
DO
$outer$
DECLARE
  sSqlText  text;
　sSchema   varchar = 'sudare'; 

  
  -- カーソル宣言
  DELETE_PRO_CS CURSOR FOR
  select proname
  from pg_catalog.pg_proc 
  where pronamespace = (select oid from pg_catalog.pg_namespace where nspname = sSchema)
    and prokind      = 'p';       -- pはPROCEDURE fはFUNCTION
  
 BEGIN
    FOR DPCS IN DELETE_PRO_CS LOOP
    
     sSqlText := 'DROP PROCEDURE ' || DPCS.proname || ' CASCADE';
     execute sSqlText;
     COMMIT;
    END LOOP;
 END;
$outer$ language plpgsql;
```

```plsql:FUNCTION版
DO
$outer$
DECLARE
  sSqlText  text;
  sSchema   varchar = 'sudare'; 

  
  -- カーソル宣言
  DELETE_FUN_CS CURSOR FOR
  select proname
  from pg_catalog.pg_proc 
  where pronamespace = (select oid from pg_catalog.pg_namespace where nspname = sSchema)
    and prokind      = 'f';       -- pはPROCEDURE fはFUNCTION
  
 BEGIN
    FOR DFCS IN DELETE_FUN_CS LOOP
    
     sSqlText := 'DROP FUNCTION ' || DFCS.proname || ' CASCADE';
     execute sSqlText;
     COMMIT;
    END LOOP;
 END;
$outer$ language plpgsql;
```