ฉันจะระบุคอลัมน์ที่รับผิดชอบ "ข้อมูลสตริงหรือไบนารีจะถูกตัดทอนได้อย่างไร"


31

ฉันกำลังสร้างการสืบค้นบางอย่างโดยอัตโนมัติด้วยรหัสที่ฉันเขียนถึง SELECT จากฐานข้อมูล Pg ระยะไกลและแทรกลงในฐานข้อมูล SQL Server ท้องถิ่น อย่างไรก็ตามหนึ่งในนั้นกำลังสร้างข้อผิดพลาดนี้:

[Microsoft] [โปรแกรมควบคุมเซิร์ฟเวอร์ ODBC SQL] [เซิร์ฟเวอร์ SQL] สตริงหรือข้อมูลไบนารีจะถูกตัดทอน (SQL-22001) [สถานะเป็น 22001 ตอนนี้ 01000]

[Microsoft] [โปรแกรมควบคุมเซิร์ฟเวอร์ ODBC SQL] [เซิร์ฟเวอร์ SQL] คำสั่งถูกยกเลิก (SQL-01000) ที่. \ insert.pl บรรทัด 106

ฉันจะค้นหาคอลัมน์ใดที่ทำให้เกิดข้อผิดพลาดนั้นและไม่มีความยาวสำหรับอินพุตได้อย่างไร มีวิธีการทำเช่นนี้โดยไม่คาดเดาสัตว์เดรัจฉานvarcharหรือไม่?

คำตอบ:


35

ไม่มันไม่ได้ถูกบันทึกไว้ทุกที่ ลงคะแนนและระบุกรณีธุรกิจของคุณ นี่คือหนึ่งในรายการสิ่งต่าง ๆ ที่ควรได้รับการแก้ไขใน SQL Server

สิ่งนี้ได้รับการร้องขอเมื่อหลายปีก่อนในการเชื่อมต่อ (อาจเป็นครั้งแรกในช่วงเวลาของ SQL Server 2000 หรือ 2005) จากนั้นอีกครั้งในระบบผลตอบรับใหม่:

และตอนนี้มันถูกส่งในSQL Server 2019 , SQL Server 2017 CU12 และจะปรากฏใน SQL Server 2016 SP2 CU ในอนาคต

ใน CTP สาธารณะแรกสุดของ SQL Server 2019 จะปรากฏเฉพาะภายใต้ค่าสถานะการสืบค้นกลับ 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 CTPs ด้วยการเปิดใช้งานการตั้งค่าสถานะการสืบค้นกลับ:

DBCC TRACEON(460);
GO

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

ผลลัพธ์แสดงตารางคอลัมน์และค่า ( ตัดทอนไม่เต็ม ):

ข่าวสารเกี่ยวกับ 2628, ระดับ 16, สถานะ 1, บรรทัดที่ 11
สตริงหรือข้อมูลไบนารีจะถูกตัดทอนในตาราง 'tempdb.dbo.x', คอลัมน์ 'a' ค่าที่ตัดปลาย: 'f'
คำสั่งถูกยกเลิก

จนกว่าคุณจะสามารถวางทุกอย่างและอัปเกรดเป็น SQL Server 2019 หรือย้ายไปยังฐานข้อมูล Azure SQL คุณสามารถเปลี่ยนรหัส "automagic" ของคุณเพื่อดึง max_length จากsys.columnsพร้อมกับชื่อที่คุณต้องไปที่นั่นแล้วใช้LEFT(column, max_length)หรือ สิ่งที่เทียบเท่าของ PG คือ หรือเนื่องจากนั่นหมายความว่าคุณจะสูญเสียข้อมูลไปอย่างเงียบ ๆ ลองหาว่าคอลัมน์ใดที่ไม่ตรงกันและแก้ไขคอลัมน์ปลายทางเพื่อให้พอดีกับข้อมูลทั้งหมดจากแหล่งที่มา เมื่อได้รับการเข้าถึงข้อมูลเมตาของทั้งสองระบบและความจริงที่ว่าคุณกำลังเขียนแบบสอบถามที่ต้องจับคู่แหล่งที่มา -> คอลัมน์ปลายทางโดยอัตโนมัติ (มิฉะนั้นข้อผิดพลาดนี้แทบจะเป็นปัญหาที่ใหญ่ที่สุดของคุณ) คุณไม่ควรทำอะไรโหดร้าย คาดเดาทั้งหมด


2

หากคุณสามารถเรียกใช้ตัวช่วยสร้างการนำเข้าและส่งออกของเซิร์ฟเวอร์ SQL จาก SQL Server Management Studio (ฐานข้อมูลคลิกขวา> งาน> นำเข้าข้อมูล ... ) ให้สร้างงานที่นำเข้าจากไคลเอนต์ SQL โดยใช้แบบสอบถามของคุณเป็นแหล่งข้อมูลไปยังปลายทาง ตาราง.

ก่อนที่คุณจะรันการนำเข้าคุณสามารถตรวจสอบการแมปข้อมูลและจะบอกให้คุณทราบว่าคอลัมน์ใดมีประเภทฟิลด์ที่ไม่สอดคล้องกัน และถ้าคุณเรียกใช้งานการนำเข้ามันจะบอกให้คุณทราบว่าคอลัมน์ใดล้มเหลวในการนำเข้า

คำเตือนการตรวจสอบตัวอย่าง:

คำเตือน 0x802092a7: การไหลของข้อมูลงานที่ 1: การตัดอาจเกิดขึ้นเนื่องจากการแทรกข้อมูลจากคอลัมน์การไหลของข้อมูล "NARRATIVE" ที่มีความยาว 316 ถึงคอลัมน์ฐานข้อมูล "NARRATIVE" ที่มีความยาว 60 (ตัวช่วยสร้างการนำเข้าและส่งออกเซิร์ฟเวอร์ SQL)


1

ท้ายที่สุดฉันไม่สามารถหาข้อมูลคอลัมน์ได้โดยไม่ต้องเขียนเอง

ข้อความแสดงข้อผิดพลาดนี้สร้างขึ้นโดยDBD::ODBCคุณสามารถใช้ได้เช่นกันsys.columns (max_length) (ฉันไม่ทราบวิธี)

ฉันใช้รหัสแบบนี้ในรายการคอลัมน์ของฉันเพื่อรับรายการอาร์เรย์ที่มีสององค์ประกอบคือCOLUMN_NAME, และMAX_LENGTH(บันทึกในDBIcolumn_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;
}

นอกจากนี้โปรดโหวตและโหวตขึ้นอีกคำตอบ


2
ฉันไม่ได้ใส่การอ้างอิงรหัสใด ๆsys.columnsเพราะฉันไม่รู้ว่าคุณกำลังใช้รหัสใดในการสร้างข้อความค้นหาของคุณโดยอัตโนมัติ SELECT name, object_id, max_length FROM sys.columns;จริงๆมีไม่มากเกินไปที่ซับซ้อนมากขึ้นฉันสามารถคาดเดาเกี่ยวกับการผสมผสานลงในรหัสของคุณมากกว่า เนื่องจากคุณมีรหัสอัตโนมัติที่ต้องทำเช่นนี้ - หรืออะไรทำนองนั้น - ฉันไม่คิดว่าจำเป็นต้องมีตัวอย่าง
Aaron Bertrand

ฉันไม่แน่ใจว่าsys.columnsทำงานกับสองคอลัมน์ที่เหมือนกันnameได้อย่างไร นอกจากนี้ฉันได้สิ่งที่ทำงานโดยใช้ห้องสมุดมากกว่าsysทำไมฉันจะทำให้มันเป็นคำตอบที่เลือก? Microsoft SQL doesn't have x, do y insteadเป็นการบริจาคที่ถูกต้อง แต่ถ้าคุณyด้อยกว่าของyฉันฉันจะทำสิ่งที่แตกต่างและทำเครื่องหมายตามที่เลือก
Evan Carroll

1
คำถามของคุณคือว่าฉันจะทราบได้อย่างไรว่าคอลัมน์ใดที่ทำให้เกิดข้อผิดพลาด (สมมุติดังนั้นคุณสามารถแก้ไขจุดนั้นได้แทนที่จะแก้ไขวิศวกรรมซ้ำ) ฉันบอกคุณแล้วว่าต้องดูที่ไหน: sys.columns สิ่งใดที่คุณควรดูเพื่อเปรียบเทียบความยาวของคอลัมน์ต้นทางกับความยาวคอลัมน์ปลายทาง คุณทำเช่นนั้นขึ้นอยู่กับคุณ ฉันไม่ได้บอกคุณว่าจะแก้ไขรหัสของคุณอย่างไรเพราะฉันไม่รู้ว่าการสร้าง automagic ของคุณถูกสร้างขึ้นตั้งแต่แรกอย่างไรฉันก็เลยไม่รู้ว่าจะเพิ่มการกำหนดความยาวให้กับการสืบค้นใด ๆ ที่คุณมีอยู่แล้ว .
Aaron Bertrand

1

ในที่สุดMicrosoft ได้ตัดสินใจที่จะให้ข้อมูลที่มีความหมายสำหรับการString or binary would be truncatedเริ่มต้นจาก SQL Server 2016 SP2 CU, SQL Server 2017 CU12 และใน SQL Server 2019

ข้อมูลในขณะนี้มีทั้งคอลัมน์ตารางที่ละเมิด (ชื่อที่ผ่านการรับรองอย่างสมบูรณ์) และค่าที่กระทำผิด (ถูกตัดทอนที่ 120 อักขระ):

ข่าวสารเกี่ยวกับ 2628 ระดับ 16 สถานะ 1 บรรทัด x สตริงหรือข้อมูลไบนารีจะถูกตัดทอนในตาราง 'TheDb.TheSchema.TheTable' คอลัมน์ 'TheColumn' ค่าที่ตัดปลาย: '... ' คำสั่งถูกยกเลิก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.