“文字列またはバイナリデータの原因となる列を特定するにはどうすればよいですか。”

リモートのPgデータベースからSELECTに書き込んだコードを使用して、いくつかのクエリを自動的に生成し、ローカルのSQLServerデータベースに挿入しています。ただし、そのうちの1つが次のエラーを生成しています。

[Microsoft] [ODBC SQLServerドライバー] [SQLServer]文字列またはバイナリデータは切り捨てられます。 (SQL-22001)[状態は22001でしたが01000になりました]

[Microsoft] [ODBC SQLServerドライバー] [SQLServer]ステートメントは終了しました。 (SQL-01000)。\ insert.pl行106。

どの列がそのエラーを生成していて、の長さが不足しているのかを確認するにはどうすればよいですか。入力?すべてのvarcharを総当たり攻撃せずにこれを行う方法はありますか?

回答

いいえ、どこにも記録されていません。投票してビジネスケースを述べてください。これは、SQLServerで修正する必要があるものの長いリストの1つです。

これは、Connectで数年前に要求されました(おそらく最初にSQL Server 2000または2005の時間枠で)、次に再び新しいフィードバックシステムの場合:

現在、次のバージョンで提供されています:

SQL Server 2019の最初のパブリックCTPでは、トレースフラグ460でのみ表示されます。これは一種の秘密に聞こえますが、このMicrosoftホワイトペーパー。これは今後のデフォルトの動作(トレースフラグは不要)になりますが、新しいデータベーススコープの構成VERBOSE_TRUNCATION_WARNINGSを介してこれを制御できます。

ここに例:

USE tempdb; GO CREATE TABLE dbo.x(a char(1)); INSERT dbo.x(a) VALUES("foo"); GO 

SQL Server 2019より前のサポートされているすべてのバージョンの結果:

メッセージ8152、レベル16、状態30、5行目
文字列またはバイナリデータは切り捨てられます。
ステートメントは終了しました。

SQL Server 2019 CTPで、トレースフラグが有効になっています:

DBCC TRACEON(460); GO INSERT dbo.x(a) VALUES("foo"); GO DROP TABLE dbo.x; DBCC TRACEOFF(460); 

結果には、テーブル、列、および(切り捨てられたが表示され、<ではありませんdiv id = "7f7ee51e4b">

full )値:

メッセージ2628、レベル16、状態1、11行目
文字列またはバイナリデータは、テーブル「tempdb.dbo.x」、列「a」で切り捨てられます。切り捨てられた値:「f」。
ステートメントは終了しました。

サポートされているバージョン/ CUに移動するか、Azure SQLデータベースに移動できるようになるまで、 sys.columnsからmax_lengthを実際にプルする「automagic」コードと、とにかくそこに到達する必要のある名前を入力して、LEFT(column, max_length)を適用します。または、PGに相当するものは何でも。または、それは単にデータを黙って失うことを意味するので、どの列が不一致であるかを調べ、ソースからのすべてのデータに合うように宛先列を修正します。両方のシステムへのメタデータアクセスと、「ソース->宛先列に自動的に一致する必要があるクエリをすでに作成している(そうでない場合、このエラーが最大の問題になることはほとんどない)」という事実を考えると、ブルートフォースを実行する必要はありません。推測します。

回答

SQLServerインポートおよびエクスポートウィザードを実行するためのアクセス権がある場合 SQL Server Management Studio([データベース]を右クリック> [タスク]> [データのインポート…])から、クエリをデータソースとして使用して宛先テーブルにSQLクライアントからインポートするタスクを作成します。

インポートを実行する前に、データマッピングを確認すると、フィールドタイプに一貫性がない列がわかります。また、インポートタスクを実行すると、インポートに失敗した列が表示されます。

検証警告の例:

警告0x802092a7:データフロータスク1:長さが316のデータフロー列「NARRATIVE」から長さ60のデータベース列「NARRATIVE」にデータを挿入するために切り捨てが発生する可能性があります。(SQLServerインポートおよびエクスポートウィザード)

回答

回答

最終的に、自分で列情報を記述せずに列情報を取得する方法を見つけることができませんでした。

このエラーメッセージは DBD::ODBC ですが、sys.columns (max_length)を使用することもできます(方法がわかりません)。

列リストでこのようなコードを使用して、COLUMN_NAMEMAX_LENGTH DBI column_info() に記載されています。

my @max_lengths = map [ @{$_->fetchall_arrayref->[0]}[3,6] ] , map $dbh_mssql->column_info("database", "dbo", $dest_table, $_) , @col_mssql ; 

次に、INSERTで例外をキャッチし、有用なものを出力しました。この例では、@$rowsth->execute()

if ($@) { warn "$@\n"; for ( my $idx=0; $idx <= $#{ $row }; $idx++ ) { Dumper { maxlength => $max_lengths[$idx]->[1] , name => $max_lengths[$idx]->[0] , length => length( $row->[$idx] ) , content => $row->[$idx] }; } die; } 
また、他の回答に投票して賛成してください

コメント

  • I ' sys.columnsを参照するコードを配置しませんでした。これは、現在自動的に"クエリを生成します。 ' SELECT name, object_id, max_length FROM sys.columns;よりも、コードに組み込むことについて推測できるほど複雑なものは実際にはありません。これを実行する必要のあるautomagicコード(またはそれに非常によく似たもの)がすでにあるので、'例が必要だとは思いませんでした。
  • I ' sys.columnsが同じnameを持つ2つの列でどのように機能するかわかりません。また、sysではなくライブラリを使用して動作するようになりましたが、なぜそれを選択した回答にするのでしょうか。 Microsoft SQL doesn't have x, do y insteadは有効な投稿ですが、yが私のyより劣っている場合は、 '何か別のことをして、それを選択済みとしてマークします。
  • あなたの質問は、基本的に、どの列がエラーを生成していたかをどのように見つけるかでした(おそらく、ソリューションをリエンジニアリングする代わりに、その1つのスポットを修正できます)。どこを見ればよいか教えてくれました:sys.columns。これは、ソース列の長さと宛先列の長さを比較するために確認する必要がある場所です。それをどのように行うかはあなた次第です。 'コードを修正する方法を教えてくれませんでした。そもそも、automagicクエリがどのように生成されているのかまったくわからないため、前述のように、どのように修正するのかわかりませんでした。すでに持っているクエリに長さの決定を追加します。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です