SQL Server 2016 JSON その2

以下のようにリレーションしている、2つのテーブル(1:nの関係)のnの方をJSON配列に出来ないかと思って、色々試してみた。

relation

最初はカーソル使って、2つのテーブルからJSONを作ってみたが、結構面倒だ。

もしかしたら・・・と思って以下のようなSQLを実行してみると、思った通りの結果が得られた。

select distinct g.GroupName,g.Comment,   (select m.Account,m.Name from Members m     where m.GroupKey = g.GroupKey     for json auto   ) as Members    from Groups g      for json auto

実行結果

[  {   "GroupName":"Administrators",   "Comment":"Administrator Group",   "Members":   [    {"Account":"T.Sumomo","Name":"すもも太郎"},    {"Account":"J.Sumomo","Name":"すもも次郎"}   ]  },           ・・・ ]
カテゴリー: 未分類 | 1件のコメント

SQL Server 2016のJSON連携

SQL Server 2016でJSONを扱えるようになったと言うので、試してみたが・・・
JSONを直接扱うための型があるわけではなく、JSONそのものはあくまでも、varchar型に格納するらしい。
結局T-SQLで、JSON文字列を解析して通常のテーブルデータのように扱えたり、通常のテーブル内容をJSONに変換できるだけの模様。ちょっとがっかり。

こんな感じ
— テーブル内容をJSON化
SELECT [EmpNo] ,[Name] ,[Birthday]
FROM [TestDB].[dbo].[TestTable] FOR JSON AUTO

結果
[{“EmpNo”:”0840303″,”Name”:”T.Ohwaki”,”Birthday”:”1964-02-03T00:00:00″},{“EmpNo”:”0980555″,”Name”:”T.Sumomo”,”Birthday”:”1988-05-15T00:00:00″}]

— JSON文字列をテーブルデータとして取得
SET @jsonstr = ‘[{“EmpNo”:”0840303″,”Name”:”T.Ohwaki”,”Birthday”:”1964-02-03T00:00:00″},{“EmpNo”:”0980555″,”Name”:”T.Sumomo”,”Birthday”:”1988-05-15T00:00:00″}]’
SELECT [EmpNo] ,[Name] ,[Birthday]
FROM OPENJSON(@jsonstr)
   WITH (EmpNo nchar(7), Name varchar(20), Birthday datetime )

結果

EmpNo Name Birthday
0840303 T.Ohwaki 1964-02-03 00:00:00.000
0980555 T.Sumomo 1988-05-15 00:00:00.000

— 2016/06/03 追記 —
ちなみに、JSON用のカラムにはJSON文法チェックの制約を掛けることが可能。
例えば、EmpNoとPropertiesからなる、テーブルで、PropertiesにJSON文法チェックを掛けるには

create table JSONTest(EmpNo nchar(7),
Properties nvarchar(max) CONSTRAINT JSONTest_PropertiesMustBeJSON CHECK (ISJSON(Properties) > 0), Primary Key(EmpNo))

といった感じ。

後、JSON用カラムに格納されたJSONのプロパティ値を取得するには、JSON_VALUE関数を使用する。

select EmpNo,JSON_VALUE(Properties,’$.”Name”‘),convert(datetime,JSON_VALUE(Properties,’$.”BirthDay”‘)) from JSONTest

当然、$.Address.Countryのような階層構造の末端プロパティを指定することも可能。
末端では無いプロパティ(上記の例では、$.Address)を指定するとNULLが返る。

他にJSON構造を文字列で返す、JSON_QUERYなどがある。
(配列や複合プロパティなど。末端のプロパティを指定すると、NULLが返る)

詳しくは、下記URLを参照。
https://blogs.technet.microsoft.com/dataplatforminsider/2016/01/05/json-in-sql-server-2016-part-1-of-4/

https://blogs.technet.microsoft.com/dataplatforminsider/2016/01/05/json-in-sql-server-2016-part-2-of-4/

https://blogs.technet.microsoft.com/dataplatforminsider/2016/01/05/json-in-sql-server-2016-part-3-of-4/

https://blogs.technet.microsoft.com/dataplatforminsider/2016/01/05/json-in-sql-server-2016-part-4-of-4/

カテゴリー: SQL Server, 技術情報 | コメントする

Surface 4 Pro

Surfaceが携帯できる状態にならないので、仕方なくSurface 4 Proを昨年末ぐらいに購入。
しかし、かなり高価になっていたので、i5 128Gのモデルしか買えなかった。(というか、買う気にならなかった)
使用用途からすると、まぁ、問題ないスペックなのだが、やっぱりメモリ8Gは欲しかったなぁ。
ペンは結構良くなっていたね。絵心が無いので、あまり意味ないけど、ちょっと面白い。
ちなみに、タイプカバーはティールグリーンにしました。デスクトップの配色も色を合わせているので、なかなか美しい。
作り的には、コネクタ類が全て右側に来てしまったのはいまいちかな・・・
基本的に、タブレットとしては使いません。携帯できるノートとして使用しています。
Unityを動かしてみたけど、まぁ、そこそこという感じ。
メモリ4Gなので、Hyper-Vはちょっと無理。
後、少々問題が・・・
タブレットモードとデスクトップモードの切替をしていると、何かのタイミングで、無線LANが繋がらなくなる現象が発生していて、その度に完全シャットダウンしないと治らない。
有線LANで繋いでいて、スリープから復帰したときに、LAN自体は繋がっているのに、USB機器が認識されませんというメッセージが何回も出る。抜き差ししても同様で、結局リブートするしかない。

ファームのアップデートで対応してくれないかな・・・

カテゴリー: Surface, 日記 | コメントする

Surface Proが・・・

気がつけば1年以上、投稿してなかった・・・

で、本題です。

2年位使用していた、Surface Proがある日突然、所謂「UEFIループ」状態に。

USB接続のDVDからWindowsインストールディスクで、ブートし、回復コンソールからdiskpartでディスク状態を見てみると、何とSSDが認識されていないではないかっ!

保障期間はとっくに過ぎているし、色々なサイトを見ても分解は難しそうだし、でももったいないので、とりあえず生かす方法を考えてみた。そうだ、Windows to goを試してみよう!

ということで、早速物理マシンにWindows 10 Enterpriseをセットアップ。まず、Windows to goがちゃんと動くか試したかったので、USB接続のHDにWindows to goワークスペースを作成。

Surface ProにそのHDを接続して、電源オン。

おお、ちゃんとブートするではないか。で、セットアップが始まって、難なく終了。

さすが、MS謹製のSurfaceだけあって、WiFiもちゃんと認識。(ネット繋がらないと何も出来ないし・・・)

後は、MSアカウントでログインするようにすれば、ほぼ以前の環境と同じで使えるようになりました。

でも、USBは1ポートしかないから、今度はMicro SDで試してみようと思います。

カテゴリー: 日記 | 1件のコメント

C# Managed構造体とUnmanaged構造体のマッピング

Managed構造体とC等のUnmanaged構造体のマッピング

Managed構造体はC等の構造体と異なり、メンバの格納順序が定義順にならなかったり、C等の固定長配列が言語仕様上定義できなかったりする。

これらの点はWindows APIに構造体パラメータを渡したり、共有メモリ等でC等のUnmanaged言語とデータを共有したりする場面で問題が発生する。

そこで、C#(.NET Framework)では、構造体やメンバに対して属性を指定することにより、ManagedとUnmanagedで相互交換を行わせる事ができるようになっている。

例えば、以下のようなCの構造体

struct Info
{
  int    index;
  char    name[128];
  int    statuses[50];
};

とメンバ順序もサイズも同じManaged構造体を定義するには属性を使用して以下のように定義。

[StructLayout(LayoutKind.Sequential)]    // メンバーは定義順に格納される
public struct Info
{
  [MarshalAs(UnmanagedType.I4)]        // Signed int(4Byte)で格納(属性無くても大丈夫です)
  public    int    index;
  [MarshalAs(UnmanagedType.ByvalTStr,SizeConst=128)]    // char[128]で格納
  public    string name;
  [MarshalAs(UnmanagedType.ByvalArray,SizeConst=50)]    // int[50]で格納
  public    int[] statuses;
  // ↑bool, byte, char, short, int, long, sbyte, ushort,
  // uint, ulong, float, double配列の場合は属性を付けずに以下のようにしても良い
  // この場合は配列のインスタンスを作成する必要は無い。→これはunsafeブロック中でしか使えないらしい・・・
  // public fixed int statuses[50];
}

注意しなければならないのは、上記のstatusesは必ず、50要素の配列として配列のインスタンスを作成しなければならない点。(コメントに書いてある表記をした場合を除く)

Info inf;
inf.Statuses = new int[50];

また、Unmanaged構造体のAlignmentにも注意

(Alignmentも属性を使用して定義可能。)

[StructLayout(LayoutKind.Sequential,Pack=4)]    // Alignment = 4

 

このようにManaged側でUnamanaged側に合わせることにより、構造体の相互参照が可能となる。

ちなみに、Managed側からUnmanaged側のポインタへ構造体内容をコピーするにはMarshal.StructureToPtrメソッドを使用する。

static void Marshal.StructureToPtr(object structure, IntPtr dest, bool fDeleteOld)

IntPtr mem = ….    // 共有メモリのマップ等
Marshal.StructureToPtr(inf,mem,true);

 

逆に、UnmanagedからManaged構造体を取得するにはMarshal.PtrToStructureメソッドを使用する。

static object Marshal.PtrToStructure(IntPtr src, Type StructureType)

Info inf = (Info)Marshal.PtrToStructure(mem,typeof(Info));

 

忘れないようにメモ。

カテゴリー: .NETフレームワーク, C#, 技術情報 | コメントする

C#のref渡しをC++/CLIのメソッドで提供するには

初歩的な話だけど、忘れないようにメモ。

C#で、以下のようなシグネチャをC++/CLIのメソッドで提供するには、トラッキング参照(%)を使用する。

int GetMessage(ref string msg);

C++側のメソッド定義

int GetMessage(String^% msg) {
msg = gcnew String(・・・)

わかりづらいね・・・

カテゴリー: .NETフレームワーク, C#, 技術情報 | 1件のコメント

scriptcs

Windows Azure SDKチームのプロジェクトマネージャGlenn Block氏始めたサイドプロジェクトで、C#をスクリプトとして使おうというもの。

スクリプトはC#の文法を理解している人なら、普通のテキストエディタで作成することができ、MicrosoftのRoslyn(compiler as a service)を使用して、コンパイル~実行が可能である。
必要なコンポーネントがローカルに無い場合は、NuGetを使用してコンポーネントのインストールを行う事で、コンパイル,実行が可能となる。

スクリプト中に#loadを指定することにより、別ファイルを取り込む事も可能(C言語のincludeと同等の機能)や#rによるAssemblyの参照指定も可能。(AssemblyはGACまたはDLLファイル直接指定で指定可)

使ってみたところ、結構良さげなのだが、日本語の扱いに少々問題があるようだ。日本語をコード内で使用するばあい、ファイルのエンコーディングがutf8でなければ化けてしまう。まぁ、それさえ気をつければC#の機能をフルに使用できるので、いいんじゃないかな。

カテゴリー: .NETフレームワーク, C#, 技術情報 | 1件のコメント

C#からMongoDBを触ってみる-更新と削除

前回、C#からのデータ挿入と、検索について書いたので、今回は更新と削除について書いてみる。

更新

更新はMongoDB API方式(検索条件に一致したもの全てを更新)と検索結果を得てから更新する方法の2種類がある。

MongoDB API方式の場合、collectionのFindAndModifyを使用する。代表的な、オーバーロードとして以下のものがある。

<collection>.FindAndModify(IMongoQUery, IMongoSortBy, IMongoUpdate)

IMongoQueryは一般的に、Queryクラスのスタティックメソッドを使用して、検索条件を指定する。

例えば、Name.StartsWith(“Jon”) && Country == “US”という検索条件を表すには、

Query.AND(Query.Matches(“Name”,”^Jon”),Query.EQ(“Country”,”US”))

となる。

IMongoSortByにはSortByクラスのスタティックメソッドを使用して、ソート条件を指定する。

SortBy.Ascending(string プロパティ名)    // 指定プロパティを昇順ソート
SortBy.Descending(string プロパティ名)    // 指定プロパティを降順ソート
SortBy.Null                    // ソート無し

通常はソートする必要が無いと思われるので、SortBy.Nullで良いと思う。ちなみに、ソート条件を複数指定するには、以下のようにする。

SortBy.Ascending(“Name”).Descending(“Birthday”)    // Nameで昇順ソート後、Birthdayで降順ソート

  • この関数ではあまり意味を持たないが必須。なお、検索メソッド(Find)では、メソッドの戻り値にソート条件を指定する。

    var cur = col.Find(Query.Matches(“Name”,”^Jon”)).SetSortOrder(SortBy.Ascending(“Name”));    // NameがJonで始まるデータをNameで昇順ソート

IMongoUpdateはUpdateクラスのスタティックメソッドを使用して、変更するプロパティと値を指定する。

Update.Set(“Office”,”東京”).Set(“Updated”,DateTime.Now)    // Officeプロパティを”東京”に、Updatedを現在時刻に更新

以下に例を示す

// オフィス名称を変更
var col = db.GetCollection<Employee>(“Employees”);
Console.Write(“現オフィス名”);
string oldOffice = Console.ReadLine();
Console.Write(“新オフィス名”);
string newOffice = Console.ReadLine();
// オフィス名称と更新日時を更新
col.FindAndModify(Query.EQ(“Office”,oldOffice),SortBy.Null,
  Update.Set(“Office”,newOffice).Set(“Updated”,DateTime.Now));

更新のもう一つの方法としては、検索などで取得したオブジェクトの値を変更して、Saveメソッドで保存する方法。

例えば、

// 指定した社員番号を持つデータを取得
var col = db.GetCollection<Employee>(“Employees”);
Console.Wrirte(“社員番号:”);
string EmpNo = Console.ReadLine();
Employee emp = col.AsQueryable().Where(p => p.EmpNo == EmpNo).First();
// 氏名を変更
emp.Name = “・・・”;
// 保存
col.Save(emp);

 
 

削除

削除は、MongoDB APIと同様なI/Fを使用する。削除に使用するメソッドはRemoveである。Removeの代表的なオーバーロードを以下に示す。

<collection>.Remove(IMongoQuery)

IMongoQueryはFindAndModify()で説明したように、検索条件を指定する。

Removeの他に、FindAndModifyと同様のFindAndRemoveを使用することも可能。

<collection>.FindAndRemove(IMongoQuery,IMongoSortBy)

なお、コレクション内容を全てクリアするには、<collection>.RemoveAll()メソッドを使用する。

以下に例を示す

// 指定された文字から始まる名前を持つユーザーを削除する
var col = db.GetCollection<User>(“Users”);
Console.Write(“Name Starts With : “)
string name = Console.ReadLine();
col.Remove(Query.Matches(“Name”,”^” + name));

カテゴリー: .NETフレームワーク, C#, NO SQL, 技術情報 | コメントする

C#からMongoDBを触ってみる

以前書いたように、MongoDBのC#ドライバはかなりの優れもので、LINQもサポートしている。

今回はC#プログラムからMongoDBのデータを操作してみよう。

まずは、ドライバAssemblyをダウンロードするのだが、VS2010,VS2012であれば、NuGetを使用するだけで、ドライバパッケージのダウンロードが完了する。パッケージ名はmongocsharpdriver。

今回の例では、下記のネームスペースを使用。

  • MongoDB.Driver
  • MongoDB.Driver.Builders
  • MongoDB.Driver.Linq
  • MongoDB.Bson
  • MongoDB.Bson.Serialization.Attributes

前提として、以下のようなクラスインスタンスを保存、参照することとする。

[BsonIgnoreExtraElements]
public class AddressEntry
{
  [BsonId]
  public BsonObjectId _id { get; set;}
  public string Name { get; set; }
  public DateTime Birthday { get; set; }
  public List<Email> EmailAddrs { get; set; }
}
[BsonIgnoreExtraElements]
public class Email
{
  public string DisplayName { get; set; }
  public string MailAddress { get; set; }
}

 

プログラムからMongoDBを使用するには、通常のDBサーバと同じようにMongoDBに接続する必要がある。接続を行うには、MongoClientクラスを使用する。

MongoClient cli = new MongoClient(<接続文字列>);    // System.Data.xxxClient的なコンストラクタ

接続文字列は、以下の形をとる。

mongodb://[<Uer Name>:<Password>@]<IP>[:<PORT>][/<Database名>]

なお、mongodがデフォルトポート設定(27017)になっていて、ユーザ管理を行っておらず、かつ、ローカルホストに対する処理を行う場合は、パラメータ無しのコンストラクタを使用すればOK。今回はこのコンストラクタを使用する。

次に使用するDatabaseを指定(取得)する。Databaseが作成されていない場合、自動的に作成される。

MongoDatabase db = cli.GetServer().GetDatabase(<Database名>);

データ操作はこのDatabase中のcollection(テーブルのようなもの)に対して行うこととなる。

今回は、Databaseを”TestDB”,collectionを”AddressBook”とする。

次にcollectionを取得。(これも作成されていない場合、自動的に作成される)

MongoCollection<T> col = db.GetCollection<T>(<collection名>);

ここまでを今回のプログラムに当てはめると、

// ローカルMongoDBに接続
MongoClient cli = new MongoClient();
// Databaseを選択
MongoDatabase db = cli.GetServer().GetDatabase("TestDB");
// コレクションの取得
MongoCollection<AddressEntry> col = db.GetCollection<AddressEntry>("AddressBook");

 

となる。

次にデータをインサートしてみよう。データをインサートするには、MongoCollectionクラスのInsertメソッドを使用する。(Saveメソッドも使用できるが、保存するタイミングで、idが設定されていないとエラーとなる。クラスメンバのBsonId属性のパラメータとしてIdGeneratorを指定することで、自動生成されるようだが、まだ試していないためInsertを使用する)

Insertメソッドの一番簡単な使用方法は、collectionの型のクラスインスタンスを渡す方法である。

今回は、AddressEntry型のcollectionとしているので、AddressEntryのインスタンスを作成して、データを設定後、Insertメソッドに渡すだけで良い。

// データ作成
AddressEntry entry = new AddressEntry(){
  Name = "すもも太郎",
  Birthday = DateTime.Parse("1964/02/03"),
  EmailAddrs = new List<Email>()
    {
      new Email() { DisplayName = "すもも太郎", MailAddress = "T.Sumomo@momo.com" },
      new Email() { DisplayName = "ぼのぼの", MailAddress = "Bonobono@bono.jp" }
    }
};
// データ挿入
col.Insert(entry);

 

次は、データを検索してみよう。データ検索はMongoDBのAPIを使う方法と、LINQを使う方法がある。LINQの方が簡単なので、LINQで検索してみる。LINQのソースとしては、collectionをQueryable化したものを使用する。つまり、AsQueryable()メソッドを呼び出せばよい。(検索条件に使用するメソッドがMongoDBのクエリに変換できない場合は、さらにAsEnumerable()を呼び出す必要がある。)

// Linqによる検索
var q = from t in col.AsQueryable() where t.Name.StartsWith("ずもも")// (MongoDB Shellのdb.AddressBook.find(/^ずもも/)に相当 select t;

 

プログラム全体は以下のような感じとなる。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MongoDB.Driver;
using MongoDB.Driver.Builders;
using MongoDB.Driver.Linq;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;

namespace
MongoSample
{ class Program { static void Main(string[] args) { // ローカルMongoDBに接続 MongoClient cli = new MongoClient(); // Databaseを選択 MongoDatabase db = cli.GetServer().GetDatabase("TestDB"); // コレクションの取得 MongoCollection<AddressEntry> col = db.GetCollection<AddressEntry>("AddressBook"); // データ作成 if (col.Count() != 0) // データがあったら削除 { col.RemoveAll(); } AddressEntry entry = newAddressEntry() { Name = "すもも太郎", Birthday = DateTime.Parse("1964/02/03"), EmailAddrs = new List<Email>() { newEmail() { DisplayName = "すもも太郎", MailAddress = "T.Sumomo@momo.com" }, new Email() { DisplayName = "ぼのぼの", MailAddress = "Bonobono@bono.jp" } } }; // データ挿入 col.Insert(entry); ・・・ // Linqによる検索 var q = from t in col.AsQueryable() where t.Name.StartsWith("ずもも") select t;
foreach (var ent in q) { Console.WriteLine("Name = {0} {1}生まれ", ent.Name, ent.Birthday.ToString("yyyy年MM月dd日")); foreach (var email in ent.EmailAddrs) { Console.WriteLine("\t{0}<{1}>", email.DisplayName, email.MailAddress); } } // サーバ切断 cli.GetServer().Disconnect(); } }
}

他に、更新と削除,インデックス操作等があるが、今回はここまで。

カテゴリー: C#, LINQ, NO SQL, 技術情報 | 1件のコメント

MongoDBを触ってみた

BIGDATA,BIGDATAと騒がしい今日この頃。

BIGDATAの代名詞といえば、NO SQLデータベース。その中で人気の高いMongoDBを触ってみた。

MongoDBサーバ内にはDatabaseと呼ばれる、RDBのデータベースやスキーマに相当するものを作成することができ、その中にCollectionという、RDBのテーブルに相当するものを作成し、その中にデータを保存する。コレクション中のデータは単一の構造となっていなくてもよい。(実用的にするなら、ある程度の整形は必要だろう。)Collection中のデータはBSON(Binary化されたJSON)として格納される。

MongoDBのクライアントShellはJavascriptのインタープリタとなっており、Javascript+MongDB APIを使用することにより、データの参照,更新が可能である。

また、C,C++,C#,Java,Perl,PHPをはじめ、様々なアクセス用ライブラリ(ドライバと呼ばれる)が用意されており、特にオブジェクト指向言語の場合は、データを半自動的に変換する機能が備わっているので、非常に使いやすいと思う。

データ形式がJSONなので、オブジェクトを永続化するのに適している。例えば、以下のようなC#のクラスインスタンスをMongoDBにストアすると

class AddressBook
{
    [BsonId]
    public BsonObjectId _Id { get; set; }
    public string Name { get; set; }
    public string PhoneNumber { get; set; }
    public string MoblilePhone { get; set; }
    public List<Email> EMailAddresses { get; set; }
}
class Email
{
    public string DisplayName { get; set; }
    public string Address { get; set; }
}
Person p = new Person() {
    Name = "T.Sumomo",    PhoneNumber = "xx-xxxx-xxxx",
    MobilePhone = "xxx-xxxx-xxxx",
    EmailAddresses = new Email[]
    {
        new Email() { DisplayName = "会社", Address="xxxxxx@xxxx.xxx.com" },
        new Email() { DisplayName = "自宅", Address="yyyyyy@yyyy.yyy.com" }
    }
};

以下のようにシリアライズされる。

{
    "_id": ObjectId("xxxxxxxxxxxxx"),
    "Name": "T.Sumomo",
    "PhoneNumber": "xx-xxxx-xxxx",
    "MobilePhone": "xxx-xxxx-xxxx",
    "EmailAddresses":
        [
            {"DisplayName": "会社", "Address": "xxxxxx@xxxx.xxx.com" },
            {"DisplayName": "自宅", "Address": "yyyyyy@yyyy.yyy.com" }
        ]
}

上記の変換は前述のドライバにより、自動的に行われる(デシリアライズも同様)。データ型や、メンバ名などは、POCOやPOJOに属性やアノテーションを付ける事によりマッピングが可能。

C#のドライバにはLINQプロバイダも含まれており、データの検索をMongoDBのShellで使用するようなI/F(Find等),LINQの双方で行うことが可能である。

BIGDATAを扱う以外にも意外と使えるのではないだろうか?

カテゴリー: C#, NO SQL, 技術情報 | コメントする