想象一下有一百个不同列的表格。想象一下,我有一个用户数据表,我希望将数据复制到基表。所以我写了这个简单的insert-select语句,弹出这个错误。那么,找出哪一列引起错误的最优雅方法是什么呢?
我对解决方案的初步想法是将它包装在一个事务中,我将最终回滚并使用一种Divide and Conquer方法:
begin tran
insert into BaseTable (c1,c2,c3,...,cN)
select c1,c2,c3,...,cN
from UserTable
rollback tran
这显然失败了。所以我们将列集分成两半:
begin tran
insert into BaseTable (c1,c2,c3,...,cK) --where K = N/2
select c1,c2,c3,...,cK --where K = N/2
from UserTable
rollback tran
如果失败则失败的列在另一半。我们继续这个过程,直到找到讨厌的专栏。
还有什么比这更优雅的?
注意:我也发现了这个问题的近乎重复,但它几乎没有答案。
答案 0 :(得分:6)
以下脚本会为SELECT
的每个整数列创建Basetable
个语句
执行生成的SELECT
语句应查明Usertable
中的违规列。
SELECT 'PRINT '''
+ sc.Name
+ '''; SELECT MIN(CAST('
+ sc.Name
+ ' AS INTEGER)) FROM Usertable'
FROM sys.columns sc
INNER JOIN sys.types st ON st.system_type_id = sc.system_type_id
WHERE OBJECT_NAME(Object_ID) = 'BaseTable'
AND st.name = 'INT'
答案 1 :(得分:0)
如果这只是您手动运行的内容,那么根据您插入的数据量,您可以使用OUTPUT
子句将插入的行输出到客户端。
输出的最后一行之后的行应该是有问题的那一行。
答案 2 :(得分:0)
我采用了Lieven Keersmaekers的方法但扩展了它。如果表具有各种数字字段长度,则此脚本将根据类型名称和精度更改Cast。考虑到这个解决方案,信用仍然留给了Lieven - 它给了我很多帮助。
DECLARE @tableName VARCHAR(100)
SET @tableName = 'tableName'
SELECT 'PRINT ''' + sc.NAME + '''; SELECT MIN(CAST([' + sc.NAME + '] as ' + CASE
WHEN st.NAME = 'int'
THEN 'int'
ELSE st.NAME + '(' + cast(sc.precision AS VARCHAR(5)) + ',' + cast(sc.scale AS VARCHAR(5)) + ')'
END + ')) from ' + @tableName
FROM sys.columns sc
INNER JOIN sys.types st ON st.system_type_id = sc.system_type_id
WHERE OBJECT_NAME(Object_ID) = @tableName
AND st.NAME NOT IN ('nvarchar', 'varchar', 'image', 'datetime', 'smalldatetime', 'char', 'nchar')
答案 3 :(得分:-1)
很多时候你建议的蛮力方法是最好的方法。
但是,如果您有数据库副本,也可以发布虚假数据。
对它运行查询,这样你就没有关于隐藏破坏它的列的transcation。有时候在错误中它会给出一个提示,说明是什么。通常,如果您正在查看正在发生的事情,您可以看到文本何时进入int,反之亦然。
我这样做,这会导致我的代码中的任何其他内容导致问题。
您需要获取生成的查询的副本,您可以将其复制并粘贴到查询工具中。
答案 4 :(得分:-1)
我认为你采取了错误的做法。如果通过简单地从一个表中选择列并插入另一个表来获得算术溢出,则必须从较大的colimns(例如bigint)中选择并插入小列(例如int)。这基本上是不正确的事情,你需要改变你的数据库结构,以便从一个表插入另一个表中的行将起作用。检查每个表中的每一列,看看可能出现溢出的位置,然后调整目标表,以便插入的数据适合。
如果你想要一个快速而肮脏的解决方案,我仍然认为我的观点仍然存在,但回应你的意见。在BaseTable varchar(MAX)中创建所有列。
然后:
insert into BaseTable (c1,c2,...,cN)
select CAST(c1 AS varchar(max)),CAST(c2 AS varchar(max))...,cN
from UserTable