カテゴリー: DB/SQL

Access覚書 リンクテーブルをローカルテーブルに変換(VBA)

リンクテーブルをローカルテーブルに変換したい!VBAで!!

と、色々調べてみたのだが、
同じようなことをしたいという質問に、
「エクスポートしたら?」とか、「手作業でできるよね?」
とか、そういう話ばっかりで、
「いやいや、質問者の意図わかってんの?」
って回答しかなくってウンザリ。

で、苦手な英語、といってもカタコト英語だが、
convert linktable to localtable
みたいな感じで調べてみたら、外国人はちゃんとVBAでの解決策を答えてくれていた。

で、回答。

DoCmd.SelectObject acTable, "TABLE1", True
DoCmd.RunCommand acCmdConvertLinkedTableToLocal

“TABLE1” のところを変換したいリンクテーブル名にしてやる。

これ調べるのに半日かかったわ。
でも、もう最悪、テーブルを別ファイルにエクスポートしてからインポートしようかとさえ思っていたので、本当に助かった。
やっぱり、いろんな言語ができたほうがいいのね。
(日本語しかできません。ってか、日本語もできません。)

参考URL:
https://stackoverflow.com/questions/59038993/access-vba-convert-linked-table-to-local

Access覚書 引数を引き渡して起動

Access起動時にパラメータを引き渡し、
渡されたパラメータによって処理をかえる方法。

起動スイッチというのがあるらしい。

参照:Microsoft Office 製品のコマンド ライン スイッチ

ということで

"C:¥.........¥MSACCESS.EXE" "......accdb" /cmd "para1" "para2" "para3" ...

順に
Accessのexe 起動するAccessファイル /cmd パラメータ(必要分)
をそれぞれダブルクォーテーションで括って設定するのが重要らしい。

そして、Access側のVBAはこの引数を引き取って処理を行う。

Command関数
参照:Microsoft Support Command関数

このようにパラメータで渡された文字列は、AutoExecマクロ内で処理をすることにする。

  1. マクロを追加 名称は「AutoExec」にする
  2. 作ったマクロに「プロシージャの実行」を追加し、3.で作成するFunctionプロシージャ名を記載する
  3.   ex) RunProc() ← 必ず()をつける

  4. ここからVBA
  5. 標準モジュールを追加して、2.のマクロで実行させるFunctionプロシージャを追加する
      ex) Function RunProc() …. End Function
    Functionでないとダメで、SubだとCommandを認識しなかった。

  6. 3.のFunctionプロシージャ内に引数を使った処理を記載する
  7.    Function RunProc()
           ' Trimを忘れずに.これはパラメータが複数の時なので1つしかない時は、Trim(Command())でOK
           Dim cmd() As String
           cmd = Split(Trim(Command()), " ")     
           ' 1つめの引数で処理を分岐
           Select Case cmd(0)
           Case "para1"
              ' ここに処理
           Case "paraX"
              ' ここに処理
           Case Else
              ' ここに処理
           End Select
       End Function
    

<注意点>
Command関数の結果は必ずTrimすること。起動コマンドで””で括っているが後ろにスペースが入って渡ってくる。

起動コマンドで最初にexeを指定したくない、ランタイム起動でも問題ない、という場合は、

"......accdb" /runtime /cmd "para1" "para2" "para3" ...

と、/runtimeを挟むと、exeの指定をせずにCommandが引き渡され、処理が走る。


んで、次。
もう1つ別のやり方があるのだが、それは /x スイッチ。

"......accdb" /runtime /x "macro1" /cmd "para1" "para2" "para3" ...

という感じにすると、
/x の後ろに入れたマクロ「macro1」を実行させられるようになる。
で、さっきと同じくプロシージャの実行をマクロに追加して、実行させるFunctionプロシージャを指定する。
VBA側は下記のようにしてパラメータを読み込んでおけばいい。

   Function RunMacro1()
       Dim cmd() As String
       cmd = Split(Trim(Command()), " ")
       ' ここに処理
   End Function

このやり方だと、わざわざ分岐処理を書く必要がないので、見た目が良いかなと思ったりする。


さて、最後。
起動コマンドからランタイム実行(/runtime 付)させたときに、AutoExecは走らせたくないなぁって思ったら、
AutoExecで動くFunction(またはSub)内の先頭に、こういう1文を先頭に入れておくといい。

If SysCmd(acSysCmdRuntime) Then Exit Function

普通に起動させたときは後続処理が走るが、ランタイム起動させたときはプロシージャを抜けるようにしておくこともできるわけだ。

奥が深いぜ、Accessさんよぉ

※ランタイム:Accessから開発機能(フォーム、クエリ、レポート、VBAの作成編集機能)を除いたもの

MySQL覚書 日付型 BETWEEN 整数型 AND 整数型が行けちゃう件

WHERE update_date BETWEEN 20200101 AND 20200131
とか書いて、ちゃんとupdate_dateが2020/1/1~1/31のデータを取ってきちゃってる。

どういうこったぁ!!!と調べたら、

“BOKU”のITな日常 『日付リテラルで日付の比較はしないほうがよさそうだ/MariaDB(MySQL)(備忘)』
という記事の中に

A DATE literal can also be an integer, in one of the following formats: YYYYMMDD or YYMMDD.
DATEリテラルは、YYYYMMDDまたはYYMMDDのいずれかの形式の整数でもかまいません。

という文章が。
MySQL
MySQL Docs『9.1.3 Date and Time Literals』
Maria
MariaDB Docs 『Date and Time Literals』
に同文がある。

ぬおぉぉぉ!スッゴ!
でも、なんか気色悪い・・・

んで、この引用記事の日付リテラルでの比較の話でうまく動かない理由は、

select case when '2018-09-01' > '2018-08-31' then 0 else 1 end;

というSQL文だと、単純に左辺側の’2018-09-01’が文字型扱いになっていることだけで、

select case when CONVERT('2018-09-01',DATE) > '2018-08-31' then 0 else 1 end;

としてやれば、解決する。
比較の対象が文字型として認識されているから、日付リテラル云々の話ではなくなっていて、
左辺が日付型と判断されれば、日付リテラルが利用できると推測する。

理解が不十分だとこういうことになるので注意が必要だが、ちゃんと基本に則り型定義通りに比較すればいいだけの話なのだよ。

MySQL覚書 mysqldumpでUnknown table ‘COLUMN_STATISTICS’…のエラーが出たとき

WordPressにもサイトヘルス機能が入ったのだね。
う~ん、しかし対応できるものがない・・・
Wordpressとは別にPHPで簡易的なシステムを入れているのだが、そっちの対応をしなきゃいけない。
時間がない、というよりやる気が起きないので未だそのまま放置状態にしているのだが、そろそろ本当にあきません!となりそう。

さて、MySQLでのExport、ダンプの件。
dumpでエラーが起きたから調べた。

cd /d “c:\Program Files\MySQL\MySQL Workbench 8.0 CE”
でパス(場所は端末差あり)を切り替えてから、

mysqldump -u [user_id] -h [HOST IP-Address] -p [DB-name] > [output-filename]

パスワードを聞かれる→入力

mysqldump: … Unknown table ‘COLUMN_STATISTICS’ in information_schema (1109)

とエラーが出る。

<原因・対策>
モヒカンメモ『mysqldumpコマンドで “Unknown table ‘COLUMN_STATISTICS’ in information_schema (1109)” と怒られる原因と対策』

に、わかりやすく整理されて書かれているので省略するが、要はダンプexeとDBバージョン違いで発生。
書かれてある通り、オプション追加で、再実行。

mysqldump –skip-column-statistics -u [user_id] -h [HOST IP-Address] -p [DB-name] > [output-filename]

今度は成功。

AccessVBA覚書 Public変数が変わらない

Accessは嫌いです。
理由はわかんないから。

オイオイ・・・

って、そんな理由かい!って思う人もいるのだろうけど、わからないというのは
・想定通り動いてくれない
・Debugしながら動かしたときと、Debugしないで動かしたときで動作が変わる
という2点からだ。

この間VB6のソースを見ていた時も実は同じようなことがあって、
・Debugしながら動かしたときと、Debugしないで動かしたときで動作が変わる
というのは、どうしたらいいのかさっぱりわからないのだ。

そして、VBAをDebug.Printを使って変数値を見ながら実行させてみたらば、Public変数に値を入れているのに値が置き換わっていないことが判明。

で、調べてみたらこんな記事があった。

Public宣言された変数の有効期間 [VBA]

なるへそ。
ってかさ、別に参照設定とかPublic変数を変えたとか、致命的なエラーが出たとかなら、リセットされるのはわかりますよ。
でもね、実行中にリセットする必要ありますか?

何のためのPublic変数なんですか!!!!

と。

で、上述の記事でテーブルに入れるのがいいと書いてあったので、結局その通りいたしました。
Excelでこんなこと起きたことはないんですけどね。
でも起きたことがないだけで、起きることがあるんだと思うとExcelのマクロも作れませんな・・・

大丈夫かMicrosoft。

ORACLE覚書 階層データを引数として渡す

サマリ1
 |– 明細1-1
 |– 明細1-2
サマリ2
 |– 明細2-1

のような、階層のあるデータを引数で渡したいと思って、調べてみたらオブジェクト型なるものを発見。

で、実際にどうやって実装すればいいのか、また調べて実行。

<手順>
1, まずはCREATE TYPEでもって、任意のオブジェクト型を作ってみる。

・明細データの型を作る。(Javaでいうと、データクラスみたいなもの)

CREATE TYPE DTL_TYPE AS OBJECT (
   DTL_ID   VARCHAR2(5)
   DTL_NAME VARCHAR2(10)
);

・次に作った明細(DTL_TYPE)のテーブルを型にする。(JavaでいうとList<明細>みたいなもの)

CREATE TYPE DTLTAB_TYPE AS TABLE OF DTL_TYPE;

・明細が済んだら次はサマリも同じように型を作る。

CREATE TYPE SUM_TYPE AS OBJECT (
  SUM_ID   VARCHAR2(5)
 ,SUM_NAME VARCHAR2(20)
 ,DTL      DTLTAB_TYPE
);
CREATE TYPE SUMTAB_TYPE AS TABLE OF SUM_TYPE;

2, 試しに作ったオブジェクト型を引数に、関数を作ってみる

---------------------------------------
-- 明細データをカンマ区切りで取得
---------------------------------------
CREATE OR REPLACE FUNCTION OTAMESHI_FUNC(
  PARAM IN SUMTAB_TYPE 
) 
RETURN VARCHAR
IS
  TEMP    VARCHAR(1000);
BEGIN
  -- サマリをぐるぐる回す
  DECLARE
  CURSOR CURSUM IS SELECT SUM_ID, SUM_NAME, DTL FROM TABLE(CAST(PARAM AS SUMTAB_TYPE));
  CURSUM_ROW CURSUM%ROWTYPE;
  BEGIN
    OPEN CURSUM;
    LOOP
      FETCH CURSUM INTO CURSUM_ROW;
      EXIT WHEN CURSUM%NOTFOUND;

      TEMP := TEMP || ',<<' || CUR_ROW2.SUM_ID || ':' || CUR_ROW2.SUM_ID || '>>';
      
      -- 明細をぐるぐる回す
      DECLARE
      CURSOR CUR IS SELECT DTL_ID, DTL_NAME  FROM TABLE(CAST(CURSUM_ROW.DTL AS DTLTAB_TYPE));
      CUR_ROW CUR%ROWTYPE;
      BEGIN
        OPEN CUR;
        LOOP
          FETCH CUR INTO CUR_ROW;
          EXIT WHEN CUR%NOTFOUND;

          TEMP := TEMP || ',' || CUR.DTL_ID || ':' || CUR.DTL_ID;

        END LOOP;
      END;


    END LOOP;
  END;

  -- TEMPに入れたデータを返す
  RETURN TEMP;
EXCEPTION
  WHEN OTHERS THEN
    RETURN 'エラーです.';
END;

3, 作った関数を呼び出してみる

SELECT
  OTAMESHI_FUNC(
      SUMTAB_TYPE(
        SUM_TYPE('01'
               , 'まさか'
               , DTLTAB_TYPE(
                             DTL_TYPE('A1','やさか')
                            ) 
               )
       ,SUM_TYPE('02'
               , 'どうか'
               , DTLTAB_TYPE(
                             DTL_TYPE('D1','ぎんか')
                            ,DTL_TYPE('B1','きんか')
                            ) 
               )
     )
  )
FROM DUAL

できるのは解ったのだが、う~ん、どうなんだろう。

PostgreSQL覚書 RETURNIG *

UPDATE、INSERT、DELETE文の最後に「RETURNING *」を加えてやると、「更新件数が返ってくる」というのをネット上で見たのだが、厳密にはどうやらそうではないらしいのでメモっておく。

INSERT .... RETURNING *

と書くとINSERTしたデータ行がすべて返ってくるのであって、件数が返ってくるわけではないのだ。
結局、

INSERT .... RETURNING {キー項目}

みたいに書いて、返ってきたデータの行数から更新件数を導きだす必要があるのだ。
だから、Javaなんかだと、SQL文を実行後のResultSetのgetRowメソッドを使う。
例)

int kensu = rs.getRow();

みたいに、返ってきたデータの行数を取得してやるのだ。

中途半端な日本語を書かれると、こういう勘違いをしてしまう。

Docker覚書 Win10にインストールの巻

そろそろDockerぐらい使えないと!と思って、仕事が暇な今こそ!とチャレンジ。
で、WordpressとMySQLの環境を作って繋げてやろうと意気込んで開始して、後述する手順でうまくいった。

ただ、後から分かったが、同じ環境でVMWare Workstationも使っているので、Dockerを動かしている間はVMWare側は動かせない・・・
しまった!!!
と思いつつ、とりあえずはDockerインストールと環境立ち上げの手順だけの備忘録を投稿。

Windows10でDocker上にWordPressを立ち上げる

  1. Docker CE → Desktop Docker for Windows インストール
  2. Desktop Dockerを起動、Setting
    • スタートメニュー等よりDesktop Dockerを起動
    • タスクバーにDockerアイコンが表示されたらアイコンを右クリックしてSettingをクリック
    • DaemonのExperimentalにチェックしApply
    • NetworkのDNS ServerはFixed:を選択して「8.8.8.8」を設定
    • ResetでRestart Docker…をクリック
  3. コマンドプロンプトを起動
  4. Imageの取込コマンド実行(次のrunコマンド実行でimageがなかったら自動的に取り込むのでここは省略できる。)
    • docker pull mysql:5.7.25
    • docker pull wordpress:latest
    • docker images で取り込めたかどうか確認
  5. コンテナー作成・起動
    • docker run --name test-mysql -e MYSQL_ROOT_PASSWORD=password -d -p 3307:3306 mysql:5.7.25
    • docker run --name test-wordpress --link test-mysql:mysql -d -p 8081:80 wordpress
      • それぞれ、ポート番号は他と被らない番号にしておきます。
    • docker container ls -a  で作成できたかどうか確認
  6. localhost:8081に接続して確認
    • WordPressの初期設定画面が表示されたら、うまく動作していることになる。

うまくいかないパターン

  • DB接続できない
    • MySQLのバージョンがWordpressと噛み合ってないのが原因

他のDockerコマンド

  • docker exec -it {コンテナ名} /bin/bash
    • Linux上でコマンド操作可能に
    • cat wp-config.php で定義ファイル内の確認
  • docker stop {コンテナ名}  コンテナ停止
  • docker start {コンテナ名}  コンテナ開始
  • docker rm {コンテナ名}  コンテナ削除
  • docker rmi {イメージ名}  イメージ削除

他のLinuxコマンド

  • apt update
  • apt install -y vim (WordPressサーバ上で、VIMを利用する場合)
  • apt install -y procps (MySQLサーバ上でMySQLが動作しているか確認で利用)
  • ps aux (プロセス状態確認)
  • mysql -u root -p (MySQL接続)
  • exit (Linuxから抜ける)

PostgreSQL覚書 crosstabでPIVOT

PostgreSQLでもOracleのPIVOTみたいなことをやりたいなぁ・・・と思って調べた。
crosstabらしい。
拡張機能らしい。
早速PgAdminで以下のSQLを実行して取り込む。

CREATE EXTENSION IF NOT EXISTS tablefunc;

いくつか関数が追加された中に、crosstabがあればOK。
で、続けてSQLを組み立てる。

今回は以下のように縦並びである店舗日別データ(qty)を全店SUM(qty)にして横並びにしてみる。
tab_shop_qty カラム構成(y |m |d |no |shop | qty)

CREATE TABLE tab_shop_qty (
  y integer,
  m integer,
  d integer,
  no integer,
  shop character varying(10),
  qty numeric(5,0)
);
INSERT INTO public.tab_shop_qty values(2019,1,1,1, 'abc', 10);
INSERT INTO public.tab_shop_qty values(2019,1,1,2, 'abc', 8);
INSERT INTO public.tab_shop_qty values(2019,1,2,1, 'abc', 25);
INSERT INTO public.tab_shop_qty values(2019,1,2,2, 'abc', 15);
INSERT INTO public.tab_shop_qty values(2019,1,1,1, 'efg', 12);
INSERT INTO public.tab_shop_qty values(2019,1,1,2, 'efg', 7);
INSERT INTO public.tab_shop_qty values(2019,1,1,2, 'efg', -2);
INSERT INTO public.tab_shop_qty values(2019,1,2,1, 'hij', 20);

店舗(shop)別に、日毎のqtyを横に並べる

SELECT c.shop,c."1",c."2",...,c."31"
FROM crosstab(
      'SELECT shop,d,SUM(qty) qty FROM tab_shop_qty WHERE y=2019 AND m=1 GROUP BY shop,d ORDER BY 1'
     ,'SELECT d FROM generate_series(1,31) d'
     )  
AS c(shop varchar,"1" numeric,"2" numeric,...,"31" numeric) 
ORDER BY c.shop

上の例だと、shopというカラム1つだけがキーになっているのでこのようなSQLで済むのだが、キーが複数カラムある場合は、第1引数のSQL文にORDER BY句を追加するという工夫が必要。

店舗,NO(shop,no)別に、日毎のqtyを横に並べる

SELECT c.shop,c.no,c."1",c."2",...,c."31"
FROM crosstab(
      'SELECT shop,no,d,SUM(qty) qty FROM tab_shop_qty WHERE y=2019 AND m=1 GROUP BY shop,no,d ORDER BY 2'
     ,'SELECT d FROM generate_series(1,31) d'
     )  
AS c(shop varchar,"1" numeric,"2" numeric,...,"31" numeric) 
ORDER BY c.shop,c.no

ドキュメントurl: https://www.postgresql.jp/document/9.6/html/tablefunc.html では、
第1引数のORDER BY句は
「実際は、同じrow_name(キー項目のこと)を持つ値をまとめられるように、source_sql(第1引数のSQL文のこと)問い合わせでは常にORDER BY 1を指定すべきです。」
との記載があるが、「ORDER BY 1」なのであれば指定ありとなしでは変わりはなかった。

結局、ORDER BYの指定の仕方がイマイチわからなかったが、ORDER BYの1つめで指定したカラム数まではキー、次が第2引数のデータとの関連付け用、その次がPIVOTとして出力するデータ、かな・・・などと思った。

————————
<2019/08/08 追記>
いろいろ試していた時に発覚したことがあったので追記。
crosstabの第1引数のSQL文だが、グルーピングするカラムのうち、1つでもデータが1種類しかないカラムが存在した場合、うまく動作しないことが分かった。
上の説明文だと自分で後から見直しても、なんのこっちゃ!って思うと推測するので、追記しておくと・・・・
最後の例だとshop,noの2カラムがグループ,dが横並びにするカラム,qtyが横並びにするデータとなるのだが、
テーブルのレコードにshop=’abc’のデータ1種類しかない場合、crosstabがうまく動作しないということがある、ということだ。
ORDER BY 2までならうまくいくかもしれないが、少なくとも私が試してみたORDER BY 3(つまりグルーピングするカラムが3列)の場合、うまくマージされず、本来は何全行と出るはずの結果レコードが1行しか出てこない始末となった。

う~ん、なんとかなんないのだろうか。他にうまくできる方法を探さなければ、「関数作成してカーソル利用」しか思いつく方法がない・・・

Access覚書 リンク貼替

結構間が開いてしまった。
1か月に1度ぐらいはせめて投稿しようと思いつつ。

テーブルやらクエリやらがAサーバのDBをみているのだが、Bサーバのテスト環境のDBをみるように変えたい
となったとき、結構大変である。
標準機能で変更できるのかどうか、やり方がわからん。

ということで、VBAでできないか探してみたら、やはり一括でどべっと変更できるやり方があった。

' テーブルとクエリのリンク先を変更
' 引数 :from_srv = 変更前(例:172.0.0.1)
'    :to_srv   = 変更後(例:196.128.1.10)
Sub ChangeLinks(from_srv As String, to_srv As String )

    Dim db As DAO.Database
    Dim tb As DAO.TableDef
    Dim qr As DAO.QueryDef
    
    Set db = CurrentDb
    On Error Resume Next
    For Each tb In db.TableDefs
        If tb.Connect <> "" Then
            tb.Connect = Replace(tb.Connect, from_srv , to_srv)     'サーバ変更
            tb.RefreshLink  ' テーブルはリフレッシュ
        End If
    Next
    For Each qr In db.QueryDefs
        If qr.Connect <> "" Then
            qr.Connect = Replace(qr.Connect, from_srv , to_srv)     'サーバ変更
        End If
    Next
End Sub

パスワードとかだと、
Replace(tb.Connect, “PWD=***”, “PWD=***”)
ってな感じで変換してやる。

SQLServer覚書 Export/Import

SQLServerはテーブル指定のバックアップができない?

ってなことで、エクスポートとインポートをお勉強。

1) Export

BCP {DBName}.{scheme}.{Table} out c:\table1.txt -c -S localhost -U {user} -P {pwd}
BCP "SELECT * FROM {DBName}.{scheme}.{Table} WHERE 1=1" queryout c:\table2.txt -c -S localhost -U {user} -P {pwd}

1つ目はテーブルそのまま。テーブル指定後は、「out」を指定して、エクスポート先ファイルを指定してExportする。
2つ目は条件句で範囲を指定してその分だけデータをとってくる方法。こっちは「queryout」でExportする。
いずれも、その後ろは接続先とユーザ名・パスワードを設定。

2) Import

BCP {DBName}.{scheme}.{Table} IN c:\table1.txt -c -S  localhost -U {user} -P {pwd}

インポート先を指定後、「IN」でインポート元ファイルを指定。
こちらもインポート先のDB接続情報を後ろに入れる。
挿入するので、主キーが重複しないようあらかじめ削除しておくこと。

モチの論、BCP.exeがないと動きまヘン。

SQLServer覚書 比較設定

SQLServerはそのDB設定によって、大文字小文字や半角全角を意識しないとのこと。
つまり、’A’ = ’a’ は True になるわけ。
現在の設定を確認したい場合は、以下のようなSELECT文を実行する。
({DBNAME}のところに対象DB名を入れる)

SELECT DATABASEPROPERTYEX('{DBNAME}', 'collation');

これはこれでいいんだが、で、意識したいときはどうすんの?って話で、

SELECT * 
FROM foo
WHERE x = 'X' COLLATE Japanese_CS_AS
AND   y = 'Y' COLLATE Japanese_BIN;

と、まぁこんな風に条件項目ごとに設定をしていくとのこと。

BINやCS、AS、KS等の違いは以下参照。
Windows 照合順序並べ替えスタイル

AccessVBA覚書 IsNumeric関数

数値(整数)チェックをしようと、

Function CheckNumber(v as Varient) As Boolean
  CheckNumber = True
  If Len(v)=0 Then Exit Function
  If IsNumeric(v) Then Exit Function
  CheckNumber = False
End Function

とか記載したら、vに「a」とか入れてもTrueで返ってきてしまった。

Function CheckNumber(v as Varient) As Boolean
  CheckNumber = True
  If Len(Cstr(v))=0 Then Exit Function
  If IsNumeric(Cstr(v)) Then 
    If InStr(Cstr(v),".")=0 Then Exit Function '小数じゃなかったら(簡易チェック)
  End If
  CheckNumber = False
End Function

みたいに、文字列に変えてからIsNumericしたらうまくいった。
関数の引数を文字列型にするってのも手だけど、簡易版なのでこれでいいかなと思った。

SQLite覚書 テーブル一覧の取得

SQLiteでテーブルの一覧を取得する場合、コマンドの「.schema」を使う方法もあるが、面倒な時もあるので、以下のようにSELECT文を使う。

SELECT * FROM sqlite_master
WHERE type = 'table' 
ORDER BY name;

WHERE句の条件を外すと、オブジェクトの一覧になって、INDEXの情報なんかも取得できる。

さて、6月も中盤。
4月から3か月間かけて行う新人研修も終盤だが、どうも、今年はイマイチ。
新人がイマイチなのか、我々がイマイチなのか、どちらもダメなのか・・・

それはともかく、中学生や高校生が読めるような漢字を読めない人がいるのがまずウンザリ。
昨今、高等教育の無料化を声高に言う人がいるが、そもそも、初等・中等教育をしっかりしてほしい。
小学生でも読めそうな漢字も読めない大人って、社会に必要なのか?
初歩的な現代国語ぐらいちゃんと勉強させてほしいものだ。

MySQL覚書 配列、縦→横、カンマ区切り

同じIDのTITLEデータをカンマ区切りでとってきたい!
とか思って漁っていたら、

MySQLでidだけをSELECTして、カンマ区切りにして出力する

という、ページが見つかった。
GROUP_CONCATという関数を使い、区切り文字をカンマに指定する方法である。

SELECT GROUP_CONCAT(title SEPARATOR ',') FROM t_sample WHERE id = 1;

PostgreSQLだと、ARRAY_TO_STRING

<参照>PostgreSQL覚書 配列

SQLite覚書 副クエリを使ったUPDATE

世の中には、ありがた迷惑とか、小さな親切大きなお世話とか、そういうことがわからない人が一杯いるようだ。
そういう人は、「やるな!」「やらないでくれ!」っていっても、「やる」のだなぁ。
人のやること横取りするんじゃないよ!と、叫びたかった、今日の朝。

それはそうと、SQLiteでSELECT文を使ってUPDATEしたい!というのがあって、
そうすると、まぁ、

 UPDATE table1 SET
  col1 = (SELECT col1 FROM table2 WHERE .... )

みたいにすればできるぜ!みたいなことはいっぱい書いてあるんだけど・・・

 そうじゃないんです!
 JOINで連結させて、ホゲホゲホゲ・・・とやりたいんです!

という要求は満たされないわけ。

で、調べた。

SQLiteはWITH句が使えるらしい。
んで、WITH句をうまく活用して、UPDATEできるらしい。

他のDBのSQL文を

UPDATE table1 SET
    col1 = a.col1
  , col2 = a.col2
 FROM (SELECT .... FROM .... INNER JOIN ....) a
 WHERE table1.id = a.id

とすると、
WITH句を使ったSQL文は

WITH a AS (
  SELECT .... FROM .... INNER JOIN ....
)
UPDATE table1 SET
    col1 = (SELECT col1 FROM a WHERE table1.id = a.id)
  , col2 = (SELECT col2 FROM a WHERE table1.id = a.id)

みたいな感じ。

で、これを私が愛用する「A5:SQL Mk-2」(SQL開発ツール)で実行したのだが、うまくいかずに、「あれ?できないの?」とか思って悩んだのだが、ツール上ではうまくいかないだけで、SQLiteのコマンド実行では、ちゃんと動いた。

ホント、統一させてほしいんですけど。

Processing覚書 SQLite接続

Processing開発。
BezierSQLibライブラリを使ってSQLiteのDBにつないでいるのだが、1つ問題が。

というのも、エラーになったときExceptionが発生しない。
ライブラリ内部で例外処理までしてるのは兎も角、結果がエラーになってもエラーを判別できるフラグがない。
DBにLockがかかってる時にUPDATEしても、コンソールにエラーメッセージは出るが、それだけ・・・
Rollbackするタイミングがつかめない。
このままではマズイ。困った。

こうなったら、直接jdbcライブラリを利用しよう!となった。

プログラムソースのpdeファイルが入っているフォルダの下に「data」フォルダを作って、その中にDBファイルの「test.db」を入れる。
「data」フォルダと同じ並びに「code」フォルダを作って、その中にライブラリ「sqlite-jdbc-***.jar」ファイルを入れておく。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;

// ------------------- ( 略 ) -------------------

void getData() {
  Connection con = null;
  Statement stmt = null;
  try {
    Class.forName("org.sqlite.JDBC");
    con = DriverManager.getConnection("jdbc:sqlite:"+ dataPath("test.db"));
    println("Opened database successfully");
    
    stmt = con.createStatement();
    stmt.executeUpdate("INSERT INTO m_users (user_cd ,user_name) VALUES ('1010101', 'Lily');");
    stmt.close();
    con.close();
  } catch ( Exception e ) {
    println( e.getClass().getName() + ":" + e.getMessage());
  }
}

Macでいけたから、あとはWindowsでも確認しよう。