SQL Server Manager で表示すると、一部の列に が含まれる SQL テーブルがあります<Unable to read data>
。を照会する方法を知っている人はいます<Unable to read data>
か? を使用してこの列のデータを個別に変更できupdate table set column = NULL where key = 'value'
ますが、この不正なデータを含む追加の行が存在するかどうかを確認するにはどうすればよいですか?
4 に答える
データの置き換えはお勧めしません。何も問題はありません。SSM が編集パネルで正しく表示できないだけです。あなたの説明から、データベース自体のデータは完全に問題ありません。
このスクリプトは問題を示しています。
create table test (id int not null identity(1,1) primary key,
large_value numeric(38,0));
go
insert into test (large_value) values (1);
insert into test (large_value) values (12345678901234567890123456789012345678);
insert into test (large_value) values (1234567890123456789012345678901234567);
insert into test (large_value) values (123456789012345678901234567890123456);
insert into test (large_value) values (12345678901234567890123456789012345);
insert into test (large_value) values (1234567890123456789012345678901234);
insert into test (large_value) values (123456789012345678901234567890123);
insert into test (large_value) values (12345678901234567890123456789012);
insert into test (large_value) values (1234567890123456789012345678901);
insert into test (large_value) values (123456789012345678901234567890);
insert into test (large_value) values (12345678901234567890123456789);
insert into test (large_value) values (NULL);
go
select * from test;
go
SELECT は正常に機能しますが、オブジェクト エクスプローラーで [上位 200 行の編集] を表示すると、次のようにはなりません。
この号にはConnect アイテムがあります。SSMS 2012 でも同じ問題が発生します。
Numeric と Decimalの詳細を見ると、実際には SQL Server の境界ではない精度 29 の奇妙な境界で問題が発生していることがわかります(精度は 28 です)。
Precision Storage bytes
1 - 9 5
10-19 9
20-28 13
29-38 17
.Net (SSMS はマネージ アプリケーションです) の10 進精度テーブルを確認すると、問題の核心がどこにあるかがすぐにわかります。そのため、.Netdecimal
型は高精度 (>29) SQL Server numeric
/decimal
型をマップできません。
これは、SSMS の表示だけでなく、アプリケーションにも影響します。SSIS のような特殊なアプリケーションは、次のような高精度表現を使用しますDT_NUMERIC
。
DT_NUMERIC
精度と位取りが固定された正確な数値。このデータ型は、符号が別の16 バイトの符号なし整数で、位取りは 0 から 38、最大精度は 38 です。
問題に戻りましょう。値を見るだけで、無効なエントリを発見できます。C# の表現範囲は、おおよそ (-7.9 x 10 28から 7.9 x 10 28 ) / (10 0 から 28 )` (範囲はスケールによって異なります) の間の値に対応できることを知っていれば、各列の範囲外の値を検索できます。 (検索する実際の値は、列のスケールによって異なります)。しかし、それでは「データを何に置き換えるか?」という疑問が生じます。
代わりに、高精度の数値を処理できるツールであるインポート エクスポート専用のツールを使用することをお勧めします。SSIS は明らかな候補です。しかし、控えめなbcp.exeでさえ、法案に適合します。
ところで、値が実際に正しくない場合 (つまり、真の破損)、実行することをお勧めしますDBCC CHECKTABLE (...) WITH DATA_PURITY
:
DATA_PURITY
DBCC CHECKDB は、無効または範囲外の列値についてデータベースをチェックします。たとえば、DBCC CHECKDB は、datetime データ型の許容範囲よりも大きいまたは小さい日付と時刻の値を持つ列を検出します。または、位取りまたは精度の値が無効な 10 進数または近似数値データ型の列。
SQL Server 2005 以降で作成されたデータベースの場合、列値の整合性チェックは既定で有効になっており、DATA_PURITY オプションは必要ありません。以前のバージョンの SQL Server からアップグレードされたデータベースの場合、DBCC CHECKDB WITH DATA_PURITY がデータベースでエラーなしで実行されるまで、既定では列値のチェックは有効になりません。この後、DBCC CHECKDB は既定で列値の整合性をチェックします。
Q:この問題はどのようにしてdatetime
カラムで発生するのですか?
use tempdb;
go
create table test(d datetime)
insert into test (d) values (getdate())
select %%physloc%%, * from test;
-- Row is on page 0x9100000001000000
dbcc traceon(3604,-1);
dbcc page(2,1,145,3);
Memory Dump @0x000000003FA1A060
0000000000000000: 10000c00 75f9ff00 6aa00000 010000 ....uùÿ.j .....
Slot 0 Column 1 Offset 0x4 Length 8 Length (physical) 8
dbcc writepage(2,1,145, 100, 8, 0xFFFFFFFFFFFFFFFF)
dbcc checktable('test') with data_purity;
メッセージ 2570、レベル 16、状態 3、行 2 ページ (1:145)、オブジェクト ID 837578022 のスロット 0、インデックス ID 0、パーティション ID 2882303763115671552、割り当てユニット ID 2882303763120062464 (タイプ「行内データ」)。列 "d" の値がデータ型 "datetime" の範囲外です。列を有効な値に更新します。
上記のように、これらのエラーは通常、Precision と Scale が保持されていない場合に発生します。SSIS に慣れている場合は、破損している行を取得できます。Martin Smith が作成した値を取得する
CREATE TABLE T(ID int ,C DECIMAL(38,0));
INSERT INTO T VALUES(1,9999999999999999999999999999999999999)
上記の表はエラーを再現しています。ここで、最初の列は主キーを表します。約 1000 行を挿入しましたが、そのうちのいくつかは破損した値でした。以下はSSISパッケージのデザインです
データ変換では、エラーのある列 C を取得し、それを Decimal(38,0) にキャストしようとしました。変換または切り捨てエラーが発生するため、基本的にテーブルを更新する OLEDB コマンドにエラー行をリダイレクトしました列をNULLに設定します
Update T
Set C=NULL
where ID=?
C と ID の値は oledb コマンドに送信されます。エラーがない場合は、テーブルに挿入するだけです (実際にはこれを行う必要はありません)。これは、主キー列がある場合に機能します。テーブル 。
日時列にエラーがある場合は、sql クエリを記述して日時値の形式を確認できます。有効な日時値については、 MSDN リンクを参照してください。
Select * from YourTable where ISDATE(Col)!=1
カーソルでデータを取得できると思います。以下のクエリのようなカーソルクエリで再試行してください:
DECLARE VerifyCursor CURSOR FOR
SELECT *
FROM MyTable
WHILE 1=1 BEGIN
BEGIN Try
FETCH FIRST FROM VerifyCursor INTO @Column1, @Column2, ...
INSERT INTO @MyTable2(Column1, Column2,...)
VALUES (@Column1, @Column2, ...)
END TRY
BEGIN CATCH
END CATCH
IF (@@FETCH_STATUS<>0) BREAK
End
OPEN VerifyCursor
CLOSE VerifyCursor
DEALLOCATE VerifyCursor
悪いデータを置き換えるのは、更新で簡単です。
UPDATE table SET column = NULL WHERE key_column = 'Some value'