2015-08-11 2 views
0

J'utilise la classe Scripter pour me donner un script pour les données d'une base de données existante. Je veux écrire un jeu de données qui peut être inséré dans une base de données de production. Nous faisons cela pour tester si une installation de notre Software est correcte.Comment créer uniquement des instructions de suppression spécifiques à l'aide de Scripter

Malheureusement, l'ensemble de données doit être retiré plus tard, sans aucune entrée laissée pour ne pas interférer avec les données de nos clients. Donc, ce dont j'ai besoin, ce sont des instructions INSERT et DELTE. Ceux-ci sont maintenus manuellement en ce moment, ce qui est trop lourd.

Très bien, donc je suis allé et exécuté le scripteur deux fois (une fois pour INSERT, une fois pour SUPPRIMER)

Le problème est que lors de la mise ScriptDrops à true, la sortie est sous la forme

DELETE FROM [dbo].[TableName] 

ce que je voudrais quelque chose de la forme:

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

techniquement, cela serait possible car il y a des clés primaires sur toutes les tables. La classe Scripter doit également, sous une forme ou une autre, connaître les choses puisqu'elle obtient également l'ordre des instructions DELETE (dépendances) correctes via les clés étrangères.

Toute aide à ce sujet serait appréciée.

Après sont les 2 scripts PowerShell-je utiliser pour exporter les données:

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 
    } 
} 

Répondre

0

Malheureusement, je n'ai pas trouvé un moyen Pour ce faire, utilisez les objets de gestion Sql.

De toute façon j'utilise maintenant la sortie du Scripter et sélectionne les identifiants de chaque table. J'utilise ensuite les ID de changer chaque ligne qui ressemble à

DELETE FROM [dbo].[tableName] 

à ceci:

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

Voici comment je l'ai fait:

$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 
    } 
} 

Où $ destination est le script a été généré avec la classe Scripter et $ database est une chaîne contenant le nom de la base de données.

J'ai dû sélectionner une deuxième colonne (ClassID qui est présente sur toutes les tables en raison de notre re-stockage OR mapper) en raison d'une erreur étrange dans Select-Object que je ne comprends pas complètement. Cela fonctionne bien sûr uniquement parce que toutes les tables ont des clés primaires et toutes les clés primaires sont nommées ID et ne sont pas combinées clés primaires ou quelque chose. Vous pouvez bien entendu obtenir la même chose pour d'autres schémas de base de données plus complexes en extrayant des informations de clé primaire via des objets de gestion SQL.