【问题标题】:Write-SqlTableData: The given value of type String from the data source cannot be converted to type bit of the specified target columnWrite-SqlTableData:来自数据源的String类型的给定值无法转换为指定目标列的类型位
【发布时间】:2017-07-21 23:34:58
【问题描述】:

我正在尝试使用Write-SqlTableData 写入表。名称已更改,因为它是公司数据库。

环境:

  • Windows 8.1 和 Powershell 5.0,SqlServer 模块 21.0.17099

命令:

Write-SqlTableData -DatabaseName 'dbname' -ServerInstance sql1 -TableName tablename -InputData (1,'1346',$false,'CalendarInvite') -Force -SchemaName "dbo"

错误:Write-SqlTableData : Input array is longer than the number of columns in this table.

表格列:

  • ID:int 身份
  • 范围:int
  • 上下文ID:ntext
  • FeatureEnabled:位
  • 类型:ntext

我不知道为什么会出现错误。四个值应该足够了,我按列顺序给它们。

我也尝试使用哈希表,但错误更令人困惑。

  • 哈希表:@{Scope=1;ContextID='1346';FeatureEnabled=$false;Type='CalendarInvite'}

  • 错误:Write-SqlTableData : The given value of type String from the data source cannot be converted to type int of the specified target column.

我完全糊涂了。我的命令有什么问题?


编辑: 该命令适用于我的测试 SQL (13.0.1601.5),但团队测试 SQL (11.0.3156.0)。也许版本很重要?

【问题讨论】:

  • 根据example here 它需要一个自定义对象。不仅仅是一个数组。因此,您可以使用哈希表,但如果您遵循示例,则键应该是列号。这对你有用吗-InputData @{1=1,2='1346',3=$false,4='CalendarInvite'}。尽管该错误表明一组值可以工作,但如果要信任它,也许您正在添加一个名称相似但列不同的表?
  • @Matt 我尝试使用您编写的表格,但它不起作用。我确信我将它插入到正确的表中。我怀疑第一列有些东西,因为它是一个自动增加的 id 列。我看到的所有示例都使用没有该功能的表格。

标签: sql-server powershell


【解决方案1】:

@Matt @DSakura:所以,我在这件事上撞了墙很长时间,但最终想通了……有点。我什至反编译了包含 Write-SqlTableData cmdlet (Microsoft.SqlServer.Management.PSSnapins) 的程序集。

这是我发现的:

这是一个错误。 在代码中,cmdlet 会尝试猜测您尝试向其发送的内容,然后尝试将您发送的内容重新格式化为与 SQL 期望接收的内容一致的内容。

它在这个过程中进行:

1 哪个 .Net 对象正在发送给我?

  • 是 SQL 数据集吗?
  • 它是 SQL 数据表吗?
  • 它是 SQL 数据行吗?
  • 是其他类型的时髦对象吗?

2 如果是时髦的对象,我可以把它变成我可以放入 SQL 表的东西吗?

.Net 对象不与 SQL 列类型对齐([System.String] 不是有效的 SQL 类型),因此 cmdlet 使用转换表进行最佳猜测(例如 nvarchar(MAX))然后在它转换类型后,它会尝试将其转储到表中。

当您使用“-force”参数创建一个全新的表时,这会更容易,因为它不必将您尝试输入的内容与现有表中已经存在的列相匹配。它只是做出最好的猜测,并将数据类型更改为 SQL 可以理解的类型。

例子:

哈希表

Write-SQLTableData -TableName TableHash -SchemaName dbo -DatabaseName DB1 -ServerInstance localhost\SQLExpress -InputData @{col1="SomeString"} -force

生产:

-------------------------- | |钥匙 |价值 | -------------------------- | 1 | col1 |一些字符串 | --------------------------

有类型:

------------------------------------------ |列名 |数据类型 |允许空值 | ------------------------------------------ | [钥匙] | sql_varient | | ------------------------------------------ |价值 | sql_varient | | ------------------------------------------

PSObject

$Obj = New-Object PSObject -Property @{col1="SomeString"}

Write-SQLTableData -TableName TablePSObject -SchemaName dbo -DatabaseName DB1 -ServerInstance localhost\SQLExpress -InputData $Obj -force

生产:

------------------ | | col1 | ------------------ | 1 |一些字符串 | ------------------

有类型:

--------------------------------------------- |列名 |数据类型 |允许空值 | --------------------------------------------- | col1 | nvarchar(MAX) |真的 | ---------------------------------------------

所以,这就是它变得复杂的地方。当您有一个现有表时,cmdlet 会尽最大努力将您的数据与表列对齐。它还不是很擅长。文档提供的默认示例显示了如何通过将您的值放入哈希表中来执行此操作,其中列名作为哈希键。 这不适用于现有表 官方文档在这里:https://docs.microsoft.com/en-us/powershell/module/sqlserver/write-sqltabledata?view=sqlserver-ps

现有表失败示例

现有表:

--------------------------------------------- |列名 |数据类型 |允许空值 | --------------------------------------------- | col1 | varchar(MAX) |错误 | --------------------------------------------- | col2 |正文 |错误 | ---------------------------------------------

PowerShell 命令:

Write-SQLTableData -TableName TableExistsAlready -SchemaName dbo -DatabaseName DB1 -ServerInstance localhost\SQLExpress -InputData @{col1="SomeText";col2="SomeMoreText"}

Write-SQLTableData -TableName TableExistsAlready -SchemaName dbo -DatabaseName DB1 -ServerInstance localhost\SQLExpress -InputData @{col1="SomeText2";col2="SomeMoreText2"}

生产:

----------------------------------------- | | col1 | col2 | ----------------------------------------- | 1 | col2 | SomeMoreText | ----------------------------------------- | 2 | col1 |一些文本 | ----------------------------------------- | 3 | col2 |更多文本2 | ----------------------------------------- | 4 | col1 |一些文本2 | -----------------------------------------

不用说,这不是我们所期望的。

当您尝试将更复杂的数据类型放入表中时,情况会变得更糟,即使您在哈希表中排列了正确的类型(字符串与字符串,整数与整数等),在写入 SQL 阶段,它永远不会正确排列列。

那么,解决办法是什么?

在这里... 代码实际上是为了处理类型[PSCustomObject]而编写的。

如果您想了解 PSObject、Hash 和 PSCustomObject 类型之间的详细区别,请参阅以下内容: Difference between PSObject, Hashtable and PSCustomObject

所以,既然我们知道了我们需要什么,同样重要的是要注意哈希表不设置项目的顺序(至少默认情况下不设置)。但是,您可以指定 PSObject 类型的顺序,但不能使用快速“散列”创建方法。您必须单独定义每个 NoteProperty。见:Change order of columns in the object

但是,从 PowerShell V3 开始,Microsoft 为 [PSCustomObject] 添加了一个类型加速器,该加速器使用有序哈希表创建对象,因此属性保持声明它们的顺序。幸运的是,这正是我们想要的类型。

那么,让我们再做一次:

现有表工作示例

现有表(注意,我原封不动地保留了原始数据):

--------------------------------------------- |列名 |数据类型 |允许空值 | --------------------------------------------- | col1 | varchar(MAX) |错误 | --------------------------------------------- | col2 |正文 |错误 | ---------------------------------------------

PowerShell 命令:

$Obj = [PSCustomObject] @{col1="SomeText";col2="SomeMoreText"}

Write-SQLTableData -TableName TableExistsAlready -SchemaName dbo -DatabaseName DB1 -ServerInstance localhost\SQLExpress -InputData $Obj

$Obj2 = [PSCustomObject] @{col1="SomeText2";col2="SomeMoreText2"}

Write-SQLTableData -TableName TableExistsAlready -SchemaName dbo -DatabaseName DB1 -ServerInstance localhost\SQLExpress -InputData $Obj2

生产:

---------------------------------- | | col1 | col2 | ---------------------------------- | 1 | col2 | SomeMoreText | ---------------------------------- | 2 | col1 |一些文本 | ---------------------------------- | 3 | col2 |更多文本2 | ---------------------------------- | 4 | col1 |一些文本2 | ---------------------------------- | 5 |一些文本 | SomeMoreText | ---------------------------------- | 6 |一些文本2 |更多文本2 | ----------------------------------

万岁!它实际上是在正确的顺序!现在,不要忘记,如果你有一个需要 int 的列,你需要确保你的输入与它所期望的一致。我将把 cmdlet 用于比较类型的转换表放在底部。我从编译的 dll 中反汇编了代码,所以不能保证准确度。

所以,现在让我们转到“id”(自动递增标识规范)列问题。如果您未在 PSCustomObject 中添加该列,您的 SQL 写入将被拒绝。但是,没问题!事实证明,我们可以添加 id 列名并将值留为空白,然后它会以 SQL 将下一个值放入的方式进行转换。

ID 列示例

现有表(注意,这是一个新的空白表,只有列,没有行数据):

--------------------------------------------- |列名 |数据类型 |允许空值 | --------------------------------------------- |编号 |整数 |错误 | --------------------------------------------- | col1 | varchar(50) |错误 | --------------------------------------------- | col2 |正文 |错误 | --------------------------------------------- 注意:“id”列的身份规范(是身份)变为“是”,身份增量设置为 1,身份种子设置为 1。

PowerShell 命令:

$Obj = [PSCustomObject] @{
                    id=''
                    col1="SomeString"
                    col2="SomeMoreString"
}

Write-SQLTableData -TableName TableWithID -SchemaName dbo -DatabaseName DB1 -ServerInstance localhost\SQLExpress -InputData $Obj

生产:

-------------------------------------- | |编号 | col1 | col2 | -------------------------------------- | 1 | 1 |一些文本 | SomeMoreText | --------------------------------------

你说什么?当您再执行四次命令时会发生什么?我很高兴你问: PowerShell 命令:

$Obj = [PSCustomObject] @{
                    id=''
                    col1="SomeString"
                    col2="SomeMoreString"
}

Write-SQLTableData -TableName TableWithID -SchemaName dbo -DatabaseName DB1 -ServerInstance localhost\SQLExpress -InputData $Obj

Write-SQLTableData -TableName TableWithID -SchemaName dbo -DatabaseName DB1 -ServerInstance localhost\SQLExpress -InputData $Obj

Write-SQLTableData -TableName TableWithID -SchemaName dbo -DatabaseName DB1 -ServerInstance localhost\SQLExpress -InputData $Obj

Write-SQLTableData -TableName TableWithID -SchemaName dbo -DatabaseName DB1 -ServerInstance localhost\SQLExpress -InputData $Obj

生产:

-------------------------------------- | |编号 | col1 | col2 | -------------------------------------- | 1 | 1 |一些文本 | SomeMoreText | -------------------------------------- | 2 | 2 |一些文本 | SomeMoreText | -------------------------------------- | 3 | 3 |一些文本 | SomeMoreText | -------------------------------------- | 4 | 4 |一些文本 | SomeMoreText | -------------------------------------- | 5 | 5 |一些文本 | SomeMoreText | --------------------------------------

嗯...这比我想象的要长。我希望这对其他人有所帮助。

这是转换表:

类型转换表

case "System.String":
    return DataType.NVarCharMax;

case "System.Int64":
    return DataType.BigInt;

case "System.Byte[]":
    return DataType.VarBinaryMax;

case "System.Boolean":
    return DataType.Bit;

case "System.Char":
    return DataType.NChar(1);

case "System.DateTime":
    return DataType.DateTime2(7);

case "System.DateTimeOffset":
    return DataType.DateTimeOffset(7);

case "System.Decimal":
    return DataType.Decimal(14, 0x1c);

case "System.Double":
    return DataType.Float;

case "System.Int32":
    return DataType.Int;

case "System.Char[]":
    return DataType.NVarCharMax;

case "System.Single":
    return DataType.Real;

case "System.Int16":
    return DataType.SmallInt;

case "System.Object":
    return DataType.Variant;

case "System.TimeSpan":
    return DataType.Timestamp;

case "System.Byte":
    return DataType.TinyInt;

case "System.Guid":
    return DataType.UniqueIdentifier;

case "System.UInt64":
    return DataType.Numeric(0, 20);

case "System.UInt32":
    return DataType.BigInt;

case "System.UInt16":
    return DataType.Int;

case "System.SByte":
    return DataType.SmallInt;

case "Microsoft.SqlServer.Types.SqlHierarchyId":
    return DataType.HierarchyId;

case "Microsoft.SqlServer.Types.SqlGeography":
    return DataType.Geography;

case "Microsoft.SqlServer.Types.SqlGeometry":
    return DataType.Geometry;

【讨论】:

  • 添加与此帖子相关的错误消息以帮助搜索引擎优化页面:Write-SQLTableData : Cannot insert the value NULL into column , table ;列不允许空值。插入失败。 FullyQualifiedErrorId : WriteToTableFailure,Microsoft.SqlServer.Management.PowerShell.WriteSqlTableData WriteError: ([dbo]. :Table) [Write-SqlTableData], SqlException
  • 哇,像魔术一样工作!我也做了反编译,但到目前为止还没有。我当时去的SQL命令,但现在我想我可以重写它:D 感谢您的努力!
  • 我想知道为什么这会被复制并发布在这里? android.develop-bugs.com/article/11705144/… 去看看。人们会偷任何东西
  • 我使用Write-SqlTableData 从System.Data.DataTable 加载到SQL。你会认为这是正确的方法,对吧??不。出于某种莫名其妙的原因,我的脚本刚刚停止加载到正确的库中。阅读本文,似乎明确列映射的唯一方法是使用PSCustomObject
猜你喜欢
  • 2015-01-19
  • 1970-01-01
  • 1970-01-01
  • 2013-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-27
相关资源
最近更新 更多