SQL Server がストアドプロシージャ内の varchar を無意識に切り捨ててしまう
質問
によると
このフォーラムの議論
によると、SQL Server (私は 2005 を使用していますが、これは 2000 や 2008 にも適用されると思います) は、すべての
varchar
を使用して直接文字列を挿入しても、ストアドプロシージャのパラメータとして指定した
INSERT
を使って直接挿入すると、実際にはエラーが発生します。
CREATE TABLE testTable(
[testStringField] [nvarchar](5) NOT NULL
)
を実行すると、以下のようになります。
INSERT INTO testTable(testStringField) VALUES(N'string which is too long')
エラーが出ます。
String or binary data would be truncated.
The statement has been terminated.
素晴らしい。 データの整合性が保たれ、呼び出し元もそれを知っています。 では、それを挿入するためのストアドプロシージャを定義してみましょう。
CREATE PROCEDURE spTestTableInsert
@testStringField [nvarchar](5)
AS
INSERT INTO testTable(testStringField) VALUES(@testStringField)
GO
と入力し、実行します。
EXEC spTestTableInsert @testStringField = N'string which is too long'
エラーなし、1行に影響あり。 行がテーブルに挿入され
testStringField
を 'strin' としてテーブルに挿入されました。 SQL Server はストアド プロシージャの
varchar
パラメータが切り捨てられました。
さて、この動作は時に便利かもしれませんが、これをオフにする方法はないようです。 これは非常に迷惑なことで、私は 欲しい ストアドプロシージャに長すぎる文字列を渡すとエラーになるようにしたいからです。 これに対処する方法は2つあるようです。
まず、ストアドプロシージャの
@testStringField
パラメータをサイズ6と宣言し、その長さが5以上であるかどうかをチェックします。 これは少しハックしているようで、苛立たしい量の定型的なコードを含んでいます。
第二に、ストアドプロシージャのすべてのvarcharパラメータを、以下のように宣言します。
varchar(max)
と宣言し、その上で
INSERT
ステートメントをストアドプロシージャ内で失敗させます。
後者は問題なく動作しているようです。そこで質問ですが、ストアドプロシージャ内で
varchar(max)
もし、長すぎる文字列が渡されたときにストアド プロシージャを失敗させたい場合、SQL Server ストアド プロシージャで文字列に ALWAYS を使用するのはよい考えでしょうか。 ベストプラクティスと言えるのでしょうか? 無効化できない無言の切り捨ては、私には愚かなことのように思えます。
どのように解決するのですか?
それはただ です。 .
私のチェックの1つは、パラメータがテーブルのカラムの長さと一致していることを確認することなので、私は問題に気づいたことはありません。クライアント コードでも同様です。個人的には、SQL が長すぎるデータを見ることはないと思っています。もし、切り捨てられたデータを見たとしても、その原因は一目瞭然でしょう。
varchar(max) の必要性を感じるのであれば、以下の理由により、大規模なパフォーマンスの問題に注意してください。 データ型の優先順位 varchar(max) は varchar(n) よりも優先順位が高いです(一番長いものが一番高い)。したがって、このタイプのクエリでは、シークではなくスキャンが行われ、すべてのvarchar(100)の値はvarchar(max)にCASTされることになります。
UPDATE ...WHERE varchar100column = @varcharmaxvalue
編集する
には Microsoft Connectの項目を開く があります。
に含める価値があるでしょう。 Erland Sommarkog の厳格な設定 (そして に一致するコネクト項目 ).
Martinsのコメントを受けて、2回目の編集を行いました。
DECLARE @sql VARCHAR(MAX), @nsql nVARCHAR(MAX);
SELECT @sql = 'B', @nsql = 'B';
SELECT
LEN(@sql),
LEN(@nsql),
DATALENGTH(@sql),
DATALENGTH(@nsql)
;
DECLARE @t table(c varchar(8000));
INSERT INTO @t values (replicate('A', 7500));
SELECT LEN(c) from @t;
SELECT
LEN(@sql + c),
LEN(@nsql + c),
DATALENGTH(@sql + c),
DATALENGTH(@nsql + c)
FROM @t;
関連
-
executeQuery()ソリューションでデータ操作文を発行できない。
-
[解決済み] SQL ServerでSELECTからUPDATEする方法とは?
-
[解決済み] SQL Server で複数行のテキストを 1 つのテキスト文字列に連結する方法
-
[解決済み] SQL Server テーブルにカラムが存在するかどうかを確認する方法は?
-
[解決済み] SQL Server の DateTime データ型から日付だけを返す方法
-
[解決済み] SQL ServerにおけるLEFT JOINとLEFT OUTER JOINの比較
-
[解決済み] SQL Serverでストアドプロシージャ内のテキストを検索する
-
[解決済み] SQL Serverにおける関数とストアドプロシージャの比較
-
[解決済み】SQL Serverで既存のテーブルにデフォルト値を持つカラムを追加する
-
[解決済み] SQL ServerでINNER JOINを使用して削除するにはどうすればよいですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
MySQL】1136 - 列数が1行目の値数と一致しない問題を解決
-
[解決済み] ストアドプロシージャ 'dbo.aspnet_CheckSchemaVersion' が見つかりませんでした。
-
[解決済み] SQL Server FOR EACH ループ
-
[解決済み] SQLの結合形式 - 入れ子になった内側join
-
[解決済み] MySQLの「スキーマの作成」と「データベースの作成」 - 違いはあるのか?
-
[解決済み] SQLサーバーでNULL = NULLがfalseに評価される理由
-
[解決済み] ...値に挿入する ( SELECT ... FROM ... )
-
[解決済み] SQL Server における DateTime2 と DateTime の比較
-
[解決済み] SQLサーバーで行を列に効率的に変換する
-
[解決済み] Selectステートメントで特定のフィールドの重複を検索する