加载包含 VARCHAR(MAX) 列的数据表时出错

发布于 2025-01-14 17:52:04 字数 1283 浏览 1 评论 0原文

我有 Powershell 以下函数,可以在给定连接字符串和查询的情况下通过 ODBC 从数据库加载数据。

function Run-OdbcSQL {
[OutputType([System.Data.DataTable])]
[cmdletbinding()]
param (

        [Parameter(Mandatory)][string]$ConnString,
        [Parameter(Mandatory)][string]$Query
)
    
    $Conn = New-Object System.Data.Odbc.OdbcConnection
    $Conn.ConnectionString = $ConnString
    $Conn.Open()
    try {
        $Result =(New-Object Data.Odbc.OdbcCommand($Query,$Conn)).ExecuteReader()
        
        $Table = New-Object "System.Data.DataTable"
        $Table.Load($Result)
        # Prevent PS from unravelling a table with a single row
        Write-Output -NoEnumerate $Table

    } finally {
        $Conn.Close()
    }
}

这工作正常,除非返回的列之一定义为 VARCHAR(MAX) 。在这种情况下,该函数返回错误:

Exception calling "Load" with "1" argument(s): "Failed to enable constraints. 
One or more rows contain values violating non-null, unique, or foreign-key constraints."

如果我将查询修改为 SELECT CAST(column_name AS VARCHAR(255)) FROM …,则将毫无问题地加载数据。

环境:

  • 数据库:SQL Server 2019
  • ODBC 驱动程序:SQL Server Native Client 11.0 / ODBC Driver 18 for SQL Server(两者均可重现)

该问题似乎是 VARCHAR(MAX)的组合System.Data.DataTable,但我不知道如何解决它。

I have the Powershell following function to load data from a database via ODBC, given a connection string and a query.

function Run-OdbcSQL {
[OutputType([System.Data.DataTable])]
[cmdletbinding()]
param (

        [Parameter(Mandatory)][string]$ConnString,
        [Parameter(Mandatory)][string]$Query
)
    
    $Conn = New-Object System.Data.Odbc.OdbcConnection
    $Conn.ConnectionString = $ConnString
    $Conn.Open()
    try {
        $Result =(New-Object Data.Odbc.OdbcCommand($Query,$Conn)).ExecuteReader()
        
        $Table = New-Object "System.Data.DataTable"
        $Table.Load($Result)
        # Prevent PS from unravelling a table with a single row
        Write-Output -NoEnumerate $Table

    } finally {
        $Conn.Close()
    }
}

This works fine, except when one of the columns being returned, is defined as VARCHAR(MAX). In this case, the function returns the error:

Exception calling "Load" with "1" argument(s): "Failed to enable constraints. 
One or more rows contain values violating non-null, unique, or foreign-key constraints."

If I modify the query to SELECT CAST(column_name AS VARCHAR(255)) FROM …, the data will be loaded without any issue.

Environment:

  • Database: SQL Server 2019
  • ODBC driver: SQL Server Native Client 11.0 / ODBC Driver 18 for SQL Server (reproducible with both)

The issue seems to be a combination of VARCHAR(MAX) and System.Data.DataTable, but I can't figure how to resolve it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

花桑 2025-01-21 17:52:04

没有明确的解决方案,但我设法找到了一些解决方法。

CAST(AS VARCHAR() 有效,但字符数限制为 8000 个,因为“SQL_CHARSQL_VARCHAR 数据类型的最大长度限制为 8,000 个字符" [1][2]

另一方面,text 数据类型可以容纳 2^30 - 1 个字节(与 NVARCHAR(MAX) 相同),看起来正确传递(无法找到任何具体信息),因此:`CAST( AS TEXT) 避免了该问题。

  • 数据:给定查询 列定义为 VARCHAR(MAX),检索列内容长度为 100.000 个字符的单行。

  • 中间件:使用ODBC Driver 18 for SQL ServerSQL Server Native Client 11.0执行测试。两位车手的结果都是相同的。

  • 数据库:Microsoft SQL Server 2019。

查询结果
SELECT 查询使用“1”个参数调用“Load”时发生异常:“无法启用约束。一个或更多行包含违反非空、唯一或外键约束的值。”
SELECT CAST(query as VARCHAR(8000))好的,截断为 8.000 个字符
SELECT CAST(query as VARCHAR(10000))给类型“varchar”指定的大小 (10000) 超出了任何数据类型允许的最大值 (8000)。
SELECT CAST(query as TEXT)OK, 10.000 个字符

备注

对于其他数据库(使用不同的中间件),此方法可能不起作用。例如,对于 PostgreSQL,您需要使用 MaxLongVarcharSize 属性,默认设置为 8190,最多支持 65535 字节。

No definite solution, but I have managed to find some workarounds.

The CAST(<columnname> AS VARCHAR(<length>) works, but you're limited to 8000 characters because "SQL_CHAR and SQL_VARCHAR data types are limited to a maximum length of 8,000 characters" [1][2]

The text datatype on the other hand, can hold 2^30 - 1 bytes (identical to NVARCHAR(MAX)) and it seems to be passed through correctly (couldn't find any concrete info). Thus: `CAST( AS TEXT) avoids the issue.

Test case

  • Data: given a query column defined as VARCHAR(MAX), retrieving a single row where the contents of the column are 100.000 characters long.

  • Middleware: Tests were executed using both ODBC Driver 18 for SQL Server and SQL Server Native Client 11.0. Results were identical for either driver.

  • Database: Microsoft SQL Server 2019.

QueryResult
SELECT queryException calling "Load" with "1" argument(s): "Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints."
SELECT CAST(query as VARCHAR(8000))OK, truncated at 8.000 characters
SELECT CAST(query as VARCHAR(10000))The size (10000) given to the type 'varchar' exceeds the maximum allowed for any data type (8000).
SELECT CAST(query as TEXT)OK, 10.000 characters

Remarks

For other databases (using different middleware), this approach might not work. E.g. for PostgreSQL, you need to use the MaxLongVarcharSize property, which is set to 8190 by default, and supports up to 65535 bytes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文