SQLServer : XMLの値と属性を「replace value of」で改変する
いままでSQLServer の XML操作については、SELECT + FOR XML PATHでXMLを作成したり、OPENXMLでSELECTしたりしかしてこなかった僕です。
まぁ必ずではなかったのですが、ストアド上でXMLの値とか属性とかを個別に操作したいという案件が発生。「SQLServer XML 操作」とか調べてみると、上述している案件ばかりでてくるので、DOM操作でやろうかなとあきらめてたところ、それっぽいドキュメントを発見。
何はともあれ、Management Studioで以下のSQLを試してみた。
XML型の@xmlを宣言して、2番目の<TEST>タグの値と属性を5に変更しました。
DECLARE @xml XML = '<ROOT><TEST attr="10">1</TEST><TEST attr="20">2</TEST></ROOT>'
SELECT @xml
SET @xml.modify('replace value of (/ROOT/TEST[2]/text())[1] with "5"')
SELECT @xml
SET @xml.modify('replace value of (/ROOT/TEST[2]/@attr)[1] with "5"')
SELECT @xml
結果が下図。値も属性も改変できることを確認できた。めでたしめでたし。
SQLServer : FOR XML PATHについてあまり考えてこなかったかも
いままであまり深く考えていなかったけれども、SQLServerのFOR XML PATH句について、「タグは存在するけど、数値(文字列)がない」もしくは「タグ自体が存在しない」の2パターンについて考えてみた。
正直、いままでこれらの違いについて考えてたことなかった。しかしある時、いつも使用していたNULL判定について、挙動がおかしいことに気づいた。なので、それぞれについて以下のクエリで試してみた。
-- テスト用XMLを定義。ARG1, ARG2タグには値を挿入し、ARG3は値無し、ARG4はタグ自体無しとした。
'<ROOT>
<ARG1>1</ARG1>
<ARG2>2</ARG2>
<ARG3></ARG3>
</ROOT>'
DECLARE @xml_predoc INT
EXEC sp_xml_preparedocument @xml_predoc OUTPUT, @xml
-- ARG1, 2, 3, 4について同条件でSELECTする。
SELECT
ARG1 ,ARG2 ,ARG3, ARG4
FROM OPENXML(@xml_predoc, '/ROOT', 2)
WITH( ARG1 INT, ARG2 INT, ARG3 INT, ARG4 INT)
FOR XML PATH('ROOT')
このクエリを実行すると、結果は以下となる。
<ROOT>
<ARG1>1</ARG1>
<ARG2>2</ARG2>
<ARG3>0</ARG3>
</ROOT>
つまり、
1, タグはあるけど値を記載していない = 整数型なら0 。文字列型なら空文字。
2, タグ自体ないものに対してSELECTする = NULL
本当にあまり考えてこなかったけれども、パターン1については0になると考えると、条件文など適当に書くとエラーが出そう。
もしかしたら基礎なのかもしれないけれども、備忘録として。
SQLServer : エラーが出ていないのにストアドプロシージャの処理が止まっている?
スレッド内でSQLServerのストアドプロシージャを SQLExecDirect / SQLExecute で実行するサービスプログラムを作成した。だがしかし、なぜかストアドプロシージャの実行がうまくいっていないようであった。
ストアドプロシージャはデータの集計 + INSERTしか行っておらず、SQLServer Management Studio上で当該のストアドプロシージャを実行しても、エラーが一切確認できなかった。
ログやイベントビューアーなどから始まり、怪しい行を消したりCURSORをいじったり、SQLSetStmtAttrをいじったり、早3時間・・・。いろいろ行って分かったのは、「CURSORループ内でINSERTを使用すると止まる」ということであった。
INSERT特有といえば、Management Studio上でINSERT構文を実行すると以下のメッセージが現れることくらいである。
これやろ!!!!!なんとなくやけどこの(1行処理されました)という処理行数メッセージ!!!Management Studio上では自然におるけど、絶対に悪い奴やろ!!!とりあえず、ストアドプロシージャ内に「SET NO COUNT ON」を記述すれば消えます。この1行を追加するだけで、(1行処理されました)と出力されていた状態から、以下のように「コマンドは正常に完了しました。」という文字列に変わりました。
まじで、これだけで、正常にサービスからストアドプロシージャが実行されるようになりました。めでたしめでたし。
その後、突然のデジャブから、一年前に作成した同様の処理を行うストアドプロシージャを確認すると、SET NO COUNT ONが記述されていた。つまり、私は当該問題に一度ぶちあたり、解決していたのにもかかわらず、忘れていたのである。
なので、備忘録としてここに記す。
VBScript : Response.Formで受け取ると、すでにURLデコードされている?
一般的なのかわからないのですが、URLエンコードされた文字列をVBScript の Response.Formで 受け取ったら、受け取った段階でURLデコードされているという話。
類まれなる例なのかもしれませんが、こういった場合がありました。
クライアント側からURLエンコードしたデータをPOSTで送るから、VBScriptで受けてという話です。
で、私はサーバー側担当なので、「あ、URLデコード書かないといけないんだな」と思ったのですが、いざ取得データを確認してみるとすでにURLデコードされている状態でした。
ざっくり検索してもわからなかったし、これ以上踏み込む気もなかったので、とりあえず実証して終わりました。(クソプログラマー筆頭)
まず、VBScriptで以下のようなPOSTを受け取りResponseするだけの簡易的なプログラムを書きます。
次に、以下のような2つの文章を用意します。
その後、NKFで上記文章をURLエンコードし、POST準備したものが以下のようなものです。
これをVBScriptにPOSTし、Responseを確認すると、以下のようになっています。
以上からわかることは、VBScriptってすげぇな。
SQLServer : INSERT について、 SELECT UNION ALL と ( ), ( ),
先日、 INSERT ( ), ( ), ( ) がどうこうとか書いてるんですよね
で、INSERT SELECT UNION ALL という書き方もあるんですよね。
例えば、以下のような感じ。
*********************************************************************************
INSERT INTO TESTDB
SELECT 1, 1, 1, 1, 1
UNION ALL
SELECT 2, 1, 1, 1, 1
UNION ALL
SELECT 3, 1, 1, 1, 1
*********************************************************************************
INSERT ( ), ( ), ( ) とプランを比較しました。
同じですよね~ですよね~