2

SQL Server Manager で表示すると、一部の列に が含まれる SQL テーブルがあります<Unable to read data>。を照会する方法を知っている人はいます<Unable to read data>か? を使用してこの列のデータを個別に変更できupdate table set column = NULL where key = 'value'ますが、この不正なデータを含む追加の行が存在するかどうかを確認するにはどうすればよいですか?

4

4 に答える 4

9

データの置き換えはお勧めしません。何も問題はありません。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 行の編集] を表示すると、次のようにはなりません。

UnableToEditData

この号には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)

トップ200を編集

dbcc checktable('test') with data_purity;

メッセージ 2570、レベル 16、状態 3、行 2 ページ (1:145)、オブジェクト ID 837578022 のスロット 0、インデックス ID 0、パーティション ID 2882303763115671552、割り当てユニット ID 2882303763120062464 (タイプ「行内データ」)。列 "d" の値がデータ型 "datetime" の範囲外です。列を有効な値に更新します。

于 2012-06-08T08:38:39.217 に答える
1

上記のように、これらのエラーは通常、Precision と Scale が保持されていない場合に発生します。SSIS に慣れている場合は、破損している行を取得できます。Martin Smith が作成した値を取得する

CREATE TABLE T(ID int ,C DECIMAL(38,0));
INSERT INTO T VALUES(1,9999999999999999999999999999999999999) 

上記の表はエラーを再現しています。ここで、最初の列は主キーを表します。約 1000 行を挿入しましたが、そのうちのいくつかは破損した値でした。以下はSSISパッケージのデザインです

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
于 2012-06-07T04:45:07.007 に答える
0

カーソルでデータを取得できると思います。以下のクエリのようなカーソルクエリで再試行してください:

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
于 2012-06-07T15:46:13.563 に答える
0

悪いデータを置き換えるのは、更新で簡単です。

UPDATE table SET column = NULL WHERE key_column = 'Some value'
于 2012-06-07T19:09:15.513 に答える