2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

結合クエリもCashUpdateできるんです

Last updated at Posted at 2023-05-21

サンプルソースは、
https://delphi-dev.sakura.ne.jp/FileBox/CashUpdateSample/
よりダウンロードできます。

結合クエリのCashUpdate

結合クエリでのCashUpdateを使った更新方法について書きます。
更新ができるテーブルは、当然1つだけです。
Delphi 11.3
DBアクセス:FireDAC
DatabaseはSQLiteで確認しています。
他のコンポーエントやデータベースでも考え方は同じなので適用できると思います。

テーブル

伝票明細(Meisai)、商品マスタ(Syouhin) (1:N関連)
(伝票明細を編集するイメージです)

CREATE TABLE MEISAI (
    ORDERNO    INTEGER NOT NULL,
    MEISAINO    INTEGER NOT NULL,
    SYOUHINCODE    INTEGER NOT NULL,
    TANKA    REAL DEFAULT 0,
    SURYO    REAL DEFAULT 0,
    BIKOU    TEXT DEFAULT '',
    PRIMARY KEY(ORDERNO,MEISAINO)
)
CREATE TABLE SYOUHIN (
    SYOUHINCODE    INTEGER NOT NULL,
    SYOUHINNAME    TEXT,
    SYOUHINTANKA    REAL,
    PRIMARY KEY(SYOUHINCODE)
)

クエリ

SELECT
 M.ORDERNO
,M.MEISAINO
,M.SYOUHINCODE
,S.SYOUHINNAME
,S.SYOUHINTANKA
,M.TANKA     /* 更新対象 */
,M.SURYO     /* 更新対象 */
,M.BIKOU     /* 更新対象 */
FROM
  MEISAI M   /* 更新するテーブルはこの位置で無いといけない */
  INNER JOIN SYOUHIN S
  on (S.SYOUHINCODE = M.SYOUHINCODE)
where
 M.ORDERNO = :ORDERNO
order by
 M.MEISAINO

FDQueryの設定

 前記クエリを設定後、フィールドエディタでフィールドの展開をする。
FDQueryのdfmファイル内容(関係ない部分は一部削除しています)

object QryList: TFDQuery
    OnCalcFields = QryListCalcFields
    CachedUpdates = True
    SQL.Strings = (
      select
       M.ORDERNO
      ,M.MEISAINO
      ,M.SYOUHINCODE
      ,S.SYOUHINNAME
      ,S.SYOUHINTANKA
      ,M.TANKA
      ,M.SURYO
      ,M.BIKOU
      from
        MEISAI M
        inner join SYOUHIN S
        on (S.SYOUHINCODE = M.SYOUHINCODE)
      where
       M.ORDERNO = :ORDERNO
      order by
       M.MEISAINO)
    object QryListORDERNO: TIntegerField
      FieldName = 'ORDERNO'
      ProviderFlags = [pfInWhere, pfInKey]
    end
    object QryListMEISAINO: TIntegerField
      FieldName = 'MEISAINO'
      ProviderFlags = [pfInWhere, pfInKey]
    end
    object QryListSYOUHINCODE: TIntegerField
      FieldName = 'SYOUHINCODE'
      ProviderFlags = [pfInUpdate]
    end
    object QryListSYOUHINNAME: TWideStringField
      FieldName = 'SYOUHINNAME'
      ProviderFlags = [pfHidden]
      ReadOnly = True
    end
    object QryListSYOUHINTANKA: TFloatField
      FieldName = 'SYOUHINTANKA'
      ProviderFlags = [pfHidden]
      ReadOnly = True
    end
    object QryListTANKA: TFloatField
      FieldName = 'TANKA'
      ProviderFlags = [pfInUpdate]
    end
    object QryListSURYO: TFloatField
      FieldName = 'SURYO'
      ProviderFlags = [pfInUpdate]
    end
    object QryListCalKINGAKU: TIntegerField
      FieldKind = fkCalculated
      FieldName = 'CalKINGAKU'
      Calculated = True
    end
    object QryListBIKOU: TWideStringField
      FieldName = 'BIKOU'
      ProviderFlags = [pfInUpdate]
    end
  end

FDQueryの設定のポイント

ポイントは、ProviderFlagsになります。
更新するフィールドは、pfInUpdateをTrueにする。
更新時の、Where句に相当する部分は、pfInWhereをTrueにする。
join先のテーブルのフィールドは、pfHiddenをTrueにする。
テーブルの主キーのフィールドは、pfInKeyをTrueにする(ふつう勝手にTrueになる)

*結合クエリとは関係ないが、BDEからFireDAC切り替え時、BDEでは設定しなくても問題なかったが、キー項目のProviderFlagsが、未設定だとエラーが出る。
エラー(例外:EFDDBEngineException)が出たらキー項目の下記の確認を。
ProviderFlags = [pfInWhere, pfInKey]
エラー内容は何パターンかあるようだ。

 メッセージ [FireDAC][Phys][IB]-312.~~~~
 メッセージ [FireDAC][DApt]-400.~~~~

など。
上記だけではわかりにくいかと思うのでサンプルを下記にアップ。データベースも含めています。
(含 LookUpフィールドサンプル。結合クエリを使わないもの)
明細の追加や削除は考慮して作っていません。上記確認のためなので諸々端折っています。

追記。。。。

今回のケースでは、

from
  MEISAI M    /*更新するテーブルはこの位置で無いといけない*/
  inner join SYOUHIN S
  on (S.SYOUHINCODE = M.SYOUHINCODE)

の部分は、下記のようなLeft Outer Joinでも使えます
(仕様としては、商品マスタが無い商品を取り扱うというのは、NGですが)

from
  MEISAI M    /*更新するテーブルはこの位置で無いといけない*/
  left outer join SYOUHIN S
  on (S.SYOUHINCODE = M.SYOUHINCODE)

でもOK。
right outer join や full outer join は、当然ダメ。
ちなみにもともと、SQLiteは、right outer join / full outer join をサポートしていませんが。。。
他のデータベースをつかうときの注意点です。
ついでに。
たぶんやろうとしないと思うけど、複数のテーブル(今回では、MEISAIとSYOUHIN)を同時に更新もNGです。

追記その2。。。。

(結合クエリとLookupフィールドについて。私論)
上記の処理では、SYOUHINCODEも変更するということが一般だと思う。
この場合、上記結合テーブルで行うと、SYOUHINCODEが変わったときの処理、コードでゴリゴリ書く必要が出てくる。そのように考えると、SYOUHINテーブルの引用は、Lookupフィールドを使ったほうが便利だと思う。
ただ、読み込むMEISAIテーブルのデータが少ないケースはそれでよいが、件数が多いケースでは、Lookupフィールドの使用は、格段に処理時間がかかる。そういったケースではコードでゴリゴリ書くことに目をつぶって、結合テーブルを使用することもメリットが出ると思う。

2
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?