zipall

bash プログラム

#!/bin/bash
cat >/tmp/a.$$.sql <<-SQL

SELECT *
FROM KEN_ALL
WHERE a4 = '""';

SQL
#
cat /tmp/a.$$.sql | sqlite3 /tmp/zipdb

* (注意)なお,町域については、「小谷」を「コヤト」,「オオタニ」などいろんな読み方をすることがある.都道府県や市区町村と同じというわけにはいかない.

  • リレーショナルデータベースのテーブル ken_all の作成
  • 郵便番号テーブル ken_all

    郵便番号テーブルを定義します.テーブル名は ken_all

    【テーブル定義の方針】

    1. 半角数字は INTEGER
    2. 半角カタカナと漢字は TEXT

    【作業手順】

    1. テーブル定義

      bash プログラム

      #!/bin/bash
      
      cat >/tmp/a.$$.sql <<-SQL
      drop table ken_all; 
      SQL
      #
      cat /tmp/a.$$.sql | sqlite3 /tmp/zipdb
      
      cat >/tmp/a.$$.sql <<-SQL
      
      create table ken_all (
          jiscode             INTEGER not null CHECK ( jiscode >= 1000 AND jiscode <= 50000 ),
          zip_old             text, 
          zipcode             text, 
          ken_kana            TEXT not null,
          shichoson_kana      TEXT not null,
          choiki_kana         TEXT not null,
          ken_kanji           TEXT not null,
          shichoson_kanji     TEXT not null,
          choiki_kanji        text,
      
          num_ken_kana        INTEGER not null,
          num_shichoson_kana  INTEGER not null,
          num_choiki_kana     INTEGER not null,
          num_ken_kanji       INTEGER not null,
          num_shichoson_kanji INTEGER not null,
          num_choiki_kanji    INTEGER not null,
      
          flag10              INTEGER not null,
          flag11              INTEGER not null CHECK ( flag11 >= 0 AND flag11 <= 1 ),
          flag12              INTEGER not null CHECK ( flag12 >= 0 AND flag12 <= 3 ),
          flag13              INTEGER not null CHECK ( flag13 >= 0 AND flag13 <= 1 ),
          info14              integer, 
          info15              integer, 
      
          org_choiki_kana     text,
          org_choiki_kanji    text,
          comment_kanji       text,
          comment_kana        text,
          kaisyamei_kana      text,
          kaisyamei_kanji     TEXT );
      
      SQL
      #
      cat /tmp/a.$$.sql | sqlite3 /tmp/zipdb
      
    2. 郵便番号テーブル ken_all の作成
      #!/bin/bash
      
      cat >/tmp/a.$$.sql <<-SQL
      drop table hoge2; 
      SQL
      #
      cat /tmp/a.$$.sql | sqlite3 /tmp/zipdb
      
      cat >/tmp/a.$$.sql <<-SQL
      
      create table hoge2 AS
      SELECT * FROM KEN_ALL
      UNION ALL
      SELECT * FROM JIGYOSYO;
      
      insert into ken_all SELECT * FROM hoge2;
      
      SQL
      #
      cat /tmp/a.$$.sql | sqlite3 /tmp/zipdb
      
    3. 郵便番号テーブル ken_all の中身の確認
      #!/bin/bash
      
      cat >/tmp/a.$$.sql <<-SQL
      
      select * from ken_all limit 3;
      
      SQL
      #
      cat /tmp/a.$$.sql | sqlite3 /tmp/zipdb
      
    4. (オプション) ダンプ操作
      #!/bin/bash
      
      cat >/tmp/a.$$.sql <<-SQL
      
      .output /tmp/ken_all.sql
      .dump ken_all
      .exit
      SQL
      #
      cat /tmp/a.$$.sql | sqlite3 /tmp/zipdb
      

      (参考) 郵便番号テーブル ken_all の各列の説明

      jiscode    全国地方公共団体コード(JIS X0401、X0402)……… 半角数字
      zip_old    (旧)郵便番号(5桁)……………………………………… 半角数字
      zipcode    郵便番号(7桁)……………………………………… 半角数字
      ken_kana    都道府県名カタカナ ………… 半角カタカナ(コード順に掲載) (注1)
      shichoson_kana    市区町村名カタカナ ………… 半角カタカナ(コード順に掲載) (注1)
      choiki_kana    町域名カタカナ ……………… 半角カタカナ(五十音順に掲載) (注1)
                     ※「郵便番号CSVデータ作成プログラム」による自動編集のもの
      ken_kanji    都道府県名漢字 ………… 漢字(コード順に掲載) (注1,2)
      shichoson_kanji    市区町村名漢字 ………… 漢字(コード順に掲載) (注1,2)
      choiki_kanji    町域名漢字 ……………… 漢字(五十音順に掲載) (注1,2)
                     ※「郵便番号CSVデータ作成プログラム」による自動編集のもの
      num_ken_kana    都道府県名カタカナ文字数
                     ※「郵便番号CSVデータ作成プログラム」により追加された属性
      num_shichoson_kana    市区町村名カタカナ文字数
                     ※「郵便番号CSVデータ作成プログラム」により追加された属性
      num_choiki_kana    町域名カタカナ文字数
                     ※「郵便番号CSVデータ作成プログラム」により追加された属性
      num_ken_kanji    都道府県名漢字文字数
                     ※「郵便番号CSVデータ作成プログラム」により追加された属性
      num_shichoson_kanji    市区町村名漢字文字数
                     ※「郵便番号CSVデータ作成プログラム」により追加された属性
      num_choiki_kanji    町域名漢字文字数
                     ※「郵便番号CSVデータ作成プログラム」により追加された属性
      flag10    一町域が二以上の郵便番号で表される場合の表示 (「1」は該当、「0」は該当せず)
                     ※ 事業所の個別郵便番号では「北海道」のような文字列が入る
      flag11    小字毎に番地が起番されている町域の表示  (「1」は該当、「0」は該当せず)
      flag12    丁目を有する町域の場合の表示 (「1」は該当、「0」は該当せず)
      flag13    一つの郵便番号で二以上の町域を表す場合の表示 (「1」は該当、「0」は該当せず)
      info14    更新の表示 (「0」は変更なし、「1」は変更あり、「2」廃止(廃止データのみ使用))
                     ※ 事業所の個別郵便番号では空値(NULL)になることがある.
      info15    変更理由 (「0」は変更なし、「1」市政・区政・町政・分区・政令指定都市施行、「2」住居表示の実施、「3」区画整理、「4」郵便区調整、集配局新設、「5」訂正、「6」廃止(廃止データのみ使用))  
                     ※ 事業所の個別郵便番号では空値(NULL)になることがある.
      org_choiki_kana      org町域名カタカナ
                     ※「郵便番号CSVデータ作成プログラム」による自動編集のもの
      org_choiki_kanji      org町域名漢字
                     ※「郵便番号CSVデータ作成プログラム」による自動編集のもの
      comment_kanji      コメント漢字
      comment_kana      コメントカタカナ
      kaisyamei_kana      会社名カタカナ
      kaisyamei_kanji      会社名漢字
      

      日本郵政「ゆうびんホームページ」で公開されている郵便番号データについて, もし

      という場合には,下記のテーブル定義を使ってください.そのこと以外は,ほぼ、この Web ページの手順が使える.

      create table zips (
          jiscode INTEGER not null,
          zip_old INTEGER not null,
          zipcode INTEGER not null,
          ken_kana TEXT not null,
          shichoson_kana TEXT not null,
          choiki_kana TEXT not null,
          ken_kanji TEXT not null,
          shichoson_kanji TEXT not null,
          choiki_kanji TEXT not null,
      
          flag10 TEXT not null,
          flag11 INTEGER not null,
          flag12 INTEGER not null,
          flag13 INTEGER not null,
          info14 integer,
          info15 INTEGER );
      

    ◆ 次のSQL プログラムを実行し,この問題を解消します

    begin transaction;
    UPDATE JIGYOSYO SET a7='札幌市南区'       WHERE a0=1106;
    UPDATE JIGYOSYO SET a7='名古屋市東区'     WHERE a0=23102;
    UPDATE JIGYOSYO SET a7='名古屋市中区'     WHERE a0=23106;
    UPDATE JIGYOSYO SET a7='名古屋市名東区'   WHERE a0=23115;
    UPDATE JIGYOSYO SET a7='蒲生郡竜王町'     WHERE a0=25384;
    UPDATE JIGYOSYO SET a7='京都市上京区'     WHERE a0=26102;
    UPDATE JIGYOSYO SET a7='福岡市博多区'     WHERE a0=40132;
    UPDATE JIGYOSYO SET a7='福岡市中央区'     WHERE a0=40133;
    commit;
    

    次のを実行して確認します.

    create table T2 AS select distinct a0, a6, a7 FROM JIGYOSYO;
    SELECT * FROM T2 WHERE a0 IN ( SELECT a0 FROM T2 group by a0 HAVING COUNT(*) > 1 );
    

    2. jiscode の一意性について

    次に、「KEN_ALL テーブルと JIGYOSO テーブルの UNION ALL をとって,新しいテーブルを作ると, また,同じ a0 の値に対して,2つの違う a7 の値が出ている」 という問題がないことを確認します

    create table hoge AS
    SELECT * FROM KEN_ALL
    UNION ALL
    SELECT * FROM JIGYOSYO;
    
    create table V AS select distinct a0, a6, a7 FROM hoge;
    SELECT * FROM V WHERE a0 IN ( SELECT a0 FROM V group by a0 HAVING COUNT(*) > 1 );
    

    *もし問題が見つかった場合には、次のようなSQLで解決(このまま使ってはいけません。あくまでも見本)

    begin transaction;
    UPDATE JIGYOSYO SET a7='鳩ヶ谷市' WHERE a0=11226;
    UPDATE JIGYOSYO SET a7='羽咋郡宝逹志水町' WHERE a0=17386;
    UPDATE KEN_ALL   SET a7='鳩ヶ谷市' WHERE a0=11226;
    UPDATE KEN_ALL   SET a7='羽咋郡宝逹志水町' WHERE a0=17386;
    commit;
    

    3. テーブル JIGYOSYO の「都道府県名カタカタ」,「市区町村名カタカナ」の空文字列

    説明

    生成されたテーブル JIGYOSYO で, 「都道府県名カタカタ」,「市区町村名カタカナ」が「""」になっているレコードを確認します.

    下の実行例では、「そのようなレコードが存在しない」と分かり、問題ありません.

    SELECT * FROM JIGYOSYO WHERE a3 = '""';
    

    「都道府県名カタカタ」,「市区町村名カタカナ」が「""」になっているレコードが存在する場合の対処法を下に説明する. 出来上がったテーブル JIGYOSYO に加工を行う必要がある

    JIGYOSYO テーブルで, 「都道府県名カタカタ」,「市区町村名カタカナ」が「""」になっているレコードは,他のレコードを使って転記を行うことができる.

    下記の例で分かる通り,「都道府県名漢字」,「市区町村名漢字」の値が同じ値になっているような別のレコードに, 「都道府県名カタカタ」,「市区町村名カタカナ」が書いてあります.

    * a3 ・・・ 都道府県名カタカナ, a4 ・・・ 市区町村名カタカナ, a6 ・・・ 都道府県名漢字, a7 ・・・ 市区町村名漢字,

    create table S AS
    select distinct a7, a4 FROM KEN_ALL
    UNION ALL
    select distinct a7, a4 FROM JIGYOSYO;
    select distinct a7, a4
    FROM S
    ORDER BY a7;
    

    これを転記するというのが方針です. ここで言っている「転記」を,SQL でどう行うか,以下,説明する. ここでは,説明のため,郵便番号テーブルでなく,仮の簡略化したテーブルを使って説明する. 例えば,あるテーブルがあって,「漢字」,「カタカナ」,「文字数」が次のようになっているとしましょう. 説明用に,テーブル名,列名を日本語にしている.

    create table 元の表 (
        漢字    text,
        カタカナ text,
        文字数 INTEGER
    );
    
    begin transaction;
    insert into 元の表 values('北', 'キタ', 2);
    insert into 元の表 values('北', 'キタ', 2);
    insert into 元の表 values('北', "", 0);
    insert into 元の表 values('北', "", 0);
    insert into 元の表 values('北', "", 0);
    insert into 元の表 values('青', "", 0);
    insert into 元の表 values('青', "", 0);
    insert into 元の表 values('福', 'フク', 2);
    insert into 元の表 values('福', 'フク', 2);
    insert into 元の表 values('福', "", 0);
    insert into 元の表 values('福', "", 0);
    commit;
    

    上記のテーブルを,下記のように変更したいという問題です.「漢字」が「北」,「福」になっていて,かつ, 「カタカナ」が "" になっているレコードには,「カタカナ」,「文字数」を転記したい! ということです. 一方で,「漢字」が「青」のレコードは,転記のしようがないので,手を付けずに残します.

    漢字  カタカナ  文字数
    ======================
    北    キタ      2
    北    キタ      2
    北    キタ      2キタ      2キタ      2
    青          0
    青          0
    福    フク      2
    福    フク      2
    福    フク      2フク      2
    ----------------------
    
    転記後のテーブルの例

    さて,元のテーブルから,変更後のテーブルを得る SQL を段階的に考えましょう. 「select distinct 漢字, カタカナ, 文字数 FROM 元の表;」を実行して,同一値を持つレコードの重複を取り除くと,次のようになる.

    select distinct 漢字, カタカナ, 文字数
    FROM 元の表;
    

    「青」のように,レコードが1つしかないもの「福」,「北」のように,レコードが2個あるものが見て取れます. では,「青」のように,レコードが1つしかないものを選ぶ SQL はどう書けるかというと, これは,副問い合わせを使うのが簡単です.

    1. まずは,「漢字」で集約して,個々の「漢字」ごとに,「カタカナ」の異なり数がいくつあるかを調べ,異なり数が1のレコードだけを選びます. これは,「『カタカナ』が全部 "" になっている」.言い換えると「 ある『漢字』に対して,『カタカナ』として,""そうでないレコードが混ざっている場合には,異なり数は2以上になる」という意味です. そのために, 「HAVING COUNT(DISTINCT(カタカナ)) = 1;」という条件を SQL 内に含めることになる.

      * なお,属性「文字数」は,「カタカナ」に依存する,つまり,関数従属なので, HAVING のところに「文字数」を指定する必要はありません.

    2. 副問い合わせの結果,{「青」} のような,漢字の集合が得られますので,それを使って,元の表からレコードを選び出す.

    SQL とその実行結果は,次のようになる.

    select distinct 漢字, カタカナ, 文字数
    FROM 元の表
    WHERE 漢字 IN
        ( SELECT 漢字
          FROM 元の表
          group by 漢字
          HAVING COUNT(DISTINCT(カタカナ)) = 1 );
    

    同様に, 「福」,「北」のように,カタカナの値が "" であるレコード,ある1つの値を持つものという2種類だけあるものを選ぶ(3種類以上は除外します.) SQL も書けます.SQL とその実行結果は,次のようになる. 先ほどの SQL の「= 1」を「= 2」に変えただけです.

    select distinct 漢字, カタカナ, 文字数
    FROM 元の表
    WHERE 漢字 IN
        ( SELECT 漢字
          FROM 元の表
          group by 漢字
          HAVING COUNT(DISTINCT(カタカナ)) = 2 );
    

    この SQL に少し手を加えて,「カタカタ」が空文字列でないものだけを出力するようにします.(WHERE に,「カタカナ IS not null」を追加している).

    select distinct 漢字, カタカナ, 文字数
    FROM 元の表
    WHERE カタカナ <> ''
        AND 漢字 IN
        ( SELECT 漢字
          FROM 元の表
          group by 漢字
          HAVING COUNT(DISTINCT(カタカナ)) = 2 );
    

    以上をまとめて,次のような UNION (和)を考えます.

    select distinct 漢字, カタカナ, 文字数
    FROM 元の表
    WHERE 漢字 IN
        ( SELECT 漢字
          FROM 元の表
          group by 漢字
          HAVING COUNT(DISTINCT(カタカナ)) = 1 )
    
    UNION
    
    select distinct 漢字, カタカナ, 文字数
    FROM 元の表
    WHERE カタカナ <> '' 
        AND 漢字 IN
        ( SELECT 漢字
          FROM 元の表
          group by 漢字
          HAVING COUNT(DISTINCT(カタカナ)) = 2 );
    

    出力される表は,次のことをあらわしている.

    1. 「青」のレコードには,もともと「カタカナ」の情報が無いので,転記しない.
    2. 「福」のレコードには,「フク」,「2」を転記する
    3. 「北」のレコードには,「アオ」,「2」を転記する

    こうして出来た表を,元の表における転記用に使いたいので, 「create table ... AS ...」を使って,「作業用」という名前のテーブルに保存します.そして,「作業用」と「元の表」の2つのテーブルを使い,「元の表」における転記を行う.

    SQL とその実行結果は,次のようになる.期待通りの結果です.

    create table 作業用リスト AS
        select distinct 漢字, カタカナ, 文字数
        FROM 元の表
        WHERE 漢字 IN
            ( SELECT 漢字
              FROM 元の表
              group by 漢字
              HAVING COUNT(DISTINCT(カタカナ)) = 1 )
    
        UNION
    
        select distinct 漢字, カタカナ, 文字数
        FROM 元の表
        WHERE カタカナ <> '' 
            AND 漢字 IN
            ( SELECT 漢字
              FROM 元の表
              group by 漢字
              HAVING COUNT(DISTINCT(カタカナ)) = 2 );
    
    UPDATE 元の表 SET
      文字数 = (SELECT 作業用リスト.文字数 FROM 作業用リスト WHERE 元の表.漢字 = 作業用リスト.漢字 )
    WHERE カタカナ = '';
    
    UPDATE 元の表 SET
      カタカナ = (SELECT 作業用リスト.カタカナ FROM 作業用リスト WHERE 元の表.漢字 = 作業用リスト.漢字 )
    WHERE カタカナ = '';