「労働基準法」がDXを阻む ~序章・労働基準法の歴史~
どうも、こんぺです。普段はExcelVBAのことについてをちょくちょく書いております。ですが、今回は趣向を変えて「業務改善の私見について書こう!」と思い立ち、すったもんだ色々調べた結果、「労働基準法と最低賃金の変遷」についてまとめることにしました。
自分もまさかこんな記事書くことになるとは思わなかった(´・ω・`)
この記事ができた経緯
タイトルの通り、ある種の「労働基準法に対する批評」を今後数回にわたって書いていこおうと思っているわけですが、「そもそもどうして労働基準法ができたのか?」ということを知らずにする批評はただの「文句」にしかならない、と思い労働基準法の歴史を調べました。なぜ「現行法ではなく歴史なのか?」というと、法改正は「当初の想定と現実の問題のずれを調整するため」に行われるからです。言い換えるならば、労働基準法の変遷を追うと「その当時の労働環境の問題点の変化」が浮き彫りになる、ということです。そして時代背景と共に調べてみると、なかなか面白かったので個人的な感想と共にまとめることにしました。
ちなみに厚生労働省がこの記事よりずっとわかりやすい資料を公開しておりますので、正確なソースに興味がある方は以下のリンクをご覧ください。
労働時間法制の主な改正経緯について
労働基準法の歴史
労働基準法の歴史は古く、2021年で施行から74年になります。そのため数多くの法改正がありますが、今回は「労働時間と賃金」に関わる部分にフォーカスして、時代背景と共に変遷を追っていきたいと思います。
昭和22年(1947年)制定
この頃の時代背景は、第2次世界大戦終戦後2年しかたっておらず、日本はまだGHQによる統治がされている状況、戦後復興真っ只中の世相です。
そしてこの年に日本で起きた出来事として一番重要なことは「日本国憲法の施行」でしょう。
昭和22年(1947)4月|労働基準法が制定される:日本のあゆみ
このサイトによると、「日本国憲法に『法律で定める』と規定したため、それにあたる法律を作った」と読み解けます。実際、1946年11月に日本国憲法公布から「たった5カ月後に公布」というところが、この法律の重要性を物語っていると思います。
当時の労働基準法に盛り込まれた事項の概要は以下のような感じです。
- 労働時間は週48時間
- 女子・年少者の深夜就業禁止
- 労災補償など労働条件の最低基準の設定
- 割増賃金は2割5分以上
- 変形労働時間制
GHQからの「戦時中は人権を無視した不当労働をさせていたに違いない!不眠不休を強いる無制限の不当労働は許しません!」という建前と、日本政府の「戦後復興真っ只中、復興遅れるのも困るから割高の対価支払えば(いくらでも)働かせてOKにして」という本音を考慮したような法律だと感じます。
昭和34年(1959年)
この頃の時代背景としては炭鉱、鉄鋼業界などでストライキが頻発している世相であり、「国家体制VS市民」の構図から移行して「使用者VS労働者」という構図が成立していた時代です。
「使用者が不当に安価な賃金で労働者を雇用することを国が制限する」ことで「国家は市民(労働者)の味方」をアピールする目的もあったかな…と感じます。
昭和62年(1987年)改正
調べてびっくりしましたが、労働基準法制定から40年、労働時間に関わる改正はありませんでした!
(40年の間は安全衛生や労災保険、職業訓練などの労使契約に付帯する事項に関する法改正がメインでした)
この頃の時代背景としてはバブル景気真っ只中、「働くば働くほど稼げる」という状況だったようです…生まれてないから知らんけど…(´・ω・`)
しかし、男女雇用機会均等法の施行やグローバル化が進んだことで「いままでの生活様式」が成り立たなくなっていった時代だと言うことも想像できます。
営業、企画などの「ホワイトカラー」に応募が集中し、製造業における「ブルーカラー」の人材不足が問題になり始めた時期でもあるそうです。
平成5年(1993年)改正
この頃の時代背景としてはバブル崩壊直後。日本経済の停滞、「失われた30年」のはじまりです(´・ω・`)
1987年改正で段階的に短縮した週法定労働時間を40時間に固定することが目玉ですね。
穿った見方かもしれませんが休日労働賃金割増の政令化と、最長1年間変形労働時間制がセットというのが「飴と鞭」を使った「いかにも日本の政策」って感じです。
時代背景を遡ると、休日割増はバブル景気の時休日返上で働いた労働者の人気取りのため、要は「バブル景気の名残」。
一方、変形労働時間制はバブルが崩壊し「休日割増なんて払う余裕ない!けど稼働日減らしたくない!」という企業(雇用主)に対する助け舟…という見方もできなくない、と感じます。
平成10年(1998年)改正
この頃の時代背景としては住専問題、拓殖銀行の破綻、山一證券の廃業などバブル崩壊後の金融問題が顕在化している時代で、終身雇用制や年功序列制といった「日本型雇用」が崩壊し始めたころです。そのような世相の中「裁量労働制の拡大」を図ったところを見るに、「年功序列型から成果報酬型に変革したい(人件費削減を図りたい)」という思惑が見え隠れします。
平成15年(2003年)改正
- 企画業務型裁量労働制の拡大、導入・運用の要件・手続きについて緩和
- 解雇権濫用法理の明文化(解雇権濫用の無効の明文化)
この頃の時代背景は、小泉内閣による郵政民営化、規制緩和、三位一体の改革が行われた時期になります。労働基準法の「企画業務型裁量労働制の拡大」だけではなく「労働派遣法改正による規制緩和」も行われ、後々の日本の労働環境へ大きな影響を与えた結果となっています。
一方で「解雇権濫用の無効」が労働基準法に明文化(現在は労働契約法に移行)されたことも大きな変化だと思います。しかし、
という「直接雇用のリスク増加」と「派遣労働の低コスト化」というコンボ技により「正規雇用から非正規雇用へのシフト」が一気に加速したとも捉えられます。
平成20年(2008年)改正
- 60時間/月を超える時間外労働についての割増賃金率を25%→50%へ引上げ(中小企業は猶予)
- 上記割増賃金の支払いに代えて代替休暇付与を認可
この頃の時代背景は、なんといっても世界金融危機「リーマンショック」が起きた年です。国内の労働事情にフォーカスすると「みなし管理職」問題が明るみになり、東京地裁で「みなし管理職」への残業代支払い命令の判決が下されたり、リーマンショックの影響により所謂「派遣切り」が横行し、年末には「年越し派遣村」が開設されました。
世間一般に「名ばかり管理職」「みなし残業」「雇用の正規、非正規」という考え方が根付き始めた時代だと思います。
平成30年(2018年)改正
- 時間外労働の上限規制の導入
- 中小企業における割増賃金率引上げの施行(平成20年改正における猶予の廃止)
- 有給休暇の消化義務の導入(10日以上の有給休暇の権利を有する労働者について、最低5日の消化をさせること)
- フレックスタイム制における最長清算期間の1か月から3か月への延長
- 特定高度専門業務・成果型労働制(「高度プロフェッショナル制度」)の創設
最も直近の改正であり、読んでいる方々の記憶にも新しいと思います。5年スパンで改正が行われていましたが、民主党政権への政権交代もあってか、実は10年ぶりの改正となっております。
2015年の電通の女性新卒社員自殺というショッキングな一件から「長時間労働」や「パワハラ」が社会問題として改めて大きく取り上げられました。
そのような世論を背景に「時間外労働への上限規制導入」が為されたことが非常に大きなポイントとなります。
事実上青天井だった労働時間にデッドラインが引かれたことで、今までなぁなぁにできた「労働時間管理の責任所在」を雇用主が明確にするよう迫られた点は大きな変化だと感じます。
その一方で「高度プロフェッショナル制度」を創設して多少のガス抜きするあたりは70年経っても日本の組織体質なのか「変化がないなぁ」と感じてしまいます。
最低賃金法について
最低賃金制度の歴史についてもまとめようと思いましたが、なかなか長くなりそうなため割愛(´・ω・`)
興味がある方は 以下の論文の「Ⅴ日本の最低賃金制度について」という部分で非常に丁寧にまとめられておりましたのでご紹介。(結構長い文です)
日本の最低賃金制度について-欧米の実態と議論を踏まえて
ここで言いたかったことは2つです。
(定義)
第二条 この法律において、次の各号に掲げる用語の意義は、当該各号に定めるところによる。
三 賃金 労働基準法第十一条に規定する賃金をいう。
- 賃金の最低限基準である最低賃金は「時間基準で支給すること」が義務付けられている
(最低賃金額)
第三条 最低賃金額(最低賃金において定める賃金の額をいう。以下同じ。)は、時間によつて定めるものとする。
労働人口推移との比較
人口のデータについては以下のサイトを参考にしました。
統計情報|労働政策研究・研修機構(JILPT)
人口推移のグラフを見ると、1990年あたりから15~65歳以下の人口「生産年齢人口」が下降曲線に入り、現在まで減少の一途をたどっています。
www.jil.go.jp
その頃はちょうど、40年続いた「48時間労働の短縮」という大きな改正が行われた1987年改正にあたります。男女雇用機会均等法の施行もこのあたりというのは、世界的な風潮に押された点も多分にあったと思いますが、バブル景気も相まって「労働力の頭数確保」が当時から喫緊課題だったからだと考えられます。しかし男女雇用機会均等法は「男はとにかく仕事一本、女は家を守る」といった戦後40年以上続いた生活様式、価値観をひっくり返す法律であり、従来の労働時間では「生活が成り立たない」ということで労働時間の短縮に繋がったのかもしれません。
しかし、そんな配慮もむなしく1990年以降、労働力人口も緩やかな減少傾向のまま回復の兆しもない状況が現在まで続いています。
www.jil.go.jp
それもあってか1990年以降は「働き方のバリエーションを増やす」ための法改正が繰り返されています。「画一的な労働」から「多種多様な労働」を容認せざるを得ない労働市場の状況になったといえます。しかし2005年の「出生率1.26」という数字をたたき出し、いよいよ「日本の将来」すら危ういという状況に現在進行形でなっています。「いかに多く働かせるか」という「経営者・企業側」の視点だけでは破綻する、ということを歴史が証明してしまったと言えるかもしれません。
それもあってか、「割増賃金の一部増加」「割増賃金に変えての代替休暇付与の容認」という「労働者寄りの改正」がなされています。
そして直近の2018年改正になります。これらの経緯を知ってからだと、「働き方改革」でついに「働かせない≒休ませる」という「労働者側」の視点を重視した法改正がなされたのではないかと個人的に感じます。
今回の感想と次回について
労働基準法の変遷を調べて稚拙な観点からではありますが、考えたことや感じたことを書きました。変遷を調べることは「日本の労働観」を振り返るという点で正解でした。
しかし書いた後、働き方改革までの労働基準法、延いては日本の労働観は「第一次産業革命後のイギリスと大差ない労働価値観」だったのかもしれない、と感じました…
要は「成果を多く出すには頭数と時間をたくさん注ぎ込めばいい」という労働生産性皆無の価値観、「労働者の生活という観点がすっぽり抜けている」とも言えます。
半世紀以上、人口の大半を占める労働者の生活を無下にしたら、そりゃ国全体衰退するわな(´・ω・`)
そんな弱り目の中、コロナ禍により今までの生活様式から一変を余儀なくされ、大変な思いをされている方も多く出ています。その一方、「日本の労働観の強制アップデート」ができるまたとない機会が到来しているのも事実だと思います。この機会を逃したら、冗談抜きで「失われた1世紀」になりかねないと感じます。
そして、その機会をもしかしたら「労働基準法」「最低賃金法」が阻む原因になるのでは?という内容を次回に書きたいと思います。
長文失礼しましたm(_ _)m
ExcelVBAの一工夫:配列の繰り返し処理について
どうも、こんぺです。
今回、VBAの配列について小技とも言えないような「ちょっとした一工夫」をご紹介します
配列の繰り返し処理について
VBAにおける配列の使い方や書き方は様々なサイトで取り扱われていると思われますので、割愛させていただきます。
配列と繰り返し処理の組み合わせ技は強力ですが、慣れないうちは、
- Do Loopの終わりがわかりにくい
- For Next は繰り返し処理後イテレーター変数は「繰り返した回数+1」になっている
- カウンタ変数をカウントアップ(ダウン)するタイミングがいまいちわからない
とロジックエラーが起きやすい部分でもあると思います。
しかし、ちょっとしたひと工夫で「一気にわかりやすいコードに変わった」経験をしたのでご紹介します。
テストコード
- 1~20までの整数rndをランダムで決め、
- 1~rnd まで順に2乗し、配列に格納、
- 最後に配列の内容をイミディエイトウィンドウに表示
という処理をしています。
Sub test() 'cnt(=ループ処理の回数)を1~20までの整数からランダムで選出 Dim rnd As Long rnd = Int(WorksheetFunction.RandBetween(1, 20)) 'カウンタ変数とDoLoopを用いた動的配列の処理 Dim arr() As String Dim cnt As Long Dim i As Long Do cnt = cnt + 1 ReDim Preserve arr(1 To cnt) As String arr(cnt) = Str(cnt ^ 2) Loop Until cnt = rnd '配列内数値の確認 Debug.Print "要素数:" & cnt, Join(arr, ",") End Sub
解説
今回の工夫した箇所は以下の部分
Do cnt = cnt + 1 ReDim Preserve arr(1 To cnt) As String 繰り返し行いたい処理 Loop Until cnt = 繰り返したい回数
非常に短いですが、工夫としては
- 処理の「前」にカウンタ変数をカウントアップする
- 配列に動的配列を用いる
- 「ReDim Preserve」で処理結果を格納する要素を直前に「追加」する
- 要素数は「必ず『1』から要素が始まる」ようにする
- 条件分岐に「Until」を使う
といったことが挙げられます。
これにより
- 「配列の要素数が足りない」というエラーを除去できる
- ループを抜けたタイミングは「カウンタ変数=繰り返し処理回数」でわかりやすく、繰り返し処理後のロジックエラーを起こしにくい
- 要素数が「1」から始めることでめインデックス「0」を考慮しなくてよいため、後々Rangeに転記しやすい
など、「後々エラーの原因になりやすいポイント」を未然に解消してくれます。
おわりに
簡単ではございますが、「コーディングにおける一工夫」をご紹介させていただきました。
この書き方のアイディアを知るまで、私は「処理後にカウントアップ」していました。そのため、繰り返し処理後にロジックエラーを起こして予期しない動作になることが度々あり、「エラー回避するためのコード」を頭をひねって追加していました。しかし、この一工夫でその労力は「ほぼ0」になりました…
業務効率だけではなく、リーダブルコーディングで「コーディング効率」も上げていかねば…と思った次第です。
最後にお詫びです
以前、VBA勉強会に登壇させていただいたときに行ったリファクタリングをしたコードをすっかりアップし忘れていました。
しかし、動作確認をしたところバグが見つかってしまったので修正したのちアップします(;´・ω・)
セルコメントがあるセル番地とコメント内容を抽出するサブルーチン
セルコメントを別シートセル番地と内容を抽出し、セルコメントを削除するコード作ったので、備忘録ついでに投稿します。
※補足※サブルーチンのためこのコードのみでは動作しません。万が一コピペして利用するようなことがあればご注意ください。
コメントのセル番地と内容を抽出し、新規シートへ転記する
Sub CommentOut(wsInput As Worksheet) Dim trg As Range Dim arr() As Variant Dim cnt As Long ReDim arr(1 To 2, 1 To 1) As Variant ' コメントセルに関する情報を二次元配列へ格納 For Each trg In wsInput.Range("A1").CurrentRegion If TypeName(trg.Comment) = "Comment" Then cnt = cnt + 1 ReDim Preserve arr(1 To 2, 1 To cnt) arr(1, cnt) = trg.Address arr(2, cnt) = trg.Comment.Text ' trg.Comment.Delete End If Next ' コメント抽出用シートの作成 Worksheets.Add after:=Sheets(Sheets.Count) Dim wsOutput As Worksheet Set wsOutput = Sheets(Sheets.Count) wsOutput.Name = "抽出コメント" wsOutput.Range("A1:B" & cnt) = WorksheetFunction.Transpose(arr) End Sub
メッセージボックスで検索セル数、コメント付きセル数、セルコメント割合を集計・表示する
Sub CommentsCounter(wsInput As Worksheet) Dim trg As Range, cnt(1) As Long, Ans As Long For Each trg In wsInput.Range("A1").CurrentRegion cnt(0) = cnt(0) + 1 If TypeName(trg.Comment) = "Comment" Then cnt(1) = cnt(1) + 1 End If Next Ans = cnt(1) * 100 / cnt(0) MsgBox " 全検索セル数:" & cnt(0) & vbLf & "内 コメント付:" & cnt(1) & vbLf & " コメント率:" & Ans & "%" End Sub
VBA 100本ノックNo91
お題
#VBA100本ノック 91本目
— エクセルの神髄 (@yamaoka_ss) 2021年2月19日
「勤怠」に複数月の勤怠データが入っています。
9:00~18:00の休憩1hの実動8hです。
id・月ごとに残業時間を算出し「残業」に一覧出力。
残業:単純に1日8hを超える時間数。ただし9時前出勤は9時とする。
日々1分単位、月間30分単位で切り捨て。
※時間計算の練習問題です。 pic.twitter.com/ROf5vsuL7N
解答コード
Class1 コード(クラスモジュール)
Option Explicit Private rest As Integer Private St1_ As Double Private fin1_ As Double Private WT_ As Long Private Ded_ As Long Private NT_ As Long Private Ovt_ As Integer 'Letプロパティの一括設定 Sub SetProp(ByVal new_st1 As Double, ByVal new_fin1 As Double) rest = 60 '休憩時間 60分 If new_st1 < TimeSerial(9, 0, 0) Then St1_ = 9 / 24 '9時のシリアル値 Else St1_ = new_st1 End If fin1_ = new_fin1 WT_ = WorkTime Ovt_ = OverTime NT_ = Night End Sub '労働時間の計算 Private Function WorkTime() As Long Dim WT As Double WT = fin1_ - St1_ WorkTime = WorksheetFunction.RoundDown((WT) * 1440, 0) - rest End Function '残業時間の計算 Private Function OverTime() As Integer If WT_ > 480 Then OverTime = WT_ - 480 Else OverTime = 0 End If End Function '深夜時間の計算 Private Function Night() As Long Dim i As Long, dbStr As Double, dbFin As Double, dbNT As Long dbStr = St1_ If fin1_ >= 1 Then dbFin = fin1_ - 1 Else dbFin = fin1_ End If '始業時刻の条件分岐 '始業時刻が0時~5時までかつ、 If dbStr < TimeSerial(5, 0, 0) Then '終業時刻が0時~5時までの場合 If dbFin < TimeSerial(5, 0, 0) Then dbNT = WorksheetFunction.RoundDown((dbFin - dbStr) * 1440, 0) '終業時刻が22時~24時までの場合 ElseIf dbFin > TimeSerial(22, 0, 0) Then dbNT = WorksheetFunction.RoundDown(((5 / 24 - dbStr) + dbFin - 22 / 24) * 1440, 0) '終業時刻が5時~24時までの場合 Else dbNT = WorksheetFunction.RoundDown((5 / 24 - dbStr) * 1440, 0) End If '始業時刻が22時~24時までかつ、 ElseIf dbStr >= TimeSerial(22, 0, 0) Then '終業時刻が0時~5時までの場合 If dbFin < TimeSerial(5, 0, 0) Then dbNT = WorksheetFunction.RoundDown((dbFin + (1 - dbStr)) * 1440, 0) '終業時刻が22時~24時までの場合 ElseIf dbFin > TimeSerial(22, 0, 0) Then dbNT = WorksheetFunction.RoundDown(((dbFin - dbStr) + dbFin - 22 / 24) * 1440, 0) '終業時刻が5時~24時までの場合 Else dbNT = WorksheetFunction.RoundDown((5 / 24 + (1 - dbStr)) * 1440, 0) End If '始業時刻が8時~22時までかつ、 Else '終業時刻が0時~5時までの場合 If dbFin < TimeSerial(5, 0, 0) Then dbNT = WorksheetFunction.RoundDown((dbFin + 2 / 24) * 1440, 0) '終業時刻が22時~24時までの場合 ElseIf dbFin > TimeSerial(22, 0, 0) Then dbNT = WorksheetFunction.RoundDown((dbFin - 22 / 24) * 1440, 0) '終業時刻が翌日5時~8時までの場合 ElseIf dbFin < dbStr Then dbNT = 420 '終業時刻が8時~24時までの場合 Else dbNT = 0 End If End If Night = dbNT End Function ’プロパティ取得の設定 Property Get 勤務時間() As Double 勤務時間 = WT_ End Property Property Get 深夜時間() As Double 深夜時間 = NT_ End Property Property Get 始業時刻() As Double 始業時刻 = St1_ End Property Property Get 終業時刻() As Double 終業時刻 = fin1_ End Property Property Get 残業時間() As Integer 残業時間 = Ovt_ End Property
Module1 コード(標準モジュール)
Sub ノック91本目() Dim ID As Integer Dim Dic_ID As Object: Set Dic_ID = CreateObject("Scripting.Dictionary") Dim cnt_ID As Long Dim y As Integer, m As Integer Dim 年月 As String Dim Dic_年月 As Object: Set Dic_年月 = CreateObject("Scripting.Dictionary") Dim cnt_年月 As Long Dim i As Long 'ID,年月に関する連想配列生成と二次元配列の要素数決定 For i = 2 To Sheet1.Cells(Rows.Count, 1).End(xlUp).Row ID = Sheet1.Cells(i, 1).Value 年月 = Nengetsu(Sheet1.Cells(i, 2).Value) If Not (Dic_ID.exists(ID)) Then cnt_ID = cnt_ID + 1 Dic_ID.Add ID, cnt_ID End If If Not (Dic_年月.exists(年月)) Then cnt_年月 = cnt_年月 + 1 Dic_年月.Add 年月, cnt_年月 End If Next 'ID,年月ごとの残業時間集計 Dim obj As Class1 Dim StartTime As Double, FinishTime As Double Dim arr() As Variant ReDim arr(1 To cnt_ID, 1 To cnt_年月) As Variant For i = 2 To Sheet1.Cells(Rows.Count, 1).End(xlUp).Row ID = Sheet1.Cells(i, 1).Value 年月 = Nengetsu(Sheet1.Cells(i, 2).Value) StartTime = Sheet1.Cells(i, 3).Value FinishTime = Sheet1.Cells(i, 4).Value Set obj = New Class1 obj.SetProp StartTime, FinishTime arr(Dic_ID(ID), Dic_年月(年月)) = arr(Dic_ID(ID), Dic_年月(年月)) + obj.残業時間 Set obj = Nothing Next '残業シートへの転記 Dim j As Long, k As Long, r As Long Dim Keys_ID As Variant: Keys_ID = Dic_ID.keys Dim Keys_年月 As Variant: Keys_年月 = Dic_年月.keys r = 1 For j = 1 To cnt_ID For k = 1 To cnt_年月 r = r + 1 Sheet2.Cells(r, 1).Value = Keys_ID(j - 1) Sheet2.Cells(r, 2).Value = Keys_年月(k - 1) If arr(j, k) Mod 60 < 30 Then Sheet2.Cells(r, 3).Value = "'" & arr(j, k) \ 60 & ":00" Else Sheet2.Cells(r, 3).Value = "'" & arr(j, k) \ 60 & ":30" End If Next Next End Sub '年月文字列を生成する関数 Function Nengetsu(ByVal d As Date) As String Nengetsu = Year(d) & Month(d) If Month(d) > 9 Then Nengetsu = Year(d) & Month(d) Else Nengetsu = Year(d) & "0" & Month(d) End If End Function
振り返りと感想
完成まで3時間。以前に近いものを作った経験があったのでそのノウハウを応用。
表記は文字列で扱っており手抜き…本来はFormat関数やNunberFormat関数で整形するのが理想だと思います。
始業時刻、終業時刻から様々なデータを生成できるのでクラスを活用しています。
そのため、インスタンスのプロパティを変更するだけで、総労働時間や深夜時間を切り替えて集計できます。
個人的な時間計算における時刻データの取り回しは
- 日付型ではなくシリアル値(Double型)で取得
- シリアル値のまま時刻計算
- 端数処理は分単位に変換してから取り回し([シリアル値] ×1440)
- 最後に時刻表記に変換
という方法で基本的に行っています。
回りくどい方法ですが、日付型はシリアル値が1以上になると「時刻のみ」から「日付+時刻」で取り扱われるので直感的に扱いづらいためこのような変換を行っています。
マスタ上の時刻標記が[h]:mm:ss型であるため、労働時間の算出は非常にやりやすかったです。マスタの記述ルールの重要性を実感しました。
日付をまたぐ条件分岐(出題違反以外ですが、今回でいえば深夜時間の算出)はh:mm:ss型にも対応できるように、かなり面倒な処理をしています。
VBAの悩みはVBAerに聞け! 第7回 1次会 話題のメモ帳
関数について
やまとさんが関数(Function)を使う理由
- コーディングで楽をしたいため
- メインのプロシージャが何やっているかがわかりやすい
関数を作るとは?
Worksheet関数を作れる?
条件があるものの、標準モジュールで作成したFunctionプロシージャ
ADD2とするとエラー→ADD列2行目の参照と認識してしまった
参照とみなせる関数は作れない
FunctionとSubの違い
sub:プロシージャ名は値を返さない
Function:プロシージャ名自体が値を返す
「:=」とは?
:= :関数の名前付き引数を指定して値を代入する。引数の順番を入れ替えても関数が機能する
= :変数へ値を代入する
引数のヒントを出すショートカット
Ctrl+i (りゅうりゅうさん)
- 引数のヒントをコピペするショートカットなかった?
ワークシート関数の引数入力ショートカット
Ctrl+Shift+A
→自作関数も同じく出る
ByVal、ByRef
ByVal:引数で渡した変数が呼び出し先の影響を受けない、省略不可
- ByValでしかできないこと
分割した先のプロシージャ内で引数を変数に代入しなくてもよい
ByRef:引数で渡した変数が呼び出し先の影響を受ける、省略可
- ByRefでしかできないこと
一つの関数で渡した複数の引数に対して複数の値を返してほしいとき
その他
変数日本語派?
- やまとさんの考え
業務で使うものは日本語、自分で使うものは英語
→以前モジュール名日本語でバグったことがある
goto gosubの違い
gotoは戻る場所を自分で管理する必要がある
→どこに戻るかわかりくい
gosubはreturnで元の処理に戻れる
- エラー処理の共通化、特定の計算値算出にjika便利(ほえほえさん)
- 「変数を共有して他から呼べない処理」という意味でスーパーPrivate sub と思っていい(和風スパゲティさん)
VBA 100本ノックNo11~14
#VBA100本ノック 11本目
— エクセルの神髄 (@yamaoka_ss) 2020年10月29日
11…同じ数字が並んでいる、これは結合したのか、、、
画像のようにシートにはところどころにセル結合があります。
これは放置しておく訳にはいきません。
セル結合されているセルには、メモ(旧コメント)で警告文を出しましょう。
※シートは任意、警告文はご随意に pic.twitter.com/Vi5HoXJtDy
Sub ノック11本目() With Worksheets("セル結合") Dim r As Long: r = .Cells(Rows.Count, 1).End(xlUp).Row Dim c As Long: c = .Cells(1, Columns.Count).End(xlToLeft).Column Dim i As Long, j As Long For i = 1 To r For j = 1 To c If .Cells(i, j).MergeCells Then .Cells(i, j).AddComment.Text "セル結合…しましたね…(´・ω|" Next Next End With End Sub
#VBA100本ノック 12本目
— エクセルの神髄 (@yamaoka_ss) 2020年10月30日
A1から始まる表範囲のC列に金額が入っています。
しかし、ところどころに結合されたセルがあります。
セル結合を解除し、入っている金額を整数で均等に割り振ってください。(2枚目画像)
端数処理方法は任意とします。
※結合セルには正の整数しか入っていません。 pic.twitter.com/AiRgfucnRx
Sub ノック12本目() With Worksheets("セル結合") Dim r As Long: r = .Cells(Rows.Count, 1).End(xlUp).Row Dim c As Long: c = .Cells(1, Columns.Count).End(xlToLeft).Column Dim i As Long, j As Long, k As Long, md As Integer Dim trg As Range Dim amount As Long '金額 For j = 1 To c For i = 1 To r If .Cells(i, j).MergeCells Then 'セルの結合判定 Set trg = .Cells(i, j).MergeArea trg.UnMerge md = .Cells(i, j).Value Mod trg.Rows.Count '余りの計算 If md = 0 Then '割り切れる場合 amount = .Cells(i, j).Value / trg.Rows.Count For k = 1 To trg.Rows.Count '結合範囲のループ処理 .Cells(i + k - 1, j).Value = amount Next Else '端数が出る場合 amount = WorksheetFunction.RoundDown(.Cells(i, j).Value / trg.Rows.Count, 0) For k = 1 To trg.Rows.Count '結合範囲のループ処理 Select Case k Case Is <= md '余りの配賦 .Cells(i + k - 1, j).Value = amount + 1 Case Else .Cells(i + k - 1, j).Value = amount End Select Next End If End If Next Next End With End Sub
#VBA100本ノック 13本目
— エクセルの神髄 (@yamaoka_ss) 2020年10月31日
選択セル(Selection:複数範囲あり)の文字列に「注意」という文字があった場合は、その「注意」の文字だけを"赤の太字"に設定してください。
セル以外(図形等)が選択されている場合は何もせずに正常終了するようにしてください。 pic.twitter.com/UqvvJu8GFm
Sub ノック13本目() Dim arr As Variant, Target As Range If TypeName(Selection) = "Range" Then Set Target = Selection For Each arr In Target Dim i As Long Dim start As Integer: start = 1 Do If Not (InStr(start, arr.Value, "注意") = 0) Then arr.Characters(InStr(start, arr.Value, "注意"), 2).Font.Color = RGB(255, 0, 0) start = InStr(start, arr.Value, "注意") + 2 End If Loop Until InStr(start, arr.Value, "注意") = 0 Next End If End Sub
#VBA100本ノック 14本目
— エクセルの神髄 (@yamaoka_ss) 2020年11月2日
客先へ送付するブックを作成します。
シート名に「社外秘」の文字が含まれるシートを削除してください。
他のシートは計算式を消して値だけにしてください。
※シート間参照の数式あり。
※条件付き書式・入力規則は未使用。
※対象はアクティブブックで構いません。 pic.twitter.com/qt5skqdfYo
Sub ノック14本目() Dim wsName As String Dim ws As Worksheet Dim cnt As Long For Each ws In Worksheets wsName = ws.Name If Not (InStr(wsName, "社外秘") = 0) Then Application.DisplayAlerts = False Worksheets(wsName).Delete Application.DisplayAlerts = True cnt = cnt + 1 End If Next MsgBox cnt & "枚のコードを削除しました" End Sub
振り返りと反省
- セル結合に関わるメソッド(MergeCells、MergeAreaなど)をうまく使いこなせていない
- 結合セルのカウントと端数処理が回りくどい気がする
- Charactersプロパティ使ったのが久々。Value(値)とCharacters(文字列オブジェクト)の違いをしっかり理解する
- InStrは便利なので使いこなせるように意識して使ってみる
VBAの悩みはVBAerに聞け! 第6回 話題のメモ帳
2021/2/12 20時から行われた VBAの悩みはVBAerに聞け! に今回も参加しました。
主催者のしゃあさんも議事録を作っております。
今回の登壇者である「あこ」さんが作成したマクロもダウンロード可能ですので、コイらもぜひご覧ください。
note.com
聞き取れた範囲ですが以下にまとめました。
話題抜粋
SheetsコレクションとWorksheetsコレクションの違い
Worksheets:ワークシートのみのコレクション。インデックスで指定してもワークシートのみ指定される。
Sheets:ワークシート、グラフシート、Excel4.0マクロなども含むコレクション。
SheetsコレクションからWorksheetオブジェクトを指定する場合、インデックスで指定するとワークシート以外のシートも指定される
→グラフシートなどが挿入されていると想定外の挙動になる可能性あり
sleep、wait、doevents の違い
ループ処理の際、一時停止の方法として利用される手法として上記の3つがあるが、その違いは何なのか?という質問から
ほえほえ先生の回答
sleep: プロセスが停止→バックグランドも停止
wait:VBAスレッドが停止→バックグラウンドは動作する
doevent: 実行権の放棄
Shell,VBSの使い方
Shell関数:Shell で起動したプログラムが、他のプログラムが非同期に実行させる関数
(VBSは聞き逃しました…すみません)
VBEからMicrsoftDocsの開き方
キーワード上にマウスカーソルを置き、F1キー(ヘルプ)を押す
「””」と「Null」の違い
””:空文字。
Null:有効な数値ではないことを示す値
チャットで挙げられていた例え
- 「””」はトイレットペーパーの紙がない状態
- 「Null」はそもそもトイレがない
感想
今回も非常に勉強になりました!
Shell関数やVBSは触れたことがまだないので、もっと勉強が必要だなぁ…と実感。
しっかり理解できていないことが多いから、ブログでアウトプットしながら整理したいです。