uso

雑記いろいろ
★書いてある内容に保証は一切ありません。
 ご自身で判断をしてください。

[SQL]SqlServerの文字列検索

2020-09-16 13:05:42 | work
■久しぶりにハマった

・SQLServerのデフォルト設定では文字列検索はけっこう曖昧
 スペースの全半角を区別しないとか、大文字小文字を区別しないとか
・この辺のサイトを参考にさせていただきました
 https://johobase.com/sqlserver-where-collate/
 https://www.projectgroup.info/tips/SQLServer/MSSQL_00000005.html
・MS公式、SQL照合順序(COLLATE)について
 https://docs.microsoft.com/ja-jp/sql/relational-databases/collations/collation-and-unicode-support?view=sql-server-ver15

・「文字列」の検索が曖昧なのは、SQLとしてはいいことらしい(今までそう言うケースに遭遇したことはないが・・・)
・なので文字列の重複チェックするときとか気をつけないと地雷を踏む

■チェックする方法とか対策

・DBデフォルトの照合順序を確認
 SELECT SERVERPROPERTY('collation')
・検索時にCOLLATEを変える場合
 select hoge1, hoge2 from hoge where hoge1 COLLATE Japanese_Bin like 'hogehoge  '
※「=」ではなく「LIKE」検索しないと末尾のスペースが考慮されない事象にも遭遇
 https://blog.engineer-memo.com/2014/12/20/sql-server-%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E5%8F%AF%E5%A4%89%E9%95%B7%E6%96%87%E5%AD%97%E5%88%97%E3%81%AE%E6%9C%AB%E5%B0%BE%E3%81%AE%E7%A9%BA%E7%99%BD%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6/

末尾スペース無視もSQL的にはOKらしいが、LIKEは大丈夫というのも違和感。。
もしかしたら、カラムの型によって末尾SPは挙動が違うかもしれない。今回遭遇したカラムは「nvarchar」。
型によってはスペース埋めすると言う話くらいは聞いたことある…。

SQLServer罠多すぎ…
自分が知らなすぎるから罠にはまるのか…

[work]質とスピード

2020-07-13 00:52:52 | 日記

■以下のサイト内容まんま

ソフトウェア開発の「品質vs.スピード」、本当は何を犠牲にしているのか【デブサミ2020】
https://codezine.jp/article/detail/12245

プロジェクトマネジメントにはQCD(Quality:品質、Cost:コスト、Delivery:納期)という概念があり、
トレードオフの関係になると言われている。
しかし、ソフトウェア開発においては逆の効果をもたらす

■本当に犠牲にしているのは、品質ではなくシステムの保守性

開発に与えられた「時間」に対して「予算」「品質」「スコープ」が限られている場合、どれを犠牲にすべきかという問題だ。
多くの現場では、品質を犠牲にして、スピードを得ようとする。

しかし、品質を犠牲にすれば短期的にはスピードが得られるが、中期的には逆効果になり、長期的には致命傷になる。
本当は何を犠牲にしているのか、そして、この短期・中期・長期とは、どのくらいの期間を指すのか?

■品質とは(補足)
操作性や信頼性など「○○性」がつく言葉であらわされる物が対象。
英語では「Usability」や「Reliability」など、末尾に「ility」がつく多くの言葉が該当する。

ソフトウェアの品質
・お客様から見える外部品質
・見えない内部品質

内部品質を作り込んだ結果として、外部品質として定義される特性の実現に近づくことができる。
内部品質は結果ではなく原因であり、良いソフトウェアが備えているべきものだ
(『レガシーコードからの脱却』から引用)。
品質を犠牲にしてスピードを得ようというとき、この内部品質の保守性(Maintainability)や柔軟性(Flexibility)を犠牲にしている

■保守性を犠牲にしても、中長期的にスピードは上がらない
保守性の低さという技術的負債が蓄積された結果、いろんなところが裏で手をつないで、足を引っ張りあっい、
ひとつひとつの変更に余計な時間がかかるようになっている。
その結果、単位時間あたりの生産量は下がる。つまり、保守性を落とした結果、スピードも落ちてしまう。

■スピードを落として時間をかけたら、保守性は向上するか?
技術力のある人はある程度急いで作ったとしても一定以上の品質のコードを書くし、
意図的に品質を落としたとしても速度はあまり上がらない。
逆に、技術力が高くない人が時間をかけて作ったとしても、その人の技術力以上の品質のコードは書けない

保守性とスピードは、トレードオフの関係ではない。

■コードの品質を高く保っていたからこそスピードは速くなる
むしろ品質を高めることで、デリバリーが高速になることが多い。
低品質を受け入れることで、プロジェクトが速くなることはない。
高品質を要求することで、プロジェクトが遅くなることもない。
むしろ品質を高めることで、デリバリーが高速になることが多い。
品質基準を下げてしまうとデリバリーが遅くなり、予測できなくなってしまう。

コードの品質を高く保っていた「からこそ」速くなると言える。

■『質vs.スピード』という二律背反の関係は、局所的なものでしかない。
大域的には、片方を犠牲にした場合、知らぬうちにもう一つも犠牲にしている。

品質が劣化すれば、リードタイムが増加する。
品質は悪いと基本的に手戻りを生む。
手戻っている時間は学びを生まない時間となる。
品質を下げるという判断が、学びの速度低下を許すことになる。

「品質を捨てて速度を上げよう」は、品質が劣化して手戻りが発生するだけで、結局はリードタイムの増加に跳ね返る。
そして、リードタイムが増加すると仮説検証プロセスも回らなくなる。


■Facebookの元エンジニアであるEvan Priestley氏の言葉「本当の関係」
 内部品質がスピードを生み
 スピードが学びのループを生み
 学びのループが外部品質を生み
 外部品質が競争力を生み
 競争力が売り上げを生み
 売上が内部品質を育む

■どうやって個々人の品質とスピードを上げていくのか?
品質とスピードを上げる方法が、個人のレベルに依存しているとしたら、どうやって個々人の品質とスピードを上げていくのか。
これには正解はないが、「ソフトウェアの開発に最初から最後まで関わるという経験がとても重要だ」(Evan Priestley氏のコメント)
いろいろなフィードバックを自分で受け止めて、設計者として能力を上げることが決定的に重要だと思うと述べた。

■品質の効果は、1か月以内にあらわれる
およそ4回で手動テストと自動テストのコストが逆転する。
「内部品質への投資の損益分岐点は1か月以内に現れる」(マーティン・ファウラー)
1か月以内であれば、内部品質への投資の受益者は自分たち自身である。
エンジニアとしてのプライドやモラルのために品質に投資するのではなく、自分たちの損得の話になる。

■最後に
品質と速度についてトレードオフを意識するとき、実際には何と何を天秤にかけているのか
「若者が育つ機会」
「新技術の調査」
「多様性の確保」
が犠牲になっているのではないか

docker

2020-03-28 17:49:22 | 日記
敷居が高いけど、勉強してみた。
dockerというよりdocker-composeがメイン。楽だし。

ここを参考にvueの環境を作ってみた際のメモ。
https://qiita.com/rh_taro/items/ca08b930f704275286a4

------vue環境作る

===Dockerfile
FROM node:13.12.0-alpine3.10

WORKDIR /usr/src/app

RUN apk update && \
npm install --no-optional -g @vue/cli

★バージョンはDocker Hubで探す
 https://hub.docker.com/_/node/
 alpineの最新にしてみた(軽いらしい)
★--no-optionalを入れないとWARNがいっぱい出る、npm×Linuxの問題?
 ↓は出てしまうが、少ないしOKとしておく・・・、大量には出ない
 npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@^1.2.7 (node_modules/@vue/cli/node_modules/chokidar/node_modules/fsevents):
 npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.12: wanted {"os":"darwin","arch":"any"} (current:{"os":"linux","arch":"x64"})


===docker-compose.yml
version: '3'
services:
app:
build: .
ports:
- 9050:8080
privileged: true
volumes:
- ./app:/usr/src/app
tty: true
stdin_open: true
command: /bin/sh

ビルド
docker-compose build

実行
docker-compose up -a

作ったコンテナに入ってsh
docker-compose exec app sh

vue cliでプロジェクト作る
vue create .
→質問は適時必要なものを答える

時間がかかるがappフォルダに色々入るので、
yarn serve

ホストに戻って
http://localhost:9050
→vueの画面出てくると成功

------途中でわからなくて調べたこと色々
起動方法について(dockerコマンドはまた別モノ)
http://docs.docker.jp/compose/faq.html
docker-compose up
docker-compose run -it
docker-compose start
→up ・ run ・ start の違いは何ですか?

一般的には docker-compose upを使う。
docker-compose run コマンドは「ワンオフ」(one-off;1つだけ、偶発的) または「アドホック」(adhoc;臨時)なタスクの実行に使います。
docker-compose start コマンドは既に作成済みのコンテナの再起動には便利です。しかし止まっているコンテナを起動するだけであり、新しいコンテナは作成しません。

コマンド基本色々
http://docs.docker.jp/get-started/part2.html
チートシート
docker build -t friendlyname . # このディレクトリ内にある DockerCile でイメージ作成
docker run -p 4000:80 friendlyname # "friendlyname" の実行にあたり、ポート 4000 を 80 に割り当て
docker run -d -p 4000:80 friendlyname # 同じですが、デタッチド・モード
docker container ls # 全ての実行中コンテナを表示
docker container ls -a # 停止中も含めて全てのコンテナを表示
docker container stop <hash> # 指定したコンテナを丁寧に停止
docker container kill <hash> # 指定したコンテナを強制シャットダウン
docker container rm <hash> # マシン上から指定したコンテナを削除
docker container rm $(docker container ls -a -q) # 全てのコンテナを削除
docker image ls -a # マシン上の全てのイメージを表示
docker image rm <image id> # マシン上の特定のイメージを削除
docker image rm $(docker image ls -a -q) # マシン上の全てのイメージを削除
docker login # CLI セッションで Docker の認証を行いログイン
docker tag <image> username/repository:tag # レジストリにアップロードする <image> にタグ付け
docker push username/repository:tag # タグ付けしたイメージを送信
docker run username/repository:tag # レジストリにあるイメージを実行

未使用イメージ一括削除
docker rmi `docker images -q`

npmで大量のwarnが出る
https://docs.npmjs.com/cli/install
→解決できず、とりあえず--no-optional入れて逃した
→少し調べたら、同じようなことを調べているサイトがあった
 https://haiju.hatenablog.com/entry/2018/04/23/134809
 MacOS以外にnpmをインストールすると出るらしい・・

pythonの勉強

2019-11-01 14:44:14 | work
久しぶりに勉強したら、3.8になってたorz


Windowsの軽量版、こっそり使いたいけど勝手が違う。
python-3.8.0-embed-amd64.zip

ここのサイトを見ながら使えるように(pandas動く)したい
https://qiita.com/mm_sys/items/1fd3a50a930dac3db299


■インストール?

解凍、exeがあるとこでpython起動→インタラクティブ
終了quit()もexit()もエラー

exitする方法(まさかこんなことに困ると思わなかった)
https://takamaruo.hatenablog.com/entry/2018/10/09/232304

from sys import exit
exit()

■pip使えるようにする

python.exeと同じ場所にあるpython38._pthを編集
 #import site → コメント解除

get-pip.pyを取得しpython.exeと同じ場所に配置
https://bootstrap.pypa.io/get-pip.py

コマンドプロンプトを起動し、一時的に以下のパスを通す(こっそりだから)
path →確認
set path=%path%;python.exeがある場所\Scripts

python get-pip.py
→パスを通してないとWarning出る
 ※コマンドは必ずpython.exeがあるところですること

pipがインストールされたか見る
python -m pip list

Package Version
---------- -------
pip 19.3.1
setuptools 41.6.0
wheel 0.33.6

ここにpipが入った
python.exeのあるフォルダ\Scripts\pip.exe
pipでインストールを試す
pip install numpy

ここにnumpyが入る
python.exeがあるフォルダ\Lib\site-packages\numpy

本命のpandas入れる
pip install pandas

pipのインストール一覧を見る
pip list

Package Version
--------------- -------
numpy 1.17.3
pandas 0.25.2
pip 19.3.1
python-dateutil 2.8.0
pytz 2019.3
setuptools 41.6.0
six 1.12.0
wheel 0.33.6


こそこそやってるつもりだが、
C:\Users\ユーザー\AppData\Local\pipがあり、キャッシュフォルダとかできてしまう
むずかしい。。


■ばれないようにドロン
python.exeなどを入れたフォルダごと消す


ここからはpandasとエクセルの話


■エクセルをpandasで読み取る

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.read_excel.html

xlrdがいるのでインストール
pip install xlrd

エクセル準備
test.xlsx
hoge1 hoge2 hoge3
1 ほげ 2019-11-01
2 ふが NaT
3 NaN 2019-11-01

以下実行

>>> import pandas as pd
>>> df = pd.read_excel('test.xlsx')
>>> print(df)
hoge1 hoge2 hoge3
0 1 ほげ 2019-11-01
1 2 ふが NaT
2 3 NaN 2019-11-01

こんな感じ。

■pandasのDataFrameについてもう少し

カラムの一覧取得
>>> print(df.columns)
Index(['hoge1', 'hoge2', 'hoge3'], dtype='object')

カラムのデータ型を取得
>>> print(df.dtypes)
hoge1 int64
hoge2 object
hoge3 datetime64[ns]
dtype: object


型を指定してエクセルを読み込む場合
https://note.nkmk.me/python-numpy-dtype-astype/
>>> df2 = pd.read_excel('test.xlsx', dtype={'hoge1':object, 'hoge3':object})
>>> print(df2.dtypes)
hoge1 object
hoge2 object
hoge3 datetime64[ns]
dtype: object

一気に全部の型を指定(objectなら一気に行けそうだが、ほかの型は微妙)
>>> df3 = pd.read_excel('test.xlsx', dtype='object')
>>> print(df3.dtypes)
hoge1 object
hoge2 object
hoge3 datetime64[ns]
dtype: object


空セルのNaNを変換
>>> df.fillna('')
hoge1 hoge2 hoge3
0 1 ほげ 2019-11-01 00:00:00
1 2 ふが
2 3 2019-11-01 00:00:00
dtype: object

↑の場合、戻り値指定していないため、dfはNaNのまま!
df=df.fillna('')
こうするとdfが上書きされる

■脱線するがdfの比較をする方法
 これでエクセルファイルの比較をした

https://hack-le.com/pandas-2-true-false-10/

dfとdf2を比較する
>>> print(df)
hoge1 hoge2 hoge3
0 1 ほげ 2019-11-01
1 2 ふが NaT
2 3 NaN 2019-11-01
>>> print(df2)
hoge1 hoge2 hoge3
0 1 ほげ 2019-11-01
1 2 ふが NaT
2 3 NaN 2019-11-01
>>> print(df.dtypes)
hoge1 int64
hoge2 object
hoge3 datetime64[ns]
dtype: object
>>> print(df2.dtypes)
hoge1 object
hoge2 object
hoge3 datetime64[ns]
dtype: object

dfとdf2をキーhoge1でマージ(複数キー指定の場合はこうする→on=['key1', 'key2'])
>>> dfmg=pd.merge(df,df2, on='hoge1', how='inner')
>>> print(dfmg)
hoge1 hoge2_x hoge3_x hoge2_y hoge3_y
0 1 ほげ 2019-11-01 ほげ 2019-11-01
1 2 ふが NaT ふが NaT
2 3 NaN 2019-11-01 NaN 2019-11-01

列同士を比較し結果を入れる列を作成
>>> dfmg['hoge2_comp']=(dfmg['hoge2_x']==dfmg['hoge2_y'])
>>> dfmg['hoge3_comp']=(dfmg['hoge3_x']==dfmg['hoge3_y'])
>>> print(dfmg)
hoge1 hoge2_x hoge3_x hoge2_y hoge3_y hoge2_comp hoge3_comp
0 1 ほげ 2019-11-01 ほげ 2019-11-01 True True
1 2 ふが NaT ふが NaT True False
2 3 NaN 2019-11-01 NaN 2019-11-01 False True

hoge3が一致しない行だけ抽出し、一致しなかった値を出力
>>> r=dfmg['hoge3_comp']==False
>>> print(dfmg.loc[r,['hoge1','hoge3_x','hoge3_y']])
hoge1 hoge3_x hoge3_y
1 2 NaT NaT

NaTとかNaNは比較するとNGになる?ちゃんと消してから比較しないとダメ。
わざわざMergeしなくても比較できそうだが、
必ずしもデータが一致していないエクセルの比較だったのでMergeした


■python3.8について

新しい機能が増えててショック・・・

・セイウチ演算子
  変数への代入と変数の使用を同時に行える
  >>> a = 'hoge'
  >>> (n := len(array)) > 4
  False
  ※代入して比較する際にはセイウチ演算子の範囲をかっこで囲む必要あり

ほかにもあるがとりあえずまた今度。




Git

2019-08-15 17:02:33 | util
◆gitコマンドメモ

基本的な理解はここが分かりやすい
https://qiita.com/kyoyyy/items/161b6905f45bee2efe21
Git-flowって何?
https://qiita.com/KosukeSone/items/514dd24828b485c69a05

--------------------
gitを始める
--------------------
ユーザー設定
git config --global user.name 名前
git config --global user.email メールアドレス
git config --global core.quotepath false
git config --global sendpack.sideband false


リモートリポジトリを作成する
git init --bare --shared

ローカルリポジトリを作成する(作成したい場所に移動して)
git init
リポジトリを作成した場所のファイルを追加する場合
git add *
git commit -m 'initial commit'

リモートリポジトリに作成したローカルリポジトリを追加
git remote add origin パスとか

リモートリポジトリにローカルリポジトリをプッシュ
git push origin master

リモートリポジトリをCloneする
git clone パス

--------------------
ブランチ
--------------------
ブランチの一覧を見る
git branch -a

上流ブランチの設定を確認する
git branch -vv
[リモート名/ブランチ名]が表示されれば、紐づいている
(Cloneすれば基本的に大丈夫

ブランチを切り替える
git checkout hoge

ブランチを作成する(作成元ブランチにcheckoutしてから)
git checkout -b fuga

リモートからブランチを作成する
git checkout -b fuga origin/master

ブランチをリモートに登録する
git push -u origin fuga

ブランチを削除する(HEADにマージしたブランチ)
git branch --delete fuga

ブランチを削除する(マージしたか問わずに)
git branch -D fuga

リモートブランチの一覧を表示する
gut branch --remote

リモートブランチを削除する
git push --delete origin fuga
または
git push origin :fuga


リモートブランチの参照がおかしい(消えてるに出るとか)時
git remote prune orgin
余計な枝を掃う

--------------------
コミット
--------------------
変更をコミットする
git add -u
git commit -m 'コメント'

↑を1回でする
git commit .

新規ファイルも含めてコミットする
git add .
git commit

特定のファイルをコミットする
git commit ファイル名

間違ったコミットを取り消す(ローカルは変更しない)
git reset --soft

直前のコミットを消す(ローカルは変更しない)
git reset --soft HEAD^

間違ったコミットを取り消す(ローカルも変更する
git resert --hard

直前のコミットコメントを変更する)
git commit --amend

ログを10件見る
git log --oneline --graph -10

--------------------
プッシュ
--------------------
コミットをリモートに反映する
git push origin
 →checkout中のブランチをプッシュ、上流ブランチが紐づいてないとエラー
git push origin ブランチ名
git push origin ローカルブランチ:リモートブランチ
※ローカルブランチ名を空にすることで削除と同じ

--------------------
プル
--------------------
リモートブランチの内容を取得し、ローカルブランチの値にマージする
git pull

git fetch
git merge
pullは↑コマンドを一気にやっている

チェックアウトしていないブランチの内容を取得する
git fetch origin ローカルブランチ:リモートブランチ

リモートで削除されたブランチを消す場合(fetchでも使える)
git pull --prune

--------------------
マージ※マージしたいbranchで行う
--------------------
マージ
git merge ブランチ名

必ずマージコミットを作ってマージ
git merge --no-ff ブランチ名

マージが競合した場合、対象を確認
git status

マージ解消用のグラフィカルツールの呼び出し(vimdiffがいけるが使い方わからない)
git mergetool

マージを途中でキャンセル(commitしなけれキャンセル可能)
git merge --abort

マージを解消したらgit add を実行して解決済みであることを通知
git add .
git commit
※ステージすると、Git はコンフリクトが解決されたと見なす

--------------------
リベース※先行しているbranchで行う
--------------------
file:///C:/Program%20Files/Git/mingw64/share/doc/git-doc/git-rebase.html
リベースマージする
git rebase ブランチ名

リベースキャンセル
git rebase --abort

競合が発生し解消した後に反映
git add .
git rebase --continue
※rebaseの場合、競合箇所を修正した後はコミットではなく、
 rebaseコマンドに --continue オプションを指定して実行する

リベースをしてコミットをまとめる(例えばHEADから2つ目までを対象)
it rebase -i HEAD~2

----
コミットを指定するときに、~(チルダ)と^(キャレット)を使ってあるコミットからの
相対位置で指定することもできます。
この時に、よく使われるのがHEADです。~(チルダ)を後ろに付け加えることで
何世代前の親かを指定することができます。
^(キャレット)は、ブランチのマージで親が複数ある場合に、
何番目の親かを指定することができます。


--------------------
タグ※Gitfllowでは「master」にのみつける
--------------------
注釈つきタグをつける
git tag -a タグ -m 'タグのコメント'

注釈なしのタグ
git tag タグ

後からタグをつける
git -tag -a タグ -m 'コメント' コミットID

タグをリモートに反映
git push origin タグ名
→タグをつけたコミットを共有しているブランチすべてに反映されるみたい
 なぜ?コミットのないしてタグをつけるから、ブランチは関係ないのか?


--------------------
stash
--------------------
一時退避
git stash save(省略可)

stashのリストを見る
git stash list
git stash list -p 変更内容を見れる

各変更の詳細を見る
git stash show stash名

stashを復活する
git stash apply stash@{0}

stashを消す
git stash drop stash@{0}

復活と削除
git stash pop stash@{0}

応用、復活したけどやっぱりやめる
git stash show <適用したstash名> -p | git apply -R


--------------------
log見る
--------------------
そこそこ見やすい
git log --oneline --graph --decorate

ファイル毎の削除、追加行数をログごとに表示
git log --numstat

変更したファイルをログごとに表示
git log --name-status

変更点を見る
git log -p

リモートリポジトリのログを見る
git log origin/master