サブフォームに通番を表示するためのレコードソース
- SELECT
- A.ID,
- , A.code
- , A.name
- , A.address
- , (SELECT
- Count(*)
- FROM
- (SELECT
- C.*
- FROM
- Sheet1 AS C
- WHERE
- C.CODE='030') AS B
- WHERE
- A.ID >= B.ID) AS 順番
- FROM
- (SELECT
- D.*
- FROM
- Sheet1 AS D
- WHERE
- D.CODE='030') AS A;
- ここで
- (SELECT
- D.*
- FROM
- Sheet1 AS D
- WHERE
- D.CODE='030')
- をAAとすると
- SELECT
- A.ID
- , A.code
- , A.name
- , A.address
- , (SELECT
- Count(*)
- FROM
- AA AS B
- WHERE A.ID >= B.ID) AS 順番
- FROM AA AS A;
- となり、理解がし易くなります。
件数および数値の合計
Table1とTable2のCODEで連結してCODE毎にTable2の件数と合計を計算してTable1にセットします。
- UPDATE
- Table1
- INNER JOIN Table2
- ON (Table1.CODE=Table2.CODE)
- SAVE
- Table1.件数 = Table1.件数+1
- , Table1.合計 = Table1.合計+Table2.数値;
データが重複しないように連番を付けて追加
*****Y(PostTable)にIDとCODEで照合して有無を判定 NOT EXISTS (SELECT Y.* FROM PostTable AS Y WHERE Y.ID=X.ID AND Y.CODE=X.CODE) *****Yに存在しないものを抽出(C) SELECT X.* FROM MeiboTable AS X WHERE [判定] *****CODEが040であるものを抽出(A)(B) SELECT C.* FROM [抽出] AS C WHERE C.CODE='040' *****抽出(A)のIDよりも小さい抽出(B)のIDのレコード数を求める SELECT COUNT(*) FROM [抽出] WHERE B.ID<=A.ID *****PostTableのCODEの条件(この場合040)に合う順番の最大値を起算の基準値とする 最初の1回しか実行されない NZ(DMAX("順番","PostTable","CODE='040'"),0)
- INSERT INTO
- PostTable ( 順番,
- ID,
- code,
- name,
- address )
- SELECT
- (SELECT
- COUNT(*)
- FROM
- (SELECT
- C.*
- FROM
- (SELECT
- X.*
- FROM
- MeiboTable AS X
- WHERE
- NOT EXISTS (SELECT
- Y.*
- FROM
- PostTable AS Y
- WHERE
- Y.ID=X.ID AND Y.CODE=X.CODE)) AS C
- WHERE
- C.CODE='040') AS B
- WHERE
- B.ID <= A.ID )+ NZ(DMAX("順番", "PostTable", "CODE = '040'"), 0) AS 順番
- , A.ID
- , A.code
- , A.name
- , A.address
- FROM
- (SELECT
- D.*
- FROM
- (SELECT
- X.*
- FROM
- MeiboTable AS X
- WHERE NOT EXISTS (SELECT
- Y.*
- FROM
- PostTable AS Y
- WHERE
- Y.ID=X.ID AND Y.CODE=X.CODE)) AS D
- WHERE
- D.CODE='040') AS A;
集計SQL
table_1 SQL実行 名前 日付 金額 名前 合計 日付1 金額1 日付2 金額2 日付3 金額3 A 2021/5/1 100 A 600 2021/5/1 100 2021/7/5 400 2021/8/10 100 B 2021/6/1 200 B 500 2021/6/1 200 2021/7/15 300 C 2021/6/10 300 C 300 2021/6/10 300 A 2021/7/5 400 B 2021/7/15 300 A 2021/8/10 100
- SELECT
- 名前
- , SUM(金額) AS 金額合計
- , MAX(IIF(ランク = 0, 日付, NULL)) AS 日付1
- , MAX(IIF(ランク = 0, 金額, NULL)) AS 金額1
- , MAX(IIF(ランク = 1, 日付, NULL)) AS 日付2
- , MAX(IIF(ランク = 1, 金額, NULL)) AS 金額2
- , MAX(IIF(ランク = 2, 日付, NULL)) AS 日付3
- , MAX(IIF(ランク = 2, 金額, NULL)) AS 金額3
- FROM
- (SELECT
- *
- , (SELECT
- COUNT(*)
- FROM
- table_1 AS B
- WHERE
- A.名前 = B.名前 AND B.日付 < A.日付) AS ランク
- FROM table_1 AS A) AS T
- GROUP
- BY 名前;
複数のレコードをグループ化した時の期間の満了日
期間の満了日が空白ということは、現在期間の進行中であるからグループ化するときも空白にしたい。集計関数Maxは、Nullを無視するのでそのままでは意図する集計はできない。そこで、レコードをカウントするCount(*)とNullを無視したカウントCount(フィールド名)を使い、NullがないのならばCount(*)=Count(フィールド名)、あるのであればCount(*)<>Count(フィールド名)となる性質を利用する。日付2とするのは日付では循環エラーがでるためである。
IIF関数のところは、SWITCH関数を使うのであれば、 SWITCH (COUNT(*) = COUNT(フィールド名), MAX(フィールド名), TRUE, NULL) とします。
- SELECT
- [テーブル1].A
- , IIF(COUNT(*) = COUNT(日付), MAX([日付]), NULL) AS 日付2
- FROM
- テーブル1
- GROUP BY
- [テーブル1].A;
SWITCH関数の入れ子
SWITCH関数の分岐は13までで14以上になるとエラーになります。14以上になるのであれば入れ子をして対応します。
13番目、最終の True, 次の入れ子(最終値)の部分は、ここに至る xpr-○ で真にならなければ 必ず実行されます。 特に、予期せぬ結果にならないように True, 最終値 を必ず書くようにします。
- SWITH ( xpr-1, value-1,
- xpr-2, value-2,
- ・・
- xpr-12, value-12,
- True, SWITCH ( xpr-13, value-13,
- xpr-14, value-14,
- ・・
- xpr-24, value-24,
- True, SWITCH ( xpr-25, value-25,
- xpr-26, value-26,
- ・・
- True, 最終値
- )
- )
- )
汎用的に縦から横へ変換(クロス表)
フィールド名を汎用的に作成する必要があります
グループ毎に連番を振り、それを利用します。
元テーブル 順番の振付 ------------------ ------------------------ ID 事件ID 業者 順番を振る ID 事件ID 業者 順番 1 1 AAAA → 1 1 AAAA 1 2 1 BBBB → 2 1 BBBB 2 3 1 CCCC → 3 1 CCCC 3 4 1 DDDD → 4 1 DDDD 4 5 2 EEEE → 5 2 EEEE 1 6 2 FFFF → 6 2 FFFF 2 7 2 GGGG → 7 2 GGGG 3 8 2 HHHH → 8 2 HHHH 4 9 2 IIII → 9 2 IIII 5 10 2 JJJJ → 10 2 JJJJ 6 縦横変換(クロス表) --------------------------------------------------------------------- 事件ID 業者1 業者2 業者3 業者4 業者5 業者6 業者7 業者8 業者9 業者10 1 AAAA BBBB CCCC DDDD 2 EEEE FFFF GGGG HHHH IIII JJJJ
グループ(Partition)毎に1から連番を振るSQL(IDに重複がないこと) SELECT A.事件ID , A.業者 , (SELECT COUNT(*) FROM 業者 AS B WHERE B.事件ID = A.事件ID AND B.ID <= A.ID) AS 順番 FROM 業者 AS A GROUP BY A.事件ID, A.業者, A.ID
- 連番が振れれば汎用的に縦横変換(クロス表)が作成できます。
- SELECT
- Z.事件ID
- , MAX(IIF(Z.順番 = 1, Z.業者, NULL)) AS 業者1
- , MAX(IIF(Z.順番 = 2, Z.業者, NULL)) AS 業者2
- , MAX(IIF(Z.順番 = 3, Z.業者, NULL)) AS 業者3
- , MAX(IIF(Z.順番 = 4, Z.業者, NULL)) AS 業者4
- , MAX(IIF(Z.順番 = 5, Z.業者, NULL)) AS 業者5
- , MAX(IIF(Z.順番 = 6, Z.業者, NULL)) AS 業者6
- , MAX(IIF(Z.順番 = 7, Z.業者, NULL)) AS 業者7
- , MAX(IIF(Z.順番 = 8, Z.業者, NULL)) AS 業者8
- , MAX(IIF(Z.順番 = 9, Z.業者, NULL)) AS 業者9
- , MAX(IIF(Z.順番 = 10, Z.業者, NULL)) AS 業者10
- FROM
- (SELECT
- A.ID
- , A.事件ID
- , A.業者
- , (SELECT
- COUNT(*)
- FROM
- 業者 AS B
- WHERE
- B.事件ID = A.事件ID AND B.ID <= A.ID) AS 順番
- FROM
- 業者 AS A
- GROUP BY
- A.事件ID, A.業者, A.ID) AS Z
- GROUP BY
- Z.事件ID;
グループをまとめて全体の連番を振る
元テーブル 順番の振付 ------------------ ------------------------ ID 事件ID 業者 順番を振る ID 事件ID 業者 順番 1 1 AAAA → 1 1 AAAA 1 2 2 BBBB → 2 2 BBBB 5 3 1 CCCC → 3 1 CCCC 2 4 1 DDDD → 4 1 DDDD 3 5 2 EEEE → 5 2 EEEE 6 6 2 FFFF → 6 2 FFFF 7 7 2 GGGG → 7 2 GGGG 8 8 1 HHHH → 8 1 HHHH 4 9 2 IIII → 9 2 IIII 9 10 2 JJJJ → 10 2 JJJJ 10
- SELECT
- A.ID
- , A.事件ID
- , A.業者
- , (SELECT COUNT(*) FROM
- 業者 AS B
- WHERE B.事件ID & FORMAT(B.ID,'0000') <= A.事件ID & FORMAT(A.ID,'0000')) AS 順番
- FROM 業者 AS A
- GROUP BY A.事件ID, A.業者, A.ID;
横持ちの表を縦持ちに変換
テーブル名:Personnel Class Member1 Member2 Member3 クラスA ああ いい うう クラスB かか きき クラスC ささ クラスD を Class Member クラスA ああ クラスA いい クラスA うう クラスB かか クラスB かか クラスC ささ クラスD に変換します。 Memberのマスター表を考えます。 前半のSQLを実行すると次のように出力されます(後半のSQLでこれをサブSQLにします。) Member ああ かか ささ いい きき うう テーブルPersonnelとサブSQLで外部結合をします。 外部結合する訳は、MemberがいないクラスDも表示するためです。
- 'Memberのマスター表を考えます。
- SELECT A.Member
- FROM
- (SELECT B.Member1 AS Member FROM Personnel AS B
- UNION
- SELECT C.Member2 AS Member FROM Personnel AS C
- UNION
- SELECT D.Member3 AS Member FROM Personnel AS D
- ) AS A
- WHERE Not A.Member Is Null;
- '外部結合をして
- SELECT A.Class, B.Member
- FROM Personnel AS A
- LEFT JOIN
- (SELECT XX.Member
- FROM
- (SELECT X.Member1 AS Member FROM Personnel AS X
- UNION
- SELECT Y.Member2 AS Member FROM Personnel AS Y
- UNION
- SELECT Z.Member3 AS Member FROM Personnel AS Z
- ) AS XX
- WHERE Not XX.Member Is Null
- ) AS B
- ON B.Member = A.Member1 OR BMember = A.Member2 OR B.Member = A.Member3;
- '下記のようにしたいところですが、ACCESSではエラーになります。
- 'ON B.Member IN (A.Member1, A.Member2, A.Member3)
行番号の付加
- SELECT
- X.*
- , (SELECT
- COUNT(*)
- FROM
- 数列1 AS Y
- WHERE
- Y.取引日 <= X.取引日) AS ROW
- FROM
- 数列1 AS X
前日(ひとつ前の行)の値を並べる
- SELECT
- A.*
- , (SELECT
- B.価格
- FROM
- (SELECT
- X.*
- , (SELECT
- COUNT(*)
- FROM
- 数列1 AS Y
- WHERE
- Y.取引日 <= X.取引日) AS ROW
- FROM
- 数列1 AS X) AS B
- WHERE
- B.ROW = A.ROW - 1) AS 前日
- FROM
- (SELECT
- X.*
- , (SELECT
- COUNT(*)
- FROM
- 数列1 AS Y
- WHERE
- Y.取引日 <= X.取引日) AS ROW
- FROM 数列1 AS X) AS A;
ひとつ前の値を並べることができたら、比較してUP/DOWN/STAYを判定
- SELECT
- AA.取引日
- , AA.価格
- , SWITCH(AA.価格 > AA.前日, 'UP'
- , AA.価格 < AA.前日, 'DOWN'
- , TRUE, 'STAY') AS DIFF
- , AA.ROW
- FROM (SELECT
- A.*
- , (SELECT
- B.価格
- FROM
- (SELECT
- X.*
- , (SELECT
- COUNT(*)
- FROM
- 数列1 AS Y
- WHERE
- Y.取引日 <= X.取引日) AS ROW
- FROM
- 数列1 AS X) AS B
- WHERE
- B.ROW = A.ROW - 1) AS 前日
- FROM
- (SELECT
- X.*
- , (SELECT
- COUNT(*)
- FROM
- 数列1 AS Y
- WHERE
- Y.取引日 <= X.取引日) AS ROW
- FROM 数列1 AS X) AS A) AS AA
- WHERE
- SWITCH(AA.価格 > AA.前日, 'UP'
- , AA.価格 < AA.前日, 'DOWN'
- , TRUE, 'STAY') = 'UP';
最終処理 GAPをグループ化
qqqqに前項のサブSQLを突っ込みたいところですが、突っ込んで実行させたところACCESSが落ちました。 仕方がないのでクエリqqqqを作成して実行させています。
- SELECT
- MIN(CC.取引日) AS 期間1
- , '~' AS ~
- ,MAX(CC.取引日) AS 期間2
- FROM
- (SELECT
- AAA.取引日
- , COUNT(BBB.ROW) - MIN(AAA.ROW) AS GAP
- FROM
- qqqq AS AAA
- INNER JOIN
- qqqq AS BBB
- ON BBB.ROW <= AAA.ROW
- GROUP BY AAA.取引日) AS CC
- GROUP BY CC.GAP;