我正在使用以下行运行data.bat文件:
Rem Tis batch file will populate tables
cd\program files\Microsoft SQL Server\MSSQL
osql -U sa -P Password -d MyBusiness -i c:\data.sql
data.sql文件的内容是:
insert Customers
(CustomerID, CompanyName, Phone)
Values('101','Southwinds','19126602729')
还有8条类似的线路用于添加记录。
当我使用start
>运行时run
> cmd
> c:\data.bat
,我收到以下错误消息:
1>2>3>4>5>....<1 row affected>
Msg 8152, Level 16, State 4, Server SP1001, Line 1
string or binary data would be truncated.
<1 row affected>
<1 row affected>
<1 row affected>
<1 row affected>
<1 row affected>
<1 row affected>
此外,我显然是新手,但Level #
和state #
的含义是什么,以及如何查找上述错误消息:8152?
答案 0 :(得分:554)
每当你看到消息....
string or binary data would be truncated
自己想想......这个领域不足以保存我的数据。
检查customers表的表结构。我想你会发现一个或多个字段的长度不足以容纳你想要插入的数据。例如,如果Phone字段是varchar(8)字段,并且您尝试将11个字符添加到其中,则会出现此错误。
答案 1 :(得分:18)
在其中一个INSERT
语句中,您试图将太长的字符串插入字符串(varchar
或nvarchar
)列。
如果仅通过查看脚本来判断哪个INSERT
是罪犯并不明显,则可以计算错误消息之前发生的<1 row affected>
行。获得的数字加1为您提供声明编号。在你的情况下,它似乎是产生错误的第二个INSERT。
答案 2 :(得分:18)
虽然数据长度比字段长度短,但我遇到了这个问题。 事实证明,问题是有另一个日志表(用于审计跟踪),由主表上的触发器填充,其中列大小也必须更改。
答案 3 :(得分:11)
您的某些数据无法放入数据库列(小)。找到错误并不容易。如果使用C#和Linq2Sql,则可以列出将被截断的字段:
首先创建助手类:
public class SqlTruncationExceptionWithDetails : ArgumentOutOfRangeException
{
public SqlTruncationExceptionWithDetails(System.Data.SqlClient.SqlException inner, DataContext context)
: base(inner.Message + " " + GetSqlTruncationExceptionWithDetailsString(context))
{
}
/// <summary>
/// PArt of code from following link
/// http://stackoverflow.com/questions/3666954/string-or-binary-data-would-be-truncated-linq-exception-cant-find-which-fiel
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
static string GetSqlTruncationExceptionWithDetailsString(DataContext context)
{
StringBuilder sb = new StringBuilder();
foreach (object update in context.GetChangeSet().Updates)
{
FindLongStrings(update, sb);
}
foreach (object insert in context.GetChangeSet().Inserts)
{
FindLongStrings(insert, sb);
}
return sb.ToString();
}
public static void FindLongStrings(object testObject, StringBuilder sb)
{
foreach (var propInfo in testObject.GetType().GetProperties())
{
foreach (System.Data.Linq.Mapping.ColumnAttribute attribute in propInfo.GetCustomAttributes(typeof(System.Data.Linq.Mapping.ColumnAttribute), true))
{
if (attribute.DbType.ToLower().Contains("varchar"))
{
string dbType = attribute.DbType.ToLower();
int numberStartIndex = dbType.IndexOf("varchar(") + 8;
int numberEndIndex = dbType.IndexOf(")", numberStartIndex);
string lengthString = dbType.Substring(numberStartIndex, (numberEndIndex - numberStartIndex));
int maxLength = 0;
int.TryParse(lengthString, out maxLength);
string currentValue = (string)propInfo.GetValue(testObject, null);
if (!string.IsNullOrEmpty(currentValue) && maxLength != 0 && currentValue.Length > maxLength)
{
//string is too long
sb.AppendLine(testObject.GetType().Name + "." + propInfo.Name + " " + currentValue + " Max: " + maxLength);
}
}
}
}
}
}
然后为SubmitChanges准备包装器:
public static class DataContextExtensions
{
public static void SubmitChangesWithDetailException(this DataContext dataContext)
{
//http://stackoverflow.com/questions/3666954/string-or-binary-data-would-be-truncated-linq-exception-cant-find-which-fiel
try
{
//this can failed on data truncation
dataContext.SubmitChanges();
}
catch (SqlException sqlException) //when (sqlException.Message == "String or binary data would be truncated.")
{
if (sqlException.Message == "String or binary data would be truncated.") //only for EN windows - if you are running different window language, invoke the sqlException.getMessage on thread with EN culture
throw new SqlTruncationExceptionWithDetails(sqlException, dataContext);
else
throw;
}
}
}
准备全局异常处理程序和日志截断详细信息:
protected void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
string message = ex.Message;
//TODO - log to file
}
最后使用代码:
Datamodel.SubmitChangesWithDetailException();
答案 4 :(得分:7)
您可以收到此错误的另一种情况如下:
我遇到了同样的错误,原因是在从UNION接收数据的INSERT语句中,列的顺序与原始表不同。如果将#table3中的顺序更改为a,b,c,则将修复错误。
select a, b, c into #table1
from #table0
insert into #table1
select a, b, c from #table2
union
select a, c, b from #table3
答案 5 :(得分:7)
Web应用程序表面也出现此问题。 最终发现相同的错误消息来自特定表中的SQL更新语句。
最后,我们发现相关历史记录表中的列定义未在某些特定情况下映射nvarchar
类型的原始表格列长度。
希望这个暗示也可以帮助其他人..;)
答案 6 :(得分:7)
只想贡献一些额外的信息:我有同样的问题,因为该字段对于传入的数据来说不够大,而且这个线程帮助我解决了它(最重要的答案澄清了所有这些)。 / p>
但是知道可能导致它的原因是非常重要的。
在我的情况下,我用这样的字段创建表:
Select '' as Period, * From Transactions Into #NewTable
因此,字段“Period”的长度为零,导致Insert操作失败。我将其更改为“XXXXXX”,这是传入数据的长度,现在它正常工作(因为现在字段的长度为6)。
我希望这可以帮助任何有同样问题的人:)
答案 7 :(得分:7)
在sql server上你可以像这样使用SET ANSI_WARNINGS OFF:
using (SqlConnection conn = new SqlConnection("Data Source=XRAYGOAT\\SQLEXPRESS;Initial Catalog='Healthy Care';Integrated Security=True"))
{
conn.Open();
using (var trans = conn.BeginTransaction())
{
try
{
using cmd = new SqlCommand("", conn, trans))
{
cmd.CommandText = "SET ANSI_WARNINGS OFF";
cmd.ExecuteNonQuery();
cmd.CommandText = "YOUR INSERT HERE";
cmd.ExecuteNonQuery();
cmd.Parameters.Clear();
cmd.CommandText = "SET ANSI_WARNINGS ON";
cmd.ExecuteNonQuery();
trans.Commit();
}
}
catch (Exception)
{
trans.Rollback();
}
}
conn.Close();
}
答案 8 :(得分:6)
我有同样的问题。 我专栏的长度太短了。 您可以做的是增加长度或缩短您想要放入数据库的文本。
答案 9 :(得分:3)
即使增加了表中有问题的列的大小,我也遇到了同样的问题。
tl; dr:可能还需要增加相应表类型中匹配列的长度。
就我而言,该错误来自Microsoft Dynamics CRM中的数据导出服务,该服务允许CRM数据同步到SQL Server DB或Azure SQL DB。
经过长时间的调查,我得出结论,数据导出服务必须使用Table-Valued Parameters:
您可以使用表值参数将多行数据发送到Transact-SQL语句或例程(例如存储过程或函数),而无需创建临时表或许多参数。
如您在上面的文档中所见,表类型用于创建数据提取过程:
CREATE TYPE LocationTableType AS TABLE (...);
CREATE PROCEDURE dbo.usp_InsertProductionLocation
@TVP LocationTableType READONLY
不幸的是,无法更改表类型,因此必须完全删除并重新创建它。由于我的表有300多个字段(),因此我创建了一个查询,以基于表的列定义来方便地创建相应的表类型(只需将[table_name]
替换为表名)即可。
SELECT 'CREATE TYPE [table_name]Type AS TABLE (' + STRING_AGG(CAST(field AS VARCHAR(max)), ',' + CHAR(10)) + ');' AS create_type
FROM (
SELECT TOP 5000 COLUMN_NAME + ' ' + DATA_TYPE
+ IIF(CHARACTER_MAXIMUM_LENGTH IS NULL, '', CONCAT('(', IIF(CHARACTER_MAXIMUM_LENGTH = -1, 'max', CONCAT(CHARACTER_MAXIMUM_LENGTH,'')), ')'))
+ IIF(DATA_TYPE = 'decimal', CONCAT('(', NUMERIC_PRECISION, ',', NUMERIC_SCALE, ')'), '')
AS field
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = '[table_name]'
ORDER BY ORDINAL_POSITION) AS T;
更新表类型后,数据导出服务再次开始正常运行! :)
答案 10 :(得分:1)
可能发生此错误的另一种情况是 SQL Server Management Studio。如果表格中有“text”或“ntext”字段, 无论您要更新哪种类型的字段(例如位或整数)。 似乎Studio不会加载整个“ntext”字段,也会更新所有字段而不是修改后的字段。 要解决此问题,请从Management Studio
中的查询中排除“text”或“ntext”字段答案 11 :(得分:1)
当我尝试执行存储过程时,我遇到了同样的问题,因为我需要添加一些数据的列的大小比我要添加的数据要短。您可以增加列数据类型的大小或减少数据的长度。
答案 12 :(得分:0)
Kevin Pope's评论。
在我的情况下,问题是我在表上定义了一些触发器,这些触发器会将更新/插入事务插入到审计表中,但是审计表的数据类型不匹配,其中包含VARCHAR(MAX)
的列原始表在审计表中存储为VARCHAR(1)
,所以当我在原始表列中插入大于VARCHAR(1)
的内容并得到此错误消息时,触发器失败。
答案 13 :(得分:0)
我使用了不同的策略,在某些地方分配了8K的字段。这里只使用了50/100。
declare @NVPN_list as table
nvpn varchar(50)
,nvpn_revision varchar(5)
,nvpn_iteration INT
,mpn_lifecycle varchar(30)
,mfr varchar(100)
,mpn varchar(50)
,mpn_revision varchar(5)
,mpn_iteration INT
-- ...
) INSERT INTO @NVPN_LIST
SELECT left(nvpn ,50) as nvpn
,left(nvpn_revision ,10) as nvpn_revision
,nvpn_iteration
,left(mpn_lifecycle ,30)
,left(mfr ,100)
,left(mpn ,50)
,left(mpn_revision ,5)
,mpn_iteration
,left(mfr_order_num ,50)
FROM [DASHBOARD].[dbo].[mpnAttributes] (NOLOCK) mpna
我想要速度,因为我总共有1M条记录,并加载28K条记录。
答案 14 :(得分:0)
此错误可能是由于字段大小小于您输入的数据。
例如如果您的数据类型为nvarchar(7)
,并且您的值为'aaaaddddf',则错误显示为:
字符串或二进制数据将被截断
答案 15 :(得分:0)
2016/2017年更新将向您显示错误的值和列。
新的跟踪标志将旧的错误替换为新的2628错误,并将打印出列和有问题的值。在2016年和2017年的最新累积更新中提供了Traceflag 460:
只需确保在安装CU之后就可以在服务器上全局/永久启用跟踪标志:
...或使用DBCC TRACEON:
答案 16 :(得分:0)
您根本无法在此方面击败SQL Server。
您可以像这样插入到新表中:
select foo, bar
into tmp_new_table_to_dispose_later
from my_table
和将表定义与要将数据插入其中的真实表进行比较。
有时候有时会有所帮助。
如果您尝试从该临时表中插入最终表/实际表,则该表可能会起作用(例如,由于数据转换的工作方式不同于SSMS)。
另一种选择是将数据插入到块中,而不是立即插入所有内容,而是使用top 1000
插入并重复该过程,直到找到有错误的块为止。至少您可以更好地了解表格中不适合的内容。