如何阻止 OLEDB 自动创建“(sheet name)1”sheet

How to stop OLEDB to create "(sheet name)1" sheet automatically

背景

我正在编写一个 PowerShell 脚本,将一些数据写入 Excel 文件 (.xlsx),其中 Microsoft.ACE.OLEDB 如下所示:

$fileName = "C:\tmp\createtest.xlsx"
$sheetName = "record"
$provider = "Provider=Microsoft.ACE.OLEDB.12.0"
$dataSource = "Data Source = $fileName"
$extend = "Extended Properties=Excel 12.0"
$ddlSQL = "CREATE TABLE [$sheetName] (ID CHAR(4), NAME VARCHAR(20))"

$conn = New-Object System.Data.OleDb.OleDbConnection("$provider;$dataSource;$extend")

$sqlCommand = New-Object System.Data.OleDb.OleDbCommand
$sqlCommand.Connection = $conn
$conn.open()

$sqlCommand.CommandText = $ddlSQL
$sqlCommand.ExecuteNonQuery()
...
$conn.close()

问题

当您手动创建带有名为 record 的空 sheet 的 C:\tmp\createtest.xlsx 时,CREATE TABLE 语句会自动创建 record1 sheet。

我想停止这种行为,让 CREATE TABLE 语句像普通 RDBMS 一样抛出异常。

问题

当 Excel 文件有一个同名的 sheet 时,有什么方法可以阻止 OLEDB 自动创建 (sheet name)1 sheet 吗?

我找到了解决办法。执行 CREATE TABLE 后缀 $ for table name:

$ddlSQL = "CREATE TABLE [${sheetName}$] (ID CHAR(4), NAME VARCHAR(20))"

如果书和 sheet record 已经存在,则此语句将无误地完成。如果这本书或 sheet record 不存在,该语句将抛出 OleDbException。无论哪种方式,都不会创建新的 sheet,因此您可以安全地测试 sheet 的存在。

如果你想使用 sheet record 而不管现有的 sheet 并避免自动创建 record1 sheet,你可以这样做这个:

$checkExistenceSQL = "CREATE TABLE [${sheetName}$] (ID CHAR(4), NAME VARCHAR(20))"
$ddlSQL = "CREATE TABLE [$sheetName] (ID CHAR(4), NAME VARCHAR(20))"

$conn.open()
try {
  try {
    # Check existing sheet and open if it exists
    $sqlCommand.CommandText = $checkExistenceSQL
    $sqlCommand.ExecuteNonQuery() > $null
  } catch {
    try {
      # Create new sheet if it doesn't exist
      $sqlCommand.CommandText = $ddlSQL
      $sqlCommand.ExecuteNonQuery() > $null
    } catch {
      throw $PSItem
    }
  }

  $insertSQL = "INSERT INTO [${sheetName}$] VALUES (...)"
  $sqlCommand.CommandText = $insertSQL
  $sqlCommand.ExecuteNonQuery() > $null
} finally {
  $conn.close()
}

请注意,即使 sheet 已经存在,您也必须先执行 CREATE TABLE,因为它会影响数据类型约束的有效性。此外,您必须在 INSERT 语句中为 table 名称加上 $ 后缀,因为如果 sheet record 已经存在,它将失败。有关详细信息,请参阅 https://satob.hatenablog.com/entry/2021/11/24/003818 and https://satob.hatenablog.com/entry/2021/11/25/012835