<feed version="0.3" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns="http://purl.org/atom/ns#" xml:lang="ja-JP"><title>あきこのSQL ServerなBlog</title><link rel="alternate" type="text/html" href="http://blogs.sqlpassj.org/akiko/" /><tagline type="text/html">SQL Server関係の日々のメモです。</tagline><id>http://blogs.sqlpassj.org/akiko/</id><author><name>あきこ</name><url>http://blogs.sqlpassj.org/akiko/</url></author><generator url="http://scottwater.com/blog" version=".Text Version 0.95.2004.102">.Text</generator><modified>2008-05-15T11:00:00Z</modified><entry><title>Datetime型で、あれれ~？</title><link rel="alternate" type="text/html" href="http://blogs.sqlpassj.org/akiko/archive/2008/05/14/24769.aspx" /><id>http://blogs.sqlpassj.org/akiko/archive/2008/05/14/24769.aspx</id><created>2008-05-14T13:16:00Z</created><issued>2008-05-14T04:16:00+09:00</issued><modified>2008-05-15T11:00:00Z</modified><content type="text/html" mode="escaped">&lt;P&gt;私の部で扱っているシステムと、他部署のシステムとの間で、データ連携をするため、主にSSIS(Integration Services)を利用しています。&lt;/P&gt;
&lt;P&gt;また、主に相手側とのデータの受け渡しは、DBのコネクションではなく、Http/Httsが中心です。データのプロトコル、フォーマットXML-RPCの場合もあれば、CSV、Soap の場合もありますが、基本的にSSISのタスクで処理可能です。ちょっと具体例が少ないのが悲しいのですが、なんとかタスクを組み合わせてパッケージ作成、Agentジョブに登録して実行させています。&lt;/P&gt;
&lt;P&gt;さて、そんなある日。&lt;/P&gt;
&lt;P&gt;いつも問題なく稼働していたデータ受渡しのジョブが、ある日失敗してしまいました。相手は、Soap経由でデータをもらっているシステムです。&lt;/P&gt;
&lt;P&gt;失敗したのは、Webサービスタスクの部分。&lt;/P&gt;
&lt;P&gt;パッケージをVisual Studioで実行してみると、なるほど失敗してしまいます。Webサービスタスクから返って来るエラーは、こんな感じ。&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;&lt;FONT color=#a52a2a&gt;[Web Service Task] Error: An error occurred with the following error message: "Microsoft.SqlServer.Dts.Tasks.WebServiceTask.WebserviceTaskException: Could not execute the Web method. The error is: There was an error generating the XML document...... (実際は日本語です)&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;プロトコルにはHttpsを使っているのですが、同じWebサービスで提供している&lt;STRONG&gt;他のメソッド&lt;/STRONG&gt;は、&lt;STRONG&gt;Webサービスタスクで処理しても問題はありませんでしたので&lt;/STRONG&gt;、証明書切れなどの問題ではなさそうです。&lt;/P&gt;
&lt;P&gt;問題のメソッドだけが、プロトコルにはHttpsを使っているのですが、同じWebサービスで提供している他のメソッドは、Webサービスタスクで処理しても問題はありませんでしたので、証明書の問題ではなさそうです。&lt;/P&gt;
&lt;P&gt;問題のメソッドだけが、Webサービスタスクを通して呼び出すと、非常に長い時間処理待ちになり、ついには上記のエラーを出して止まってしまいます。実行されると返ってくるデータ量が多いメソッドなので、もしかしたらデータ量が多すぎてタイムアウトしちゃうんじゃないかしら.....とも思いました。&lt;/P&gt;
&lt;P&gt;さて、相手のシステム担当者に状況を聞いてみると、先方の環境では、テストしても問題はないとの事。（Rails環境で作ったWebサービスなので、Railsのテストクライアントでチェックしてもらいました。）&lt;/P&gt;
&lt;P&gt;でも、こちらでは失敗するのは変わらず。このデータ取り込み用のWebサービスがうまくいかないと、残りの関連するジョブを実行できません。&lt;/P&gt;
&lt;P&gt;やっていることは、Webサービスを実行し、結果をXMLとして保存し、そのデータをXSLTを使って（XML変換タスクで）CSVに変換、CSVファイルを同僚の担当するジョブに渡すというもの。&lt;/P&gt;
&lt;P&gt;要は、Webサービスの結果をCSVに変換できれば良いので、とりあえず代替として、相手のシステム担当者の環境にあわせ、RubyのコードでWebサービスを呼び出し、想定しているフォーマットでデータを取得し、CSVに書き出すことにしました。&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#a52a2a size=2&gt;＃RubyのコードでWebサービスの呼び出しを行うのは、結構簡単だったので、ちょっと驚きましたが(^^;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;
&lt;HR id=null&gt;

&lt;P&gt;&lt;/P&gt;
&lt;P&gt;さて、なんとか代替案を使って同じようなCSVが生成できたので、次に同僚のジョブを実行してもらいました。&lt;/P&gt;
&lt;P&gt;そうしたら、同僚のジョブの側でもエラーが発生。（これもSSISのパッケージで作ったもので、CSVからDBのテーブルに格納するというものです）&lt;/P&gt;
&lt;P&gt;エラーのリダイレクトなどで問題になるデータが何かチェックしたところ、どうやら、とある「&lt;STRONG&gt;日付&lt;/STRONG&gt;」のデータで変換エラーが発生していることが分りました。失敗前の取り込み結果との差分を見ると、このデータが登録された日以降、ジョブが失敗するようになっていました。&lt;/P&gt;
&lt;P&gt;問題の日付データは、なんと、「&lt;STRONG&gt;&lt;FONT color=#a52a2a&gt;20080-04-01&lt;/FONT&gt;&lt;/STRONG&gt;」となっていました。この列をSQL ServerのDATETIME型の列に取り込む際に、変換できずに失敗してしまったようです。（YYYY-MM-DDでは無いので。また、SQL ServerのDATETIME型だと、9999年までしかサポートしてないようですし）&lt;/P&gt;
&lt;P&gt;?結局、このデータが悪さをしているんだろうな、という予感がしました。もちろん、そういう（途方もなく先の）日付があるのも間違いでは無いでしょうけれど...。&lt;/P&gt;
&lt;P&gt;Webサービスのメソッドも、WSDLに従うと、この列は&lt;STRONG&gt;xsd:date&lt;/STRONG&gt;になっています。&lt;STRONG&gt;W3C&lt;/STRONG&gt;の決まりに従うと、フォーマットは"YYYY-MM-DD"でないといけないので、このフォーマットにマッチしないため、Webサービスタスクが失敗したのかなと判断。&lt;/P&gt;
&lt;P&gt;相手方のシステム担当者に「このデータって、間違いじゃないですか？」と問い合わせ、実際入力ミスだったようですので、データの修正をしてもらったところ、あっさりとWebサービスタスクのエラーが解消されてしまいました....。&lt;/P&gt;
&lt;P&gt;
&lt;HR id=null&gt;

&lt;P&gt;&lt;/P&gt;
&lt;P&gt;ただ、相手側も、日付情報はCHAR(String)ではなく日付型などでDB上にデータを格納しているはず。Railsで生成されたWSDLも、おそらくDBのデータ型に沿ってDATETIME型にしているはずです。&lt;/P&gt;
&lt;P&gt;ふと、先方のDBがなんだったか思い出すと、PostgreSQL。&lt;/P&gt;
&lt;P&gt;ちょっと調べてみると、日付をサポートする型には2つあるようで、TIMESTAMP型とDATETIME型が。PostgreSQLでのTIMESTAMP型は2038年までのようですが、DATETIME型は、どうやら「無制限」のようです(^^;&lt;/P&gt;
&lt;P&gt;おそらく相手のシステムでも、一般的なDATETIME型を利用しているのでしょう...。SQL ServerではDATETIME型に&amp;#8221;20080-04-01&amp;#8221;を登録しようとすると怒られちゃいますが、PostgreSQLの場合は、入力ミスであってもデータとしては受け入れ可能な範囲で、エラーにはならないと思われますし...。&lt;/P&gt;
&lt;P&gt;なんだか脱力でしたが、とりあえずWebサービスタスクで処理を行い、そちらが失敗した場合は、Rubyのコードでデータを生成するエラーハンドリングを追加しました。&lt;/P&gt;
&lt;P&gt;また、CSVを生成し、処理を完了する前に、日付やフォーマットのチェックを行う処理も組み込むことにしました。その際に、こちらで受け入れられないデータが存在する場合は、相手の担当者に、エラーを通知するようにもしてみるつもりです。&lt;/P&gt;&lt;img src ="http://blogs.sqlpassj.org/akiko/aggbug/24769.aspx" width = "1" height = "1" /&gt;</content><wfw:comment>http://blogs.sqlpassj.org/akiko/comments/24769.aspx</wfw:comment><slash:comments>0</slash:comments><wfw:commentRss>http://blogs.sqlpassj.org/akiko/comments/commentRss/24769.aspx</wfw:commentRss><trackback:ping>http://blogs.sqlpassj.org/akiko/services/trackbacks/24769.aspx</trackback:ping></entry><entry><title>制約の無効化とデータの削除。</title><link rel="alternate" type="text/html" href="http://blogs.sqlpassj.org/akiko/archive/2008/04/18/24696.aspx" /><id>http://blogs.sqlpassj.org/akiko/archive/2008/04/18/24696.aspx</id><created>2008-04-18T12:55:00Z</created><issued>2008-04-18T03:55:00+09:00</issued><modified>2008-04-18T12:55:00Z</modified><content type="text/html" mode="escaped">&lt;P&gt;緒事情により、DBのファイルサイズが実データに比してとても大きくなってしまい、メンテナンスのためにデータ移行(Export/Import)をさせないといけなくなりました。&lt;/P&gt;
&lt;P&gt;SSISのパッケージでもExport/Importは出来ますが、そのままではかゆいところに手が届かないので、その他のスクリプトを併用しつつ準備を進めています。&lt;/P&gt;
&lt;P&gt;さて、データの登録/削除のテストをしている時に、テーブルに制約があるとデータの削除が（もちろん）うまく行えません。&lt;/P&gt;
&lt;P&gt;制約の削除ではなく、無効化ってどうするんだっけ...と調べてみると、NOCHECKオプションで指定すれば良いということが分りました。&lt;/P&gt;
&lt;P&gt;でも、&lt;FONT color=#a52a2a&gt;根が横着者&lt;/FONT&gt;なので、&lt;STRONG&gt;全部のテーブルの制約を無効化するにはどうしたらいいかな&lt;/STRONG&gt;....と考え、ストアドを作ってみました。（ストアドについては、Articleの方に載せてみました: 　[ &lt;A id=viewpost.ascx_TitleUrl HREF="/akiko/articles/24695.aspx"&gt;DB内のオブジェクト（テーブル）の全部の制約を無効/有効にする&lt;/A&gt;&amp;nbsp;]　）&lt;/P&gt;
&lt;P&gt;一応期待通り、まとめて外部キーの制約を無効化/有効化できるようにはなったのですが、&lt;STRONG&gt;制約が無効であっても、TRUNCATEはできないんですね&lt;/STRONG&gt;....。&lt;/P&gt;
&lt;P&gt;＃Oracleは出来たと思ったのですが、違ったかな？&lt;/P&gt;
&lt;P&gt;DELETEは出来てもTRUNCATEさせたい場合は制約を削除しないといけないので、やっぱり、ちゃんとCreate TableとかDROP Constraint/ADD ConstraintのSQLを用意しておかないとダメなのかなあ、と思いました....。&lt;/P&gt;&lt;img src ="http://blogs.sqlpassj.org/akiko/aggbug/24696.aspx" width = "1" height = "1" /&gt;</content><wfw:comment>http://blogs.sqlpassj.org/akiko/comments/24696.aspx</wfw:comment><slash:comments>2</slash:comments><wfw:commentRss>http://blogs.sqlpassj.org/akiko/comments/commentRss/24696.aspx</wfw:commentRss><trackback:ping>http://blogs.sqlpassj.org/akiko/services/trackbacks/24696.aspx</trackback:ping></entry><entry><title>Subversion + VisualStudio</title><link rel="alternate" type="text/html" href="http://blogs.sqlpassj.org/akiko/archive/2008/02/07/24543.aspx" /><id>http://blogs.sqlpassj.org/akiko/archive/2008/02/07/24543.aspx</id><created>2008-02-07T09:13:00Z</created><issued>2008-02-07T00:13:00+09:00</issued><modified>2008-02-07T09:13:00Z</modified><content type="text/html" mode="escaped">&lt;P&gt;サーバサイドのアプリケーション（Webサービスなど）や、SSISパッケージ、CLR作成のため、普段はVisualStudioを使っています。&lt;/P&gt;
&lt;P&gt;その一方、クライアントアプリケーションの作成も行っていますが、こちらは&lt;STRONG&gt;Flex2.0/AIR&lt;/STRONG&gt;を使ったものが中心で、IDEには&lt;STRONG&gt;eclipse&lt;/STRONG&gt;を使っています。（必要に迫られ、へなちょこなPerlとかPythonなどもたまに書きます....）&lt;/P&gt;
&lt;P&gt;さて、チームの中では、VisualStudioを使う回数が多いのは私だけなので、ソースコードの管理には、どちらかというと&lt;STRONG&gt;Subversion&lt;/STRONG&gt;が主になってきます。&lt;/P&gt;
&lt;P&gt;eclipseにはSubverion用のプラグインがありますので、特に問題無し。&lt;/P&gt;
&lt;P&gt;VisualStudioの場合はどうしようかな....と思い、最初は、&lt;A href="http://tortoisesvn.net/docs/nightly/TortoiseSVN_ja/index.html"&gt;TortoiseSVN&lt;/A&gt;だけを使っていたのですが、やっぱりIDEの中からコミットやUpdate、差分の確認をしたくなりました。そこでプラグインを探したところ、&lt;A href="http://ankhsvn.tigris.org/"&gt;AnkhSVN&lt;/A&gt;というものを発見。&lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.visualsvn.com/"&gt;VisualSVN&lt;/A&gt;という、有償のツールもありますが、今のところ、AnkhSVNで十分という感じです。&lt;/P&gt;
&lt;P&gt;逆に、&lt;STRONG&gt;Visual SourceSafe &lt;/STRONG&gt;のほうは使ったことがありません......。もしかしたら、物凄く便利なんでしょうか.....(^^;&lt;/P&gt;&lt;img src ="http://blogs.sqlpassj.org/akiko/aggbug/24543.aspx" width = "1" height = "1" /&gt;</content><wfw:comment>http://blogs.sqlpassj.org/akiko/comments/24543.aspx</wfw:comment><slash:comments>0</slash:comments><wfw:commentRss>http://blogs.sqlpassj.org/akiko/comments/commentRss/24543.aspx</wfw:commentRss><trackback:ping>http://blogs.sqlpassj.org/akiko/services/trackbacks/24543.aspx</trackback:ping></entry><entry><title>信頼可能オプション: アタッチだけではダメだった...。</title><link rel="alternate" type="text/html" href="http://blogs.sqlpassj.org/akiko/archive/2008/02/01/24524.aspx" /><id>http://blogs.sqlpassj.org/akiko/archive/2008/02/01/24524.aspx</id><created>2008-02-01T09:42:00Z</created><issued>2008-02-01T00:42:00+09:00</issued><modified>2008-02-01T09:43:00Z</modified><content type="text/html" mode="escaped">&lt;P&gt;＃2008で遊んでみたいな...と思いながらも、手が出せずにいるこの頃です(^^;&lt;/P&gt;
&lt;P&gt;さて、またもや失敗の話題です。今回の失敗は、CLRに関する事でした。&lt;/P&gt;
&lt;P&gt;現在、Transact-SQLでカバー仕切れない処理などを、CLRを使ってコーディングしています。（データを正規表現を使ってSELECTさせたり、ストアドの実行結果を受けて外部プログラムをキックする、といった処理です）&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#a52a2a size=2&gt;＃CLRについては、賛否両論あるかと思いますが、どうしても方法が思いつかなかったので、利用しています...。&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;実際のアプリ/DBは、まだ開発段階なので、DBの停止も可能。βテスト分（という大層なものではないのですが）を公開するため、開発環境からDBをデアタッチして、コピーし、公開用のサーバにアタッチしました。（このDBには、CLR用のアセンブリも登録されています）&lt;/P&gt;
&lt;P&gt;もちろん、公開用のSQL Serverも、CLRを有効に設定しておきました。&lt;/P&gt;
&lt;P&gt;DBのアタッチは問題なく終了。関連するDBも、テスト環境で使っていたのと同じものを使い、動作的には全く同じに動くはずでした。&lt;/P&gt;
&lt;P&gt;早速チェックを始めたのですが、普通のストアドも問題なく動いたので、「これで良いかな～」と、ひと安心。&lt;/P&gt;
&lt;P&gt;ところが、同僚から『ストアドを実行するとエラーになっちゃうんですけど～』の声が...。&lt;/P&gt;
&lt;P&gt;「なんで？ソースもデータもおんなじDBのはずなのに？？」と不審に思いながら、問題のストアドを実行すると、&lt;STRONG&gt;&lt;FONT color=#a52a2a&gt;私の担当した部分&lt;/FONT&gt;&lt;/STRONG&gt;でエラーが発生していました...。問題は、&lt;STRONG&gt;CLRで関数を実行している&lt;/STRONG&gt;箇所で発生していました。&lt;/P&gt;
&lt;P&gt;エラーメッセージは、この通り。&lt;/P&gt;&lt;PRE&gt;&lt;FONT color=#a52a2a&gt;
「アセンブリ ID 65648 をロード中に Microsoft .NET Framework でエラーが発生しました。
サーバーのリソースが不足しているか、PERMISSION_SET が EXTERNAL_ACCESS または UNSAFE 
に設定されていて、アセンブリが信頼されていない可能性があります。」&lt;/FONT&gt;
&lt;/PRE&gt;
&lt;P&gt;Management Studioで問題のアセンブリを参照すると、特にエラーのような表示は出ていません。関数も登録されています。（デタッチ/アタッチしただけなで）&lt;/P&gt;
&lt;P&gt;でも、単純にCLRを単体で実行しても、同じエラーが....。&lt;/P&gt;
&lt;P&gt;仕方なく、Visual Studioで、テスト公開用のDBに配布しなおしてみようとしたところ、これまたエラー。（開発用ではエラーになりません）&lt;/P&gt;
&lt;P&gt;あわてて調べると、アタッチしたDBの&lt;STRONG&gt;TRUSTWORTHY&lt;/STRONG&gt;プロパティが、&lt;STRONG&gt;False&lt;/STRONG&gt;だったことが発覚。&lt;/P&gt;
&lt;P&gt;この値は、ManagementStudioからは変更できなかったので、&amp;nbsp; ALTER DATABASE&amp;nbsp;xxxxDB SET TRUSTWORTHY ON でTrueに変更したところ、配布OKになりました。&lt;/P&gt;
&lt;P&gt;単純に、DBをアタッチするだけでは、TRUSTWORTHYの値は引き継がれないんですね.....。（どこのものとも分からないアセンブリをそのまま信頼するのは、確かに問題なんでしょうけれど） &lt;/P&gt;&lt;img src ="http://blogs.sqlpassj.org/akiko/aggbug/24524.aspx" width = "1" height = "1" /&gt;</content><wfw:comment>http://blogs.sqlpassj.org/akiko/comments/24524.aspx</wfw:comment><slash:comments>1</slash:comments><wfw:commentRss>http://blogs.sqlpassj.org/akiko/comments/commentRss/24524.aspx</wfw:commentRss><trackback:ping>http://blogs.sqlpassj.org/akiko/services/trackbacks/24524.aspx</trackback:ping></entry><entry><title>PerlからADO</title><link rel="alternate" type="text/html" href="http://blogs.sqlpassj.org/akiko/archive/2008/01/04/24442.aspx" /><id>http://blogs.sqlpassj.org/akiko/archive/2008/01/04/24442.aspx</id><created>2008-01-04T09:44:00Z</created><issued>2008-01-04T00:44:00+09:00</issued><modified>2008-01-04T09:49:00Z</modified><content type="text/html" mode="escaped">&lt;P&gt;
&lt;HR id=null&gt;
最近、&lt;STRONG&gt;Perl&lt;/STRONG&gt;からSQL Serverへの接続を行うコードを書いていたので、その覚え書きです。 
&lt;HR id=null&gt;

&lt;P&gt;&lt;/P&gt;
&lt;P&gt;実は、ストアドや.NET系のコーディングを始める前は、PerlやJavaがメインで、DB操作のためのSQLは、コードや設定ファイルの中に書くことが中心でした。(ただしOracleとかでした)&lt;/P&gt;
&lt;P&gt;その後、SQL Serverを中心にお仕事をするようになってから、ストアドを多用するようになり、コードもC#などで書くようになっていきました。&lt;/P&gt;
&lt;P&gt;さて今回、XML-RPCで外部APIと連携を行う必要が出たので、PerlでSQL Serverの操作を行うことになりました。（C#でもXML-RPCは実装可能だったのですが、私以外のメンテナーがいないので、同僚がメンテナンスしやすいPerlで行きましょう、ということになったのでした...）&lt;/P&gt;
&lt;P&gt;ただ、私としては、できるだけ面倒なSQLはコードに書かず、サーバ側のストアドでカバーしたいというのが希望でした。同僚も、SQL(ストアド）の方は操作/修正には問題無いので、この方針で。&lt;/P&gt;
&lt;UL&gt;
&lt;UL&gt;
&lt;LI&gt;ストアドを使うメリットは、まずは、Perl中にSQLを書かなくて済むこと。（コード内で、@や\といった特殊文エスケープしたりするのが面倒なんですよね....） 
&lt;LI&gt;同じストアドは（データ取得用ですけど）、ManagementStudioからも呼べるし、WebServiceでも呼び出せます。JavaのJDBCでも呼べますね。 &lt;/LI&gt;&lt;/UL&gt;&lt;/UL&gt;
&lt;P&gt;さて、問題は、PerlのDBIで、SELECTステートメントを返すストアドをどう実行するか、ということと、複数SELECTの結果が返る場合、値をどうやって取得するかです。&lt;/P&gt;
&lt;UL&gt;
&lt;UL&gt;
&lt;LI&gt;どうやらDBI + ODBCだとうまくできません....。（というか、とんでもなく久しぶりなので、よく分らない） 
&lt;LI&gt;かと言って、またもPerl中に長～いSQLは書きたくない。&lt;/LI&gt;&lt;/UL&gt;&lt;/UL&gt;
&lt;P&gt;一方、ADO .NETだと、SELECT結果は、複数STATEMENTも含め、DataSetというオブジェクトで返してくれるので、それぞれテーブル名や順番に取り出すことができます。（ここが、私が.NETのASPにしたいよ～と言った理由のひとつでした）&lt;/P&gt;
&lt;P&gt;で、かなり時間がかかってしまったのですが、調べた結果、&lt;STRONG&gt;Win32::OLE&lt;/STRONG&gt;を使うと、&lt;STRONG&gt;ADOを用できることが判明&lt;/STRONG&gt;。&lt;/P&gt;
&lt;P&gt;若干C#などで扱うのよりは面倒ではありますが、これでいくらか幸せになりました。&lt;/P&gt;
&lt;P&gt;
&lt;HR id=null&gt;

&lt;P&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000080 size=2&gt;use strict;&lt;BR&gt;use Win32::OLE;&lt;BR&gt;use vars qw($dsn);&lt;BR&gt;&lt;BR&gt;# Data Source Setting&lt;BR&gt;$dsn = "driver=SQL Server;".&lt;BR&gt;&amp;nbsp;"Server=localhost;".&lt;BR&gt;&amp;nbsp;"database=TestDB;".&lt;BR&gt;&amp;nbsp;"Trusted_Connection=no;".&lt;BR&gt;&amp;nbsp;"AutoTranslate=No;";&lt;BR&gt;&lt;BR&gt;# Connection Open&lt;BR&gt;my $Conn = Win32::OLE-&amp;gt;new("ADODB.Connection");&lt;BR&gt;$Conn-&amp;gt;{CursorLocation} = 3;? # the same as adUseClient&lt;BR&gt;$Conn-&amp;gt;{Open} = $dsn;&lt;BR&gt;&lt;BR&gt;if (Win32::OLE-&amp;gt;LastError() != 0) {&lt;BR&gt;&amp;nbsp; print "Failed creating ADODB.Connection object -&amp;gt; "&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; . Win32::OLE-&amp;gt;LastError();&lt;BR&gt;&amp;nbsp; exit 0;&lt;BR&gt;}&lt;BR&gt;&lt;BR&gt;my $Cmd = Win32::OLE-&amp;gt;new("ADODB.Command");&lt;BR&gt;&lt;BR&gt;if (Win32::OLE-&amp;gt;LastError() != 0) {&lt;BR&gt;&amp;nbsp;&amp;nbsp; print "Failed creating ADODB.Command object -&amp;gt; "&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; . Win32::OLE-&amp;gt;LastError();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;exit 0;&lt;BR&gt;}&lt;BR&gt;&lt;BR&gt;my $Id;&lt;BR&gt;my $ReferenceId;&lt;BR&gt;&lt;BR&gt;####&lt;BR&gt;# For Test&lt;BR&gt;#&lt;BR&gt;# 実際は、CGIのRequest Parameterやコマンドライン引数などから受け取ります。&lt;BR&gt;#&lt;BR&gt;###&lt;BR&gt;$Id = 8;&lt;BR&gt;$ReferenceId= 300;&lt;BR&gt;&lt;BR&gt;# Command Execute&lt;BR&gt;$Cmd-&amp;gt;{CommandType} = 4; # Execute as Stored&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000080 size=2&gt;# Prepared Statementを使わない場合はこんなかんじ。&lt;BR&gt;$Cmd-&amp;gt;{CommandText} = &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; "dbo.getSampleData ($Id, $ReferenceId )";&lt;BR&gt;$Cmd-&amp;gt;{CursorLocation} = 3;&lt;BR&gt;$Cmd-&amp;gt;{ActiveConnection} = $Conn;&lt;BR&gt;&lt;BR&gt;$Cmd-&amp;gt;{Prepared} = 1;&lt;BR&gt;$Cmd-&amp;gt;{CommandTimeout} = 15;&lt;BR&gt;&lt;BR&gt;my $rs = $Cmd-&amp;gt;Execute();&lt;BR&gt;&lt;BR&gt;if (Win32::OLE-&amp;gt;LastError() != 0) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; print "Failed opening ADODB.Recordset object for Command -&amp;gt; ". Win32::OLE-&amp;gt;LastError();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; exit 0;&lt;BR&gt;}&lt;BR&gt;&lt;BR&gt;my $rs_count = $rs-&amp;gt;{RecordCount};&lt;BR&gt;print $rs_count . "\n";&lt;BR&gt;if (!$rs_count) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; print "Record not found to post or close.\n";&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; exit 0;&lt;BR&gt;}&lt;BR&gt;&lt;BR&gt;print "\n------------1st SELECT Result-------------\n";&lt;BR&gt;while ($rs-&amp;gt;EOF != 1) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; print "Id = ". $rs-&amp;gt;Fields('Id')-&amp;gt;{Value}."\n";&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; print "Name = ". $rs-&amp;gt;Fields('Name')-&amp;gt;{Value}."\n";&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; :&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $rs-&amp;gt;MoveNext();&lt;BR&gt;}&lt;BR&gt;&lt;BR&gt;my $rs1 = $rs-&amp;gt;NextRecordSet();&lt;BR&gt;&lt;BR&gt;print "\n------------2nd SELECT Result-------------\n";&lt;BR&gt;while ($rs1-&amp;gt;EOF != 1) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; print "ReferenceId = ". $rs-&amp;gt;Fields('ReferenceId')-&amp;gt;{Value}."\n";&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; print "ProductName = ". $rs-&amp;gt;Fields('ProductName')-&amp;gt;{Value}."\n";&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000080 size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;:&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000080 size=2&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;&lt;FONT color=#000080 size=2&gt;$rs1-&amp;gt;MoveNext();&lt;BR&gt;}&lt;BR&gt;$rs-&amp;gt;Close();&lt;BR&gt;$Conn-&amp;gt;Close();&lt;BR&gt;exit 0;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;
&lt;HR id=null&gt;

&lt;P&gt;&lt;/P&gt;
&lt;P&gt;Prepared Statementを使ってストアド実行時の引数を渡したい場合は、こんな感じ。&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000080 size=2&gt;$Cmd-&amp;gt;{Prepared} = 1;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000080 size=2&gt;#ストアドの戻り値を指定する場合　（Direction = 4）&lt;BR&gt;$Cmd-&amp;gt;Parameters-&amp;gt;Append(&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; $Cmd-&amp;gt;CreateParameter(&lt;/FONT&gt;&lt;A href="mailto:'@retval'"&gt;&lt;FONT color=#000080 size=2&gt;'@retval'&lt;/FONT&gt;&lt;/A&gt;&lt;FONT color=#000080 size=2&gt;, 3, 4));&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000080 size=2&gt;# ストアドへの引数はこちら&lt;BR&gt;$Cmd-&amp;gt;Parameters-&amp;gt;Append($Cmd-&amp;gt;CreateParameter(&lt;/FONT&gt;&lt;A href="mailto:'@Id'"&gt;&lt;FONT color=#000080 size=2&gt;'@Id'&lt;/FONT&gt;&lt;/A&gt;&lt;FONT color=#000080 size=2&gt;, 3, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 1, , $Id));&lt;BR&gt;$Cmd-&amp;gt;Parameters(&lt;/FONT&gt;&lt;A href="mailto:'@Id')-&gt;{Value"&gt;&lt;FONT color=#000080 size=2&gt;'@Id')-&amp;gt;{Value&lt;/FONT&gt;&lt;/A&gt;&lt;FONT color=#000080 size=2&gt;} = $Id; &lt;BR&gt;　　:&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000080 size=2&gt;my $rs = $Cmd-&amp;gt;Execute();&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000080 size=2&gt;if (Win32::OLE-&amp;gt;LastError() != 0) {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; adoError(Win32::OLE-&amp;gt;LastError());&lt;BR&gt;}&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#000080 size=2&gt;# 戻り値を取得します&lt;/FONT&gt;&lt;FONT color=#000080 size=2&gt;&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#000080 size=2&gt;$retval = $Cmd-&amp;gt;Parameters(&lt;A href="mailto:'@retval')-&gt;{Value"&gt;'@retval')-&amp;gt;{Value&lt;/A&gt;};&lt;BR&gt;&lt;/FONT&gt;
&lt;HR id=null&gt;

&lt;P&gt;&lt;/P&gt;
&lt;P&gt;ただ、通常のADOのように、PerlからでもResultSetにテーブル名を付けて、明示的にアクセスできるのかは、まだ分りませんでした....。&lt;/P&gt;
&lt;P&gt;また、ストアドへのパラメータを指定する部分は、Win32::OLE::Variantを使えばもっといいのかもしれませんが、うまく動かなかったので、以下のサイトを参考に直接値を指定しました。&lt;BR&gt;&lt;/P&gt;
&lt;P&gt;&lt;A href="http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/jpdnvid/htm/VintrDev/VISQL/visql.asp"&gt;http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/jpdnvid/htm/VintrDev/VISQL/visql.asp&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;また、コーディングの際は、ActivePerlを使い、eclipse + Perl EPICというPerl用のプラグインを使ってみました。これもなかなか便利でした。(Visual Perlっていうのもあるんですね)&lt;/P&gt;&lt;img src ="http://blogs.sqlpassj.org/akiko/aggbug/24442.aspx" width = "1" height = "1" /&gt;</content><wfw:comment>http://blogs.sqlpassj.org/akiko/comments/24442.aspx</wfw:comment><slash:comments>0</slash:comments><wfw:commentRss>http://blogs.sqlpassj.org/akiko/comments/commentRss/24442.aspx</wfw:commentRss><trackback:ping>http://blogs.sqlpassj.org/akiko/services/trackbacks/24442.aspx</trackback:ping></entry><entry><title>AD:レプリケートしたのはいいけれど。</title><link rel="alternate" type="text/html" href="http://blogs.sqlpassj.org/akiko/archive/2007/11/26/24328.aspx" /><id>http://blogs.sqlpassj.org/akiko/archive/2007/11/26/24328.aspx</id><created>2007-11-26T12:27:00Z</created><issued>2007-11-26T03:27:00+09:00</issued><modified>2007-11-27T04:00:00Z</modified><content type="text/html" mode="escaped">&lt;P&gt;またもトラブル系、失敗系のお話です...。&lt;/P&gt;
&lt;P&gt;
&lt;HR id=null&gt;

&lt;P&gt;&lt;/P&gt;
&lt;P&gt;試行錯誤しながらWindowsのドメイン環境で生活し始めて、3年ほどが過ぎました。&lt;/P&gt;
&lt;P&gt;ドメイン生活のきっかけは、異動先の部署に、買ったばかりの&lt;STRONG&gt;Small Business Server&lt;/STRONG&gt;? 2003 (以下：SBS)があったからです。&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;&lt;FONT color=#a52a2a size=2&gt;※ただ、上司によると、別にドメイン生活がしたかったわけではなく、&lt;U&gt;SharePointとSQL ServerとExchange Serverがバンドルされていたから&lt;/U&gt;、SBSを購入したとのこと。結局、この機能を使うためには、ドメイン利用が必要になったのですが....。&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;その後、SQL Serverの利用を中心に、試行錯誤しつつもドメインでの生活を続けていきました。一度この環境に慣れてしまうと、とくに認証まわりが便利になるため、ドメインに参加させるサーバやクライアントPCが、次第に増えていきました。&lt;/P&gt;
&lt;P&gt;
&lt;HR id=null&gt;
&lt;BR&gt;ただ、ドメインコントローラ（以下DC）と、メンバサーバのネットワークセグメントが別なため、ネットワークトラブルの時は、DCとの通信ができず、困ることもありました。これについては、同じネットワーク内にDCの複製を作ることで対応しました。（このあたりも、管理ツールお任せで、あまり深く考えずに行っていました）
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;さて、ドメインの利用は、Virtual Serverを導入したことで、さらに増えていきました。&lt;/P&gt;
&lt;P&gt;ここで私は、「DCの冗長性のために、仮想マシンでもDCを複製しておこう！」と考えました。これも、作成と複製自体は、あっさり終了しました。&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;&lt;FONT color=#a52a2a size=2&gt;※実は、D&lt;/FONT&gt;&lt;FONT color=#a52a2a size=2&gt;C同士は同じOSでないとダメという制限があるようで、複製のサーバは、Windwos 2003 R2にしようと思ったのですが、SBSに合わせたOS/ServicePackでしか稼働させることができませんでした....。また、Windows 2003 Serverとは言え、SBSはどうやら特別らしく、これも正直なところ扱いに難儀したのですが。&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;とりあえず仮想マシンも含め、DCは3台になり、私も少しは安心感がアップ。&lt;/P&gt;
&lt;P&gt;ところが、その後、Virtual Serverのリソースを別の仮想マシンに多く割り当てないといけない状況になり、リソース節約のために、&lt;FONT color=#a52a2a&gt;DCとして作成した仮想マシンを停止させることにしました&lt;/FONT&gt;。&lt;/P&gt;
&lt;P&gt;
&lt;HR id=null&gt;

&lt;P&gt;&lt;/P&gt;
&lt;P&gt;そのまま、すっかり停止させていたことを忘れて、いつしか2ケ月ほどが経過。&lt;/P&gt;
&lt;P&gt;やがて、最初のDCとなったSBSのサーバ状況のレポートメールから、「&lt;STRONG&gt;NTDS Replication / EventID: 1864&lt;/STRONG&gt;」のエラーが通知されるようになりました。もちろん、原因はDCの仮想マシンを停止させてしまったことでした.....。&lt;/P&gt;
&lt;P&gt;&lt;FONT size=2&gt;＃あとから知ったのですが、仮想マシンを使う場合の注意事項は、ちゃんと、こんなところに出ているんですね(^^;;;&lt;/FONT&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://support.microsoft.com/kb/888794/ja"&gt;&lt;FONT size=2&gt;&lt;FONT color=#000080&gt;仮想ホスト環境で Active Directory ドメイン コントローラをホストする場合の考慮事項&lt;/FONT&gt;&lt;/FONT&gt;&lt;/A&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;FONT size=2&gt;&amp;nbsp;&lt;/FONT&gt;&lt;A href="http://support.microsoft.com/kb/888794/ja"&gt;&lt;FONT size=2&gt;http://support.microsoft.com/kb/888794/ja&lt;/FONT&gt;&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;とりあえずサポートツールをDCになっている各サーバにインストールし、repadminを使って、あとからメンテナンスすれば良いや～、と単純に思って悠長に構えていました。実際、警告が出てから半月くらいは、特に問題は無かったからです。&lt;/P&gt;
&lt;P&gt;ところが、3連休中に、この同期のための有効期限(tombstone)が切れてしまっていたのです...。&lt;/P&gt;
&lt;P&gt;さて、大変なのが後始末。&lt;/P&gt;
&lt;P&gt;単純に同期を取り直そうとしても、時すでに遅く、素直には実施できません。&lt;/P&gt;
&lt;P&gt;じゃあ、DCから降格させれば良いかな、と思ったのですが、これまた正常に複製されていて、同期が取れた状態でないと、降格できなかったのです。&lt;/P&gt;
&lt;P&gt;ドメインのメンバには、SBSのDCをプライマリのDNSとしていたので、SBSのDCが大丈夫なら問題ないかな、と考えていたのですが、これも甘かったようで、&lt;FONT color=#a52a2a&gt;&lt;STRONG&gt;ドメインへのログオンが失敗する&lt;/STRONG&gt;&lt;/FONT&gt;、といったトラブルに見舞われてしまいました。&lt;/P&gt;
&lt;P&gt;この原因は、グローバルカタログになっているDCにエラーが発生すると生じる問題のようなのですが、私は、詳しい理由がまだ見つけられていません。&lt;/P&gt;
&lt;P&gt;ひとまず、クライアントを再起動すれば、ドメインへのログオンが出来るようになったのですが....。&lt;/P&gt;
&lt;P&gt;
&lt;HR id=null&gt;

&lt;P&gt;&lt;/P&gt;
&lt;P&gt;自分の出来心のおかげで、とんでもないことになった連休明けでした。（幸い、メインに利用されていた2台のDC間で同期は取れていたので、被害はまだ少ないのですが）&lt;/P&gt;
&lt;P&gt;あれこれ試した結果、なんとか同期を取らせ、DCの降格まで行うことができました。この顛末は、また別途。&lt;/P&gt;
&lt;P&gt;とか言いつつ、まだ落とし穴がありそうな気もします。&lt;/P&gt;
&lt;P&gt;知識も乏しいのに、DCをいじった事には変わりないので、これでしばらく様子を見ないといけません...。&lt;/P&gt;&lt;img src ="http://blogs.sqlpassj.org/akiko/aggbug/24328.aspx" width = "1" height = "1" /&gt;</content><wfw:comment>http://blogs.sqlpassj.org/akiko/comments/24328.aspx</wfw:comment><slash:comments>0</slash:comments><wfw:commentRss>http://blogs.sqlpassj.org/akiko/comments/commentRss/24328.aspx</wfw:commentRss><trackback:ping>http://blogs.sqlpassj.org/akiko/services/trackbacks/24328.aspx</trackback:ping></entry><entry><title>トランザクションのネスト対応について</title><link rel="alternate" type="text/html" href="http://blogs.sqlpassj.org/akiko/archive/2007/11/16/24282.aspx" /><id>http://blogs.sqlpassj.org/akiko/archive/2007/11/16/24282.aspx</id><created>2007-11-16T11:16:00Z</created><issued>2007-11-16T02:16:00+09:00</issued><modified>2007-11-16T15:14:00Z</modified><content type="text/html" mode="escaped">&lt;P&gt;先の投稿で書いた、「&lt;A id=viewpost.ascx_TitleUrl href="/akiko/archive/2007/10/09/24108.aspx"&gt;知らなかった：ストアドプロシージャのネスト。&lt;/A&gt;」の続き。&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#a52a2a&gt;一緒にコーディングしていた同僚の働きママさんに、大変ご迷惑をおかけしてしまいました...。&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;その後、自分なりに認識した制限と、対策をこちらのArticleのほうに書いてみました。&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&amp;nbsp;&lt;A class=entrylisttitle id=CategoryEntryList.ascx_EntryStoryList_Entries__ctl1_TitleUrl href="/akiko/articles/24280.aspx"&gt;トランザクションのネスト対応&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;おそらくまだ不備なところとか、認識間違いがありそうな気がしますので、後学のために、ご指摘いただければ幸いです。&lt;/P&gt;
&lt;P&gt;今回も含め、色々システム連携の必要が出てきて、改めて難しさや自分の情けなさを痛感。&lt;/P&gt;
&lt;P&gt;以前、ESB製品のセミナーを受けた時、トレーナーの方が、サービス連携のポイントを以下のように話してくださっていました。&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;各システムの提供するサービスは、『粒度を荒く』して作る。 
&lt;LI&gt;小さなサービスをラップ（マッシュアップ）して、大きな『ビジネスプロセス』を作る 
&lt;UL&gt;
&lt;LI&gt;&lt;STRONG&gt;オーケストレーション&lt;/STRONG&gt;、という表現だったかと。&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;ストアドプロシージャや関数も、できるだけ小さな処理単位で作って、いろんなところで再利用できるようにしたいな...と思っていたんですが、なかなか私には難しいところです..。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;img src ="http://blogs.sqlpassj.org/akiko/aggbug/24282.aspx" width = "1" height = "1" /&gt;</content><wfw:comment>http://blogs.sqlpassj.org/akiko/comments/24282.aspx</wfw:comment><slash:comments>0</slash:comments><wfw:commentRss>http://blogs.sqlpassj.org/akiko/comments/commentRss/24282.aspx</wfw:commentRss><trackback:ping>http://blogs.sqlpassj.org/akiko/services/trackbacks/24282.aspx</trackback:ping></entry><entry><title>FOR XML PATHモード。</title><link rel="alternate" type="text/html" href="http://blogs.sqlpassj.org/akiko/archive/2007/11/13/24258.aspx" /><id>http://blogs.sqlpassj.org/akiko/archive/2007/11/13/24258.aspx</id><created>2007-11-13T16:57:00Z</created><issued>2007-11-13T07:57:00+09:00</issued><modified>2007-11-13T16:57:00Z</modified><content type="text/html" mode="escaped">&lt;DIV class=entryBody&gt;
&lt;P class=plain&gt;覚え書きのようなものですが....。&lt;/P&gt;
&lt;P class=plain&gt;SQL Server 2005では、FOR　XMLの機能が、かなり良くなっていました。（私個人的には、『とっても』でした）&lt;/P&gt;
&lt;P class=plain&gt;SQL Server 2000の時と同じ、&lt;STRONG&gt;FOR XML Auto　&lt;/STRONG&gt;とか &lt;STRONG&gt;RAW&lt;/STRONG&gt;モードももちろん使えます。&lt;BR&gt;ただし、上記のモードだと、お手軽ではあるんですが、Viewや一時テーブル、テーブル変数を使ったSELECTが、思いもよらないXMLで出力されることがありました。&lt;/P&gt;
&lt;P class=plain&gt;でも、2005だと、PATHモードのおかげで、かなり自分の希望に近い形で、XMLを出力させることができるようになりました。&lt;/P&gt;
&lt;DIV class=plain&gt;
&lt;HR&gt;
&lt;/DIV&gt;
&lt;P class=plain&gt;[今までのパターン]&lt;/P&gt;
&lt;P class=plain&gt;SELECT Id AS Id, Name AS Name, ISNULL(NickName, Name) AS NickName&lt;BR&gt;&amp;nbsp;&amp;nbsp; FROM [Test].[DocumentType]&amp;nbsp; AS "DocumentType"&lt;BR&gt;&amp;nbsp; WHERE IsEnabled = 1&lt;BR&gt;&amp;nbsp; &lt;FONT color=#000080&gt;FOR XML Auto, Elements&lt;/FONT&gt;&lt;/P&gt;
&lt;P class=plain&gt;-- 実行結果&lt;/P&gt;
&lt;P class=plain&gt;&amp;lt;DocumentType&amp;gt;&lt;BR&gt;&amp;nbsp; &amp;lt;Id&amp;gt;1&amp;lt;/Id&amp;gt;&lt;BR&gt;&amp;nbsp; &amp;lt;Name&amp;gt;見積り&amp;lt;/Name&amp;gt;&lt;BR&gt;&amp;nbsp; &amp;lt;NickName&amp;gt;みつもり&amp;lt;/NickName&amp;gt;&lt;BR&gt;&amp;lt;/DocumentType&amp;gt;&lt;BR&gt;&amp;lt;DocumentType&amp;gt;&lt;BR&gt;&amp;nbsp; &amp;lt;Id&amp;gt;3&amp;lt;/Id&amp;gt;&lt;BR&gt;&amp;nbsp; &amp;lt;Name&amp;gt;交通費精算&amp;lt;/Name&amp;gt;&lt;BR&gt;&amp;nbsp; &amp;lt;NickName&amp;gt;こうつうひ&amp;lt;/NickName&amp;gt;&lt;BR&gt;&amp;lt;/DocumentType&amp;gt;&lt;/P&gt;
&lt;P class=plain&gt;上記は、FOR　XML Autoモードの場合ですが、SELECT結果が複数あった場合は、1行につき1つのXMLで、複数のXMLが返ります。(e4x的に言うと、XMLListという感じでした。)&lt;/P&gt;
&lt;P class=plain&gt;この場合、私が直面した困った点は、以下の通りです。&lt;/P&gt;
&lt;DIV class=plain&gt;
&lt;UL&gt;
&lt;LI&gt;ドキュメントルートのタグ（たとえば&amp;lt;root&amp;gt;...&amp;lt;/root&amp;gt;）タグは自分でつけないといけませんでした。 
&lt;LI&gt;また、要素と属性を混在したXMLにするには、&lt;STRONG&gt;EXPLICITモード&lt;/STRONG&gt;とかを使わないといけなかったのですが、これが非常にわかりづらいものでした。 
&lt;LI&gt;Viewを連結させた場合は、予想外の入れ子構造になっていたりしました。&lt;/LI&gt;&lt;/UL&gt;&lt;/DIV&gt;
&lt;DIV class=plain&gt;なんとかあれこれ操作して、解決はできていたのですが、制限があって断念していたことも、いくつかありました。&lt;/DIV&gt;
&lt;DIV class=plain&gt;&amp;nbsp;&lt;/DIV&gt;
&lt;HR&gt;

&lt;P&gt;&lt;STRONG&gt;[PATHモード利用]&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;さて、2005のドキュメントを見ると、PATHモードというものがあるのに、遅ればせながら気が付きました。&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;PATHモードを利用すると、わりと理解しやすいSQLで、XMLの出力をコントロールできるようになります。 
&lt;LI&gt;EXPLICITモードというのが2000から使えたので、試してみたのですが、上記の通り、これが超理解に苦しみました。PATHモードを知った時、先にこっちを知っていれば...と、すくなからず後悔しました。&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;さて、SQLはこんな感じに指定しました。AS -&amp;gt; 要素名、@ -&amp;gt; 属性名になり、データは要素/属性のテキストノードとして格納されます。&lt;/P&gt;
&lt;P&gt;SELECT (SELECT [Id] AS "@Id",&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[Name] AS "@Name"&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ISNULL([NickName], [Name]) AS "@NickName"&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;FROM [Test].[DocumentType] &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; WHERE IsEnabled = 1&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;FONT color=#a52a2a&gt;FOR XML PATH('Item'),&lt;/FONT&gt; TYPE) AS "DocumentType"&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;FONT color=#a52a2a&gt;FOR XML PATH(''), ROOT('root')&lt;/FONT&gt; -- root要素を追加&lt;/P&gt;
&lt;P&gt;-- 実行結果&lt;/P&gt;
&lt;P&gt;&amp;lt;root&amp;gt;&lt;BR&gt;&amp;nbsp; &amp;lt;DocumentType&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;Item Id="1" Name="見積り" NickName="みつもり" /&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;Item Id="3" Name="交通費精算" NickName="こうつうひ" /&amp;gt;&lt;BR&gt;　　　　　　　　　　　：&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;Item Id="5" Name="顧客見積もり" NickName="こきゃくみつもり" /&amp;gt;&lt;BR&gt;&amp;nbsp; &amp;lt;/DocumentType&amp;gt;&lt;BR&gt;&amp;lt;/root&amp;gt;&lt;/P&gt;
&lt;P&gt;今度は、root要素も指定できるし、要素と属性を混在させたりできます。&lt;/P&gt;
&lt;P&gt;※ Namespace付きにする場合は、こんな感じで指定できました。&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#a52a2a&gt;WITH XMLNAMESPACES&lt;/FONT&gt; (&lt;BR&gt;&amp;nbsp;&amp;nbsp; 'http://blogs.passj.org/akiko' as Akiko)&lt;BR&gt;　SELECT (SELECT [Id] AS "@Id"&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ,[Name] AS "@Name"&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ,ISNULL([NickName], [Name]) AS "@NickName"&lt;BR&gt;&amp;nbsp; FROM [Test].[DocumentType] &lt;BR&gt;&amp;nbsp;WHERE IsEnabled = 1&lt;BR&gt;&amp;nbsp;FOR XML PATH('Akiko:Item'), TYPE) AS "Akiko:DocumentType"&lt;BR&gt;FOR XML PATH(''), ROOT('Akiko:root')&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#a52a2a&gt;※WITH XMLNAMESPACES (....)&lt;/FONT&gt;がポイント。&lt;/P&gt;
&lt;P&gt;結果はこんな感じになります。&lt;/P&gt;
&lt;P&gt;&amp;lt;Akiko:root xmlns:Charon="http://blogs.passj.org/akiko"&amp;gt;&lt;BR&gt;&amp;nbsp; &amp;lt;Akiko:DocumentType&amp;gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;Akiko:Item xmlns:Akiko="http://blogs.passj.org/akiko" Id="1" Name="見積り" NickName="みつもり" /&amp;gt;&lt;BR&gt;　　　　　:&lt;/P&gt;
&lt;P&gt;&amp;nbsp; &amp;lt;/Akiko:DocumentType&amp;gt;&lt;BR&gt;&amp;lt;/Akiko:root&amp;gt;&lt;/P&gt;&lt;A name=more&gt;&lt;/A&gt;&lt;/DIV&gt;
&lt;DIV class=visualClear&gt;&lt;!-- --&gt;&lt;/DIV&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;
&lt;HR id=null&gt;
&lt;/FONT&gt;もしかして、使い方を間違っていたり、まだまだ分っていないことがたくさんありそうですが、私には嬉しい機能でした。&lt;/P&gt;
&lt;P&gt;そんなことを書いているうちに、もう2008....。いったいどうなるのでしょうか、楽しみです。&lt;/P&gt;&lt;img src ="http://blogs.sqlpassj.org/akiko/aggbug/24258.aspx" width = "1" height = "1" /&gt;</content><wfw:comment>http://blogs.sqlpassj.org/akiko/comments/24258.aspx</wfw:comment><slash:comments>1</slash:comments><wfw:commentRss>http://blogs.sqlpassj.org/akiko/comments/commentRss/24258.aspx</wfw:commentRss><trackback:ping>http://blogs.sqlpassj.org/akiko/services/trackbacks/24258.aspx</trackback:ping></entry><entry><title>知らなかった：ストアドプロシージャのネスト。</title><link rel="alternate" type="text/html" href="http://blogs.sqlpassj.org/akiko/archive/2007/10/09/24108.aspx" /><id>http://blogs.sqlpassj.org/akiko/archive/2007/10/09/24108.aspx</id><created>2007-10-09T09:30:00Z</created><issued>2007-10-09T00:30:00+09:00</issued><modified>2007-10-09T11:33:00Z</modified><content type="text/html" mode="escaped">&lt;P&gt;現在作っているシステムでは、ビジネスロジックは、大部分をストアドプロシージャでコーディングしています。&lt;/P&gt;
&lt;P&gt;通常のSQLからの利用や、SSIS経由のジョブからの実行、というだけでなく、SOAP化してSQL Server外からも実行するのが簡単で、再利用しやすいからです。（IISやNative XML Webサービスを使って。）&lt;/P&gt;
&lt;P&gt;さて、そうこう進めているうちに、「1つのストアドの実行後、それだけで終わらず、処理結果を他のシステムと渡さないといけない」といった、状況が増えてきました。ビジネスロジックをアプリケーションサーバで組んでいれば、他システムとの連携はやりやすかったのかもしれませんが、上記の通り実装はストアドが中心。&lt;/P&gt;
&lt;P&gt;処理結果を連携させる必要のある、もう一つのシステムにも、本来はDBの外から連携させた方が良いのですが、能力と手間の問題で、&lt;STRONG&gt;ストアドからストアドの呼び出し&lt;/STRONG&gt;、という形で連携させてしまえば良いかな、と安易に考えてしまいました。（もう一つのシステムのデータソースも、同じSQL Serverのインスタンス上にあるので...）&lt;/P&gt;
&lt;P&gt;ところが、これが&lt;STRONG&gt;大きな落とし穴&lt;/STRONG&gt;になってしまいました(T_T)&lt;/P&gt;
&lt;P&gt;「こっちのストアドから、そっちのストアドを呼び出せば良いのよね」と、もう1つのシステムの担当者と軽く話を進めたのですが、表面上は1つづつしかネストしないと思っていたストアド、お互い、既にその自身内に、&lt;STRONG&gt;いろんなストアドや関数をネストしていました&lt;/STRONG&gt;。&lt;/P&gt;
&lt;P&gt;また、ストアドの結果を受けて処理を分岐させるため、&lt;STRONG&gt;INSERT...EXEC&lt;/STRONG&gt;で結果を受け取っていたのですが、自分の担当分では正常に処理が終了するのに、さらに相手に自分の実装したストアドを実行してもらうと、以下のようなエラーが発生してしまい、正常に実行できません!&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;&lt;FONT color=#a52a2a&gt;INSERT-EXEC ステートメント内では ROLLBACK ステートメントを使用できません。&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;また、それぞれのストアドには、Transaction処理（エラーが発生したら、Rollbackする）も設けていたのですが、何度修正しても、以下のようなエラーが発生してしまいました...。&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P&gt;&lt;FONT color=#a52a2a&gt;EXECUTE 後の&lt;/FONT&gt;&lt;A class=keyword href="http://d.hatena.ne.jp/keyword/%a5%c8%a5%e9%a5%f3%a5%b6%a5%af%a5%b7%a5%e7%a5%f3"&gt;&lt;FONT color=#a52a2a&gt;トランザクション&lt;/FONT&gt;&lt;/A&gt;&lt;FONT color=#a52a2a&gt;数は、 COMMIT TRAN または ROLLBACK TRAN ステートメントに間違いがあることを示しています。以前の数 = 1、現在の数 = 0 です。&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P dir=ltr&gt;
&lt;HR id=null&gt;

&lt;P&gt;&lt;/P&gt;
&lt;P dir=ltr&gt;&lt;FONT color=#000000&gt;せっかく再利用できると思ってストアドを多用したのに、ほとんど同じコードを組み込み直さないといけないのかしら...と、だいぶ辟易していたころに、こんなサイトを見つけました。&lt;/FONT&gt;&lt;/P&gt;
&lt;P dir=ltr&gt;&lt;STRONG&gt;[ &lt;A href="http://www.sommarskog.se/share_data.html#INSERTEXEC"&gt;How to Share Data Between Stored Procedures&lt;/A&gt; ]&lt;/STRONG&gt; &lt;SPAN class=link-external&gt;&lt;A title=external-link href="http://www.sommarskog.se/share_data.html#INSERTEXEC"&gt;&lt;FONT color=#800080&gt;http://www.sommarskog.se/share_data.html#INSERTEXEC&lt;/FONT&gt;&lt;/A&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P dir=ltr&gt;&lt;SPAN class=link-external&gt;ここに、以下のような一文が。&lt;/SPAN&gt;&lt;/P&gt;
&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;
&lt;P dir=ltr&gt;&lt;SPAN class=link-external&gt;&lt;FONT color=#000080&gt;&lt;STRONG&gt;&lt;EM&gt;It can't nest&lt;/EM&gt;&lt;/STRONG&gt;. If &lt;B&gt;some_sp&lt;/B&gt; tries to call&lt;B&gt; some_other_sp&lt;/B&gt; with &lt;/FONT&gt;&lt;FONT size=3&gt;&lt;FONT color=#000080&gt;&lt;SMALL class=allcaps&gt;INSERT-EXEC&lt;/SMALL&gt;, you will get an error message. Thus, &lt;U&gt;you can only have one &lt;SMALL class=allcaps&gt;INSERT-EXEC&lt;/SMALL&gt; active at a time&lt;/U&gt;. This is a restriction in &lt;SMALL class=allcaps&gt;SQL&lt;/SMALL&gt; Server.&lt;/FONT&gt; &lt;/FONT&gt;&lt;/SPAN&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P dir=ltr align=left&gt;&lt;SPAN class=link-external&gt;いつも参考にしていた本には、ストアドのネストの場合は、INSERT-EXECで結果を受け取れば良いという旨しか書かれていなかったので、こういう制限があるとは、分りませんでした....。（実際に、これって本当なんでしょうか？？）&lt;/SPAN&gt;&lt;/P&gt;
&lt;P dir=ltr align=left&gt;&lt;SPAN class=link-external&gt;また、ロールバックのエラーについては、こちらを呼んで、なんとか納得いたしました...。&lt;/SPAN&gt;&lt;/P&gt;
&lt;P dir=ltr align=left&gt;&lt;SPAN class=link-external&gt;[ &lt;A href="http://www.vfpconversion.com/Article.aspx?quickid=0305111"&gt;&lt;STRONG&gt;Handling SQL Server Errors in Nested Procedures&lt;/STRONG&gt; &lt;/A&gt;] &lt;A href="http://www.vfpconversion.com/Article.aspx?quickid=0305111"&gt;http://www.vfpconversion.com/Article.aspx?quickid=0305111&lt;/A&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;以前、アプリケーションサーバ上（J2EE/EJB)で、ビジネスロジックを組んだことがあるのですが、その時は、Commin/Rollback処理を含んだ1つのビジネスロジックを、さらに別のCommin/Rollback処理を含むビジネスロジックでラップした場合、トランザクションマネージャがうまく処理をしてくれていました。（一番上のビジネスロジックのトランザクションに合わせる）&lt;/P&gt;
&lt;P&gt;そこでの理解が足りなかったのかもしれませんが、ストアドプロシージャもそういうことが可能と思って、安易にネストさせてしまっていました。これがいけないんでしょうね...。&lt;/P&gt;
&lt;P&gt;また、本当は、他システムとの連携は、BASやらService Brokerを使ったりするほうが望ましいのですよね...。&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;img src ="http://blogs.sqlpassj.org/akiko/aggbug/24108.aspx" width = "1" height = "1" /&gt;</content><wfw:comment>http://blogs.sqlpassj.org/akiko/comments/24108.aspx</wfw:comment><slash:comments>3</slash:comments><wfw:commentRss>http://blogs.sqlpassj.org/akiko/comments/commentRss/24108.aspx</wfw:commentRss><trackback:ping>http://blogs.sqlpassj.org/akiko/services/trackbacks/24108.aspx</trackback:ping></entry><entry><title>いまごろですが、CTE。</title><link rel="alternate" type="text/html" href="http://blogs.sqlpassj.org/akiko/archive/2007/08/24/23943.aspx" /><id>http://blogs.sqlpassj.org/akiko/archive/2007/08/24/23943.aspx</id><created>2007-08-24T16:51:00Z</created><issued>2007-08-24T07:51:00+09:00</issued><modified>2007-08-24T16:54:00Z</modified><content type="text/html" mode="escaped">&lt;P&gt;部署の情報を格納したテーブルを作っています。&lt;/P&gt;
&lt;P&gt;ここには、ParentIdという列に、1つ上の親の部署Idを格納しています。ここから、上下の関係を導出する...という具合に考えているのですが、この方法だと、どうしても再帰クエリになってしまいます。&lt;/P&gt;
&lt;P&gt;Oracleでは、CONNECTというのを使うとうまくできそうなんですが、SQL Serverだとどうしていいのか分かりません...。&lt;/P&gt;
&lt;P&gt;（階層は深くても4階層くらいまでなので、固定のSQLでも頑張ればいいのですが）&lt;/P&gt;
&lt;P&gt;また、データはDBはRDBにフラットに定義しておいて、実際にアプリケーションに渡す場合は、XMLに加工して使おうと思っています。&lt;/P&gt;
&lt;P&gt;色々探していたら、CTEというのが使えるんですね。&lt;/P&gt;
&lt;P&gt;正しい方法じゃないかもしれませんが、とりあえず、やってみると....。&lt;/P&gt;
&lt;P&gt;
&lt;HR id=null&gt;

&lt;P&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#0000ff&gt;&lt;PRE&gt;USE Common&lt;/PRE&gt;&lt;PRE&gt;GO
WITH Recursive (ParentId, Id, Code, Name, Level)
AS
(
-- Divisionの定義
    SELECT D.ParentId, D.Id, D.Code, D.Name, 
        0 AS Level
    FROM Division AS D
    WHERE ParentId IS NULL
	AND IsEnabled = 1
    UNION ALL
-- 再帰の定義
    SELECT D.ParentId, D.Id, D.Code, D.Name, 
        Level + 1
    FROM Division AS D
    INNER JOIN Recursive AS R
        ON D.ParentId = R.Id
	AND IsEnabled = 1
)
-- 再帰テーブルから取り出し
SELECT ParentId, Id, Code, Name, Level, replicate('-', (Level)* 10) + Code 
FROM Recursive&lt;/PRE&gt;&lt;/FONT&gt;
&lt;P&gt;&lt;/P&gt;&lt;FONT face="Courier New" size=2&gt;
&lt;P&gt;
&lt;HR id=null&gt;

&lt;P&gt;&lt;/P&gt;
&lt;P&gt;結果。個人的に、かなり感動しました(^^;&lt;/P&gt;
&lt;P&gt;FOR XML, PATHモードを使えば、そこそこ希望しているものが作れるかもしれません...。&lt;/P&gt;&lt;/FONT&gt;&lt;img src ="http://blogs.sqlpassj.org/akiko/aggbug/23943.aspx" width = "1" height = "1" /&gt;</content><wfw:comment>http://blogs.sqlpassj.org/akiko/comments/23943.aspx</wfw:comment><slash:comments>0</slash:comments><wfw:commentRss>http://blogs.sqlpassj.org/akiko/comments/commentRss/23943.aspx</wfw:commentRss><trackback:ping>http://blogs.sqlpassj.org/akiko/services/trackbacks/23943.aspx</trackback:ping></entry></feed>