サブフォームに通番を表示するためのレコードソース
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;