【问题标题】:How to create only specific delete statements using Scripter如何使用 Scripter 仅创建特定的删除语句
【发布时间】:2015-08-11 19:50:36
【问题描述】:

我正在使用Scripter 类为我提供现有数据库中数据的脚本。我想编写一个可以插入生产数据库的数据集。我们这样做是为了测试我们的Software 的安装是否正确。

不幸的是,数据集稍后必须删除,没有留下任何条目,以免干扰我们客户的数据。所以我需要的是 INSERT 和 DELTE 语句。目前这些都是手动维护的,负担太大了。

很好,所以我只执行了两次 Scripter(一次用于 INSERT,一次用于 DELETE)

问题是当将ScriptDrops 设置为 true 时,输出的格式为

DELETE FROM [dbo].[TableName]

我想要的是某种形式:

DELETE FROM [dbo].[TableName] WHERE ID = 'GUID'

从技术上讲,这是可能的,因为所有表上都有主键。 Scripter 类也必须以某种形式知道这些事情,因为它还通过外键获得正确的 DELETE 语句(依赖项)的顺序。

对此的任何帮助将不胜感激。

以下是我用来导出数据的 2 个 PowerShell 脚本:

ScriptRepositoryData.ps1

$scriptPath = $MyInvocation.MyCommand.Path
$scriptDirectory = Split-Path $scriptPath -Parent

. $scriptDirectory\DatabaseScripting.ps1

$filepath='c:\data.sql'
$database='ECMS_Repository'

$tablesToExclude = @(
  "SomeUnwantedTable"
  )

$tablesListFromDatabase = GetTableList $database

$tablesArray = @()

$tablesListFromDatabase |% {
  if (-not $tablesToExclude.Contains($_.Name.ToString()))
  {
    $tablesArray += $_.Name
  }
}

ScriptInsert $database $tablesArray $filepath

DatabaseScripting.ps1

[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMO") | out-null
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SMOExtended") | out-null

Function GetTableList ($database)
{
  Invoke-SqlCmd -Database $database -query "SELECT * FROM sys.tables"
}

Function ScriptInsert ($database, $tables, $destination)
{
  try {

    $serverMO = new-object ("Microsoft.SqlServer.Management.Smo.Server") "localhost"
    if ($serverMO.Version -eq  $null) {Throw "Can't find the instance localhost"}

    $urnsToScript = New-Object Microsoft.SqlServer.Management.Smo.UrnCollection

    $databaseMO = $serverMO.Databases.Item("ECMS_Repository")
    if ($databaseMO.Name -ne $database) {Throw "Can't find the database $database"}

    $tables |% {

      $tableListMO = $databaseMO.Tables.Item($_, "dbo")

      $tableListMO |% {
        $urnsToScript.Add($_.Urn)
      } 
    }

    $scripter = new-object ('Microsoft.SqlServer.Management.Smo.Scripter') $serverMO
    $scripter.Options.ScriptSchema = $False;
    $scripter.Options.ScriptData = $true;
    $scripter.Options.ScriptDrops = $true;
    $scripter.Options.ScriptAlter = $true;

    $scripter.Options.NoCommandTerminator = $true;
    $scripter.Options.Filename = $destination;
    $scripter.Options.ToFileOnly = $true
    $scripter.Options.Encoding = [System.Text.Encoding]::UTF8

    $scripter.EnumScript($urnsToScript)

    Write-Host -ForegroundColor Green "Done"
  }
  catch {
    Write-Host
    Write-Host -ForegroundColor Red "Error occured"
    Write-Host
    Write-Host $_.Exception.ToString()
    Write-Host
  }
}

【问题讨论】:

    标签: sql-server powershell smo


    【解决方案1】:

    不幸的是,我没有找到使用 Sql 管理对象的方法。

    无论如何,我现在使用 Scripter 的输出并选择每个表的 ID。然后,我使用 ID 更改看起来像的每一行

    DELETE FROM [dbo].[tableName]
    

    到这里:

    DELETE FROM [dbo].[tableName] WHERE ID IN ('guid1', 'guid2')
    

    我是这样做的:

    $content = Get-Content $destination
    Clear-Content $destination
    
    $content |% {
      $line = $_
      $table = $line.Replace("DELETE FROM [dbo].[","").Replace("]","")
      $query = "SELECT ID, ClassID FROM" + $_
    
      $idsAsQueryResult = Invoke-SqlCmd -Database $database -query $query
      $ids = $idsAsQueryResult | Select-Object -Expand ID
    
      if ($ids -ne $null) {
        $joinedIDs = [string]::Join("','",$ids)
        $newLine = $line + " WHERE ID IN ('" + $joinedIDs + "')"
    
        Add-Content $destination $newLine
      }
    }
    

    其中 $destination 是使用 Scripter 类生成的脚本,$database 是包含数据库名称的字符串。

    我不得不选择第二列(ClassID,由于我们的OR mapper 重新存储,所有表上都有),因为 Select-Object 中有一些我不完全理解的奇怪错误。

    这当然有效,因为所有表都有主键,所有主键都命名为 ID,而不是组合主键或其他东西。 您当然可以通过 SQL 管理对象提取主键信息,从而为其他更复杂的数据库模式实现相同的目标。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-15
      • 2015-06-07
      • 1970-01-01
      • 2015-08-05
      • 1970-01-01
      • 2021-10-11
      • 1970-01-01
      相关资源
      最近更新 更多