T-SQL - count(*)とcount(カラム名)の違い
知らなかったのでメモ。
count(*)
は全行数を取得するのに対して、count(カラム名)
はnullを除く行数を取得します。
サンプルクエリを書いて確認しておきましょう。
select -- nullに関係なく全行数を取得 count(*) as [count(*)], -- nullを除く行数を取得 count(Value) as [count(Value)] from (values (1, 100), (2, 200), (3, 200), (4, null), (5, 300), (6, 200)) as Test(Id, Value); -- 行は全部で6、nullを除くと5 /* count(*) count(Value) ----------- ------------ 6 5 */
おまけ
countだけでなくsumやavgなどの関数もnullを無視して集計します。
select count(Value) as [count(Value)], sum(Value) as [sum(Value)], avg(Value) as [avg(Value)] from (values (1, 100), (2, 200), (3, 200), (4, null), (5, 300), (6, 200)) as Test(Id, Value); /* count(Value) sum(Value) avg(Value) ------------ ----------- ----------- 5 1000 200 */
おまけ2
nullの行しか存在しない場合はどうなるんだろうと思って、countやsumなどの関数を試しました。次のような結果になります。
select count(Value) as [count(Value)], sum(Value) as [sum(Value)], avg(Value) as [avg(Value)], min(Value) as [min(Value)], max(Value) as [max(Value)] from (values -- nullの行が1つ (cast(null as int))) as Test(Value); /* count(Value) sum(Value) avg(Value) min(Value) max(Value) ------------ ----------- ----------- ----------- ----------- 0 NULL NULL NULL NULL 警告: NULL 値は集計またはその他の SET 演算で削除されました。 */
ん?警告?
参考
ASP.NET Core - ミドルウェアパイプラインを作ってみる
ミドルウェアとかミドルウェアパイプラインとかリクエストデリゲートなどを理解するために、次のドキュメントを読みながら記事内にあるミドルウェアパイプラインの画像の動きを作ってみました。
ASP.NET Core のミドルウェア | Microsoft Docs
この画像のことです。
Use/Run拡張メソッドを使ってパイプラインを作る
Startup.Configureメソッド内でミドルウェアパイプラインを構築します。Use拡張メソッドやRun拡張メソッドを使うと、ミドルウェアをインライン(ラムダ式)で記述できます。Use拡張メソッドは次のミドルウェア(コンポーネントとも言ったりしてる)を呼び出しますが、Run拡張メソッドは次のミドルウェアを呼び出さずパイプラインの終端になります。
public class Startup { public void ConfigureServices(IServiceCollection services) { } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { // 最初に呼び出されるミドルウェア app.Use(async (context, next) => { context.Response.ContentType = "text/plain"; // 次を呼び出す前の処理 await context.Response.WriteAsync("Middleware 1 before\n"); // 次のミドルウェアを呼び出す await next.Invoke(); // 次を呼び出した後の処理 await context.Response.WriteAsync("Middleware 1 after\n"); }); // 2つ目のミドルウェア app.Use(async (context, next) => { await context.Response.WriteAsync("\tMiddleware 2 before\n"); await next.Invoke(); await context.Response.WriteAsync("\tMiddleware 2 after\n"); }); // 最後に呼び出されるミドルウェア app.Run(async context => { await context.Response.WriteAsync("\t\tMiddleware 3\n"); }); } }
実行すると次のレスポンスが返ります。
Middleware 1 before Middleware 2 before Middleware 3 Middleware 2 after Middleware 1 after
ミドルウェアクラスとUseMiddleware拡張メソッドを使ってパイプラインを作る
上記と同じことをクラスを使って再現したいと思います。インラインでの処理をミドルウェアクラスにカプセル化します。
ミドルウェアクラスはHttpContextを引数に持つInvokeAsyncメソッドを持っていればいいみたいです。
// 最初に呼び出されるミドルウェア public class Middleware1 { private readonly RequestDelegate _next; public Middleware1(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { context.Response.ContentType = "text/plain"; // 次を呼び出す前の処理 await context.Response.WriteAsync("Middleware 1 before\n"); // 次のミドルウェアを呼び出す await _next(context); // 次を呼び出した後の処理 await context.Response.WriteAsync("Middleware 1 after\n"); } } // 2つ目のミドルウェア public class Middleware2 { private readonly RequestDelegate _next; public Middleware2(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { await context.Response.WriteAsync("\tMiddleware 2 before\n"); await _next(context); await context.Response.WriteAsync("\tMiddleware 2 after\n"); } } // 最後に呼び出されるミドルウェア public class Middleware3 { // 使わないけど private readonly RequestDelegate _next; public Middleware3(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { await context.Response.WriteAsync("\t\tMiddleware 3\n"); } } public class Startup { public void ConfigureServices(IServiceCollection services) { } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { // 最初に呼び出されるミドルウェア app.UseMiddleware<Middleware1>(); // 2つ目のミドルウェア app.UseMiddleware<Middleware2>(); // 最後に呼び出されるミドルウェア app.UseMiddleware<Middleware3>(); } }
実行すると上記と同じレスポンスが返るようになります。
普段UseStaticFilesメソッドやUseMvcメソッドを使っていると思いますが、その中で実際にはミドルウェアはクラスとして用意されていて、UseMiddleware拡張メソッドを使っているようです。
勉強になりました。
AzureのComputer Vision APIのOCR機能を試してみた
Azure Cognitive ServicesにあるComputer Vision APIを使ってみました。
Computer Vision — 画像処理および画像分析 | Microsoft Azure
Computer Vision APIといってもいくつか機能があって、今回はそのうちOCR機能をJavaScript(というかTypeScript)で試してみました。
OCRを試す
APIの仕様はここにあります。
使い方は簡単でAPIのエンドポイントURLに、画像のURLをJSON形式でPOSTするか、画像のバイナリデータをPOSTするだけです。
TypeScriptでバイナリデータをPOSTする場合は次のような感じになるのかなと思います。
// 画像をBlobとして取得するとして const blob: Blob = await getBlob(); // APIのURL(今回は東アジア) const apiUrl = "https://eastasia.api.cognitive.microsoft.com/vision/v1.0/ocr"; // APIのキー const apiKey = "内緒のキー"; // APIを呼び出す const response = await fetch(apiUrl, { method: "POST", // リクエストのヘッダにメディアタイプとAPIのキーを指定する headers: { "Content-Type": "application/octet-stream", // ボディのメディアタイプ "Ocp-Apim-Subscription-Key": apiKey // APIのキー }, // リクエストのボディにBlobを設定する body: blob }); // レスポンスはJSON // OCRの結果を取得できる const result: IResult = await response.json(); /* // 適当に行(文字列)を抽出してみるならこんな感じ result.regions .map(region => region.lines) .reduce((previous, current) => previous.concat(current)) .map(line => line.words.map(word => word.text).join(" ")) .forEach(line => console.log(line)); */
レスポンスにはOCRの結果が入ります。フォーマットはJSONで、次のようなインターフェイスを持ったオブジェクトです。単にテキストだけでなく、その座標も取得できるようです。
// OCRの結果 interface IResult { language: string; textAngle: number; orientation: string, // 複数のリージョン regions: IRegion[]; } // リージョン interface IRegion { boundingBox: string; // 複数行を持つ lines: ILine[]; } // 行 interface ILine { boundingBox: string; words: IWord[]; } // 単語 interface IWord { boundingBox: string; text: string; }
参考
JavaScriptのチュートリアルとかはこのあたり。
ASP.NET Core MVC - ビューコンポーネントの呼び出し方色々
ASP.NET Core MVCのビューコンポーネントを試してみました。
ビューコンポーネントは従来のASP.NET MVCにあったチャイルドアクション(子アクション、ビューからRenderActionで呼び出していたあれ)の代わりになる機能ですね。呼び出し方が色々あるようなので、ちょっと書き残しておきます。
ビューコンポーネント名を指定する
上記ドキュメントにありますが、ビューコンポーネント名を指定して呼び出す方法があります。試してみましょう。
次のようなビューコンポーネントクラスを用意します。csファイルはプロジェクト直下に「ViewComponents」フォルダを作ってそこに入れるといいのかな?
// 適当なビューコンポーネント public class Sample1ViewComponent : ViewComponent { public async Task<IViewComponentResult> InvokeAsync(int no, string name) { // 何か重たい処理があるとして await Task.Delay(0); // ViewBagも使える(それかViewModelを作るか) ViewBag.No = no; ViewBag.Name = name; return View(); } }
続いてビューコンポーネントの呼び出し側。Component.InvokeAsyncメソッドの1つ目の引数にビューコンポーネント名を、2つ目の引数にはSample1ViewComponent.InvokeAsyncメソッドの引数を匿名オブジェクトで指定します。
@await Component.InvokeAsync("Sample1", new { no = 1, name = "Sample1 string" })
型を指定する
typeof演算子で型を指定して呼び出す方法もあります。
@await Component.InvokeAsync(typeof(Sample1ViewComponent), new { no = 2, name = "Sample1 typeof" })
ジェネリック メソッドを使う
ジェネリック(ジェネリクス?)メソッドが用意されているので、次のような呼び出し方もできます。ただ丸括弧"()"を使う必要があってちょっとだけ残念。ちょいちょい括弧を忘れてコンパイラさんに怒られそう。
@(await Component.InvokeAsync<Sample1ViewComponent>(new { no = 3, name = "Sample1 generics" }))
引数にクラスを使う
ビューコンポーネントを呼び出す引数は、匿名オブジェクトではなく具体的なクラスでも問題なさそうです。
引数が多いという体で引数をクラスにまとめます。
// 適当なビューコンポーネントその2 public class Sample2ViewComponent : ViewComponent { // ビューコンポーネントの呼び出しパラメータクラス // インナークラスにする必要はないけど public class Param { public int No { get; set; } public string Name { get; set; } } // 引数にParamクラスを受け取る public async Task<IViewComponentResult> InvokeAsync(Param param) { // 何か重たい処理があるとして await Task.Delay(0); ViewBag.No = param.No; ViewBag.Name = param.Name; return View(); } }
呼び出し側もわかりやすいのでこの方法もありかなと思います。
@await Component.InvokeAsync(typeof(Sample2ViewComponent), new Sample2ViewComponent.Param { No = 4, Name = "Sample2" })
コントローラのアクションから呼び出す
ちょっと話は変わりますが、ビューコンポーネントはビューだけでなくコントローラのアクションメソッドでも呼び出せます。Ajaxでも使いたいときですかね。
// ビューコンポーネントを返すアクション public IActionResult Sample1() { return ViewComponent(typeof(Sample1ViewComponent), new { no = 5, name = "Sample1 controller" }); }
こんなところかなと。
ASP.NET Core MVC - ビューの基底クラスを変更する
ASP.NET Core MVCのビュー全体で、プロジェクト独自のプロパティやメソッドを追加して利用したいことがあるかなと思います。
デフォルトでは、ビューはMicrosoft.AspNetCore.Mvc.Razor.RazorPage<TModel>
を継承しています。このクラスを派生したクラスを用意することで実現できます。
詳しくはこのあたり。
ASP.NET Core の Razor 構文リファレンス | Microsoft Docs
上記ドキュメントそのままなんですが、覚え書きとしてメモしておきます。
まずRazorPage<TModel>
を継承した独自のRazorページクラスを用意します。
// プロジェクト独自のRazorページクラス public abstract class CustomRazorPage<TModel> : RazorPage<TModel> { // 独自のプロパティやメソッドを追加したい public int CustomValue { get; set; } }
つぎに@inherits
ディレクティブを使って、用意したRazorページクラスを継承するようにします。プロジェクト全体でビューの基底クラスを変えるには、Viewsフォルダ直下の_ViewImports.cshtml
で指定します。
@* _ViewImports.cshtml *@ @* ビューの基底クラスを変更する *@ @inherits CustomRazorPage<TModel>
すると、各cshtmlでカスタムRazorページのプロパティやメソッドが使えるようになります。
@* 各cshtml *@ @* 独自のプロパティが使えるようになる *@ @CustomValue