リモートの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インポートおよびエクスポートウィザード)
回答
情報問題のあるテーブル列(完全修飾名)と問題のある値(120文字で切り捨て)の両方が含まれるようになりました:
メッセージ2628、レベル16、状態1行x文字列またはバイナリデータは、テーブル「TheDb.TheSchema」で切り捨てられます。TheTable “、列” TheColumn “。切り捨てられた値:” … “。ステートメントは終了しました。
回答
最終的に、自分で列情報を記述せずに列情報を取得する方法を見つけることができませんでした。
このエラーメッセージは DBD::ODBC
ですが、sys.columns (max_length)
を使用することもできます(方法がわかりません)。
列リストでこのようなコードを使用して、COLUMN_NAME
とMAX_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
で例外をキャッチし、有用なものを出力しました。この例では、@$row
はsth->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; }
sys.columns
を参照するコードを配置しませんでした。これは、現在自動的に"クエリを生成します。 'SELECT name, object_id, max_length FROM sys.columns;
よりも、コードに組み込むことについて推測できるほど複雑なものは実際にはありません。これを実行する必要のあるautomagicコード(またはそれに非常によく似たもの)がすでにあるので、'例が必要だとは思いませんでした。sys.columns
が同じname
を持つ2つの列でどのように機能するかわかりません。また、sys
ではなくライブラリを使用して動作するようになりましたが、なぜそれを選択した回答にするのでしょうか。Microsoft SQL doesn't have x, do y instead
は有効な投稿ですが、y
が私のy
より劣っている場合は、 '何か別のことをして、それを選択済みとしてマークします。