2015-08-13 10 views
5

Sto rilasciando una versione più recente dell'applicazione Windows. Ci sono modifiche allo schema DB nella nuova versione. Inoltre, non voglio perdere i dati.Confronto di due schemi di database SQL Server in C#

Quindi l'approccio che ho preso è di sostituire le DLL preservando il database. Al fine di aggiornare il database, sto progettando di confrontare lo schema del database del vecchio database e apportare le modifiche necessarie.

Quindi, come posso confrontare la struttura del database (schema) di una vecchia a nuova e come posso rilevare le modifiche e correggerla. Quello che ho provato fino ad ora è provare e ottenere lo schema del database usando il metodo GetSchema.

Ma poiché il nuovo schema è predefinito, Come posso inserire il nuovo schema nel programma e confrontarlo con quello esistente nel sito in cui è stato installato precedente.

+2

Se è * l'applicazione *, perché non è possibile scrivere uno script che apporta le modifiche necessarie? Dovresti conoscere il vecchio formato e il nuovo formato. –

+1

Ma l'applicazione era stata rilasciata alcune volte e ogni volta aveva alcune modifiche al DB. Vogliamo che tutte queste versioni siano aggiornate alla versione più recente. Quindi non sappiamo se sta tentando di aggiornare dalla versione 1 o versione 2 o 3, che avrà uno schema DB diverso. – wintersolider

risposta

3

Utilizziamo SQL Confronta da RedGate, ma non è particolarmente economico.

SQL Compare

Questo ci permette di confrontare la struttura di due database, e crea uno script SQL per aggiornare uno dei database per abbinare l'altra.

+0

Grazie, ma ho bisogno di una soluzione programmatica e probabilmente gratuita; – wintersolider

+0

Capito. Dai un'occhiata alla mia altra soluzione. ;-) –

2

Crea gli script Database Migration ed eseguili con uno strumento come Db Up per tenere traccia delle modifiche dello schema. Script SQL consente di migrare il database dalla versione 1 alla 2, dalla 2 alla 3 e così via. Schema Compare è un'altra opzione menzionata in previous question.

  • Modifica clienti tables.sql
  • Aggiornamento Settings.sql
+0

+1 per Schema Compare, che è una funzionalità incorporata in Visual Studio, accessibile tramite 'Strumenti-> SQL Server-> Nuovo confronto degli schemi ...' in VS2015. –

4

Ecco un modo gratuito per confrontare i database.

Di seguito è riportato uno script di SQL Server che ho interrotto, che restituisce il contenuto delle stored procedure, delle viste e delle tabelle del database nella finestra Output.

lo si esegue chiamando:

exec [dbo].[ScriptStoredProcedures] 

Su molti dei miei progetti, corro questo script, copiare il testo in un file nel mio progetto di Visual Studio, in modo da effettuare il check-in una copia di come il nostro database ha guardato un momento particolare.

(Sì, si può anche avere Progetti di database all'interno di Visual Studio, ma questo è un metodo alternativo.)

Se si esegue questo script sia del database, è possibile confrontare le due uscite per trovare le differenze.

CREATE PROCEDURE [dbo].[ScriptStoredProcedures] 
AS 
BEGIN 
    -- 
    -- Attempt to create a long SQL script, to Drop, then "CREATE PROCEDURE" on all SPs and "CREATE FUNCTION" on all Functions in this database. 
    -- 
    -- You can then run this script on a "target" database, and it'll have the latest Stored Procedures & functions 
    -- created/updated on it. 
    -- 
    --  exec [dbo].[ScriptStoredProcedures] 
    -- 
    SET NOCOUNT ON 

    PRINT '--' 
    PRINT '-- SQL Script, generated by the [ScriptStoredProcedures] Stored Procedure.' 
    PRINT '-- Created on ' + convert(nvarchar, GetDate(), 106) + ' ' + convert(nvarchar, GetDate(), 108) 
    PRINT '--' 
    PRINT '-- This will create/update the Stored Procedures on this database, to bring them up-to-date with the SPs ' 
    PRINT '-- from the database ''' + DB_NAME() + ''' on the server ''' + @@SERVERNAME + '''' 
    PRINT '--' 
    PRINT '--' 



    -- Create a temporary table, where each record contains one line of Stored Procedure/Function script 
    -- (i.e. If you have a Stored Procedure with 30 lines of script in it, we'll create 30 temporary records 
    -- to store it) 
    CREATE TABLE #tmp 
    (
     [inx] INT IDENTITY(1, 1), 
     [text] nvarchar(4000) 
    ) 

    DECLARE @StoredProcedureName NVARCHAR(200) 
    DECLARE @StoredProcedureType NVARCHAR(10) 
    DECLARE @ExecCommand NVARCHAR(200) 
    DECLARE @OneLineOfScript NVARCHAR(4000) 

    -- First, get a list of all Stored Procedures & Functions in this database 
    DECLARE cursorEachStoredProcedure CURSOR LOCAL FORWARD_ONLY STATIC READ_ONLY FOR 
    SELECT [name],    -- Name of the Stored Procedure or Function 
      [type]    -- This will contain "FN" if it's a Function, or "P" if it's a Stored Procedure 
    FROM sysobjects 
    WHERE (OBJECTPROPERTY(id, N'IsProcedure') = 1 
     OR OBJECTPROPERTY(id, N'IsTableFunction') = 1 
     OR OBJECTPROPERTY(id, N'IsScalarFunction') = 1 
     OR OBJECTPROPERTY(id, N'IsView') = 1) 
    AND [name] NOT LIKE 'sp_%' 
    AND [name] NOT LIKE 'fn_%' 
    ORDER BY [type] DESC,  -- Sort by Stored Procedures first, then functions 
      [name]    -- then show the list of SPs/Functions in name order 


    OPEN cursorEachStoredProcedure 
    FETCH NEXT FROM cursorEachStoredProcedure INTO @StoredProcedureName, @StoredProcedureType 

    -- For each Stored Procedure we've found in our database, create some script to delete the Stored Procedure 
    -- from the target database if it exists, then re-create it. 
    WHILE (@@FETCH_STATUS = 0) 
    BEGIN 

     PRINT '' 
     IF (@StoredProcedureType = 'P') 
     BEGIN 
      PRINT 'PRINT ''Creating stored procedure: ''''' + @StoredProcedureName + '''''''' 
      PRINT '' 
      PRINT 'IF EXISTS(select Name from sysobjects where OBJECTPROPERTY(id, N''IsProcedure'') = 1 AND Name = ''' + @StoredProcedureName + ''')' 
      PRINT 'BEGIN' 
      PRINT ' DROP PROCEDURE [' + @StoredProcedureName + '] ' 
      PRINT 'END' 
     END 
     ELSE 
     IF (@StoredProcedureType = 'V') 
     BEGIN 
      PRINT 'PRINT ''Creating view: ''''' + @StoredProcedureName + '''''''' 
      PRINT '' 
      PRINT 'IF EXISTS(select Name from sysobjects where OBJECTPROPERTY(id, N''IsView'') = 1 AND Name = ''' + @StoredProcedureName + ''')' 
      PRINT 'BEGIN' 
      PRINT ' DROP VIEW [' + @StoredProcedureName + '] ' 
      PRINT 'END' 
     END 
     ELSE 
     BEGIN 
      PRINT 'PRINT ''Creating function: ''''' + @StoredProcedureName + '''''''' 
      PRINT '' 
      PRINT 'IF EXISTS(select Name from sysobjects where (OBJECTPROPERTY(id, N''IsTableFunction'') = 1 OR OBJECTPROPERTY(id, N''IsScalarFunction'') = 1) AND Name = ''' + @StoredProcedureName + ''')' 
      PRINT 'BEGIN' 
      PRINT ' DROP FUNCTION [' + @StoredProcedureName + '] ' 
      PRINT 'END' 
     END   
     PRINT 'GO ' 

     -- Run the "sp_helptext" command, to get the text of this Stored Procedure (one row per *line* of script) 
     -- and store this set of results in a temporary table, so we can step through, line-by-line, and send 
     -- the output to the Messages window. 
     SET @ExecCommand = 'sp_helptext @objname = ''' + @StoredProcedureName + '''' 

     DELETE FROM #tmp 

     INSERT INTO #tmp 
     EXEC(@ExecCommand) 

     -- Step through each line of this Stored Procedure 
     DECLARE cursorEachLineOfScript CURSOR LOCAL FORWARD_ONLY STATIC READ_ONLY FOR 
     SELECT [text] 
     FROM #tmp 
     ORDER BY [inx] 

     OPEN cursorEachLineOfScript 
     FETCH NEXT FROM cursorEachLineOfScript INTO @OneLineOfScript 

     WHILE (@@FETCH_STATUS = 0) 
     BEGIN 
      -- For each line of Stored Procedure script, send the text to the Messages window 
      PRINT @OneLineOfScript 

      FETCH NEXT FROM cursorEachLineOfScript INTO @OneLineOfScript 
     END 
     CLOSE cursorEachLineOfScript 
     DEALLOCATE cursorEachLineOfScript 
     PRINT 'GO ' 

     FETCH NEXT FROM cursorEachStoredProcedure INTO @StoredProcedureName, @StoredProcedureType 
    END 

    CLOSE cursorEachStoredProcedure 
    DEALLOCATE cursorEachStoredProcedure  

    DROP TABLE #tmp 

    PRINT 'EXEC [dbo].[spGrantExectoAllStoredProcs]' 
    PRINT 'GO' 

    PRINT '--' 
    PRINT '--' 
    PRINT '-- List of tables (and their fields) in this database' 
    PRINT '--' 
    PRINT '--' 
    PRINT '--' 


    -- First, let's iterate through our list of tables, and find out which fields they contain. 
    DECLARE 
     @tableName nvarchar(200), 
     @fieldName nvarchar(500), 
     @fieldType nvarchar(500), 
     @fieldNullable nvarchar(200) 

    DECLARE cursorTables CURSOR LOCAL FORWARD_ONLY STATIC READ_ONLY FOR 
    SELECT st.NAME as 'Table_name' 
    FROM sys.tables st 
    ORDER BY 1 

    OPEN cursorTables 
    FETCH NEXT FROM cursorTables INTO @tableName 

    WHILE (@@FETCH_STATUS = 0) 
    BEGIN 
     PRINT '-- Table: ' + @tableName 

     DECLARE cursorFields CURSOR LOCAL FORWARD_ONLY STATIC READ_ONLY FOR 
     SELECT sc.NAME as 'Field_name', 
      case when t.Name in ('char', 'varchar', 'nvarchar') 
      then t.Name + '(' + cast(sc.max_length/2 as nvarchar) + ')' 
      else 
       case when t.Name in ('numeric') 
        then t.Name + '(' + cast(sc.precision as nvarchar) + ',' + cast(sc.scale as nvarchar) + ')' 
        else t.Name 
       end 
     end as 'Data_type', 
     case when sc.is_nullable=1 then 'null' else 'not null' end as 'Nullable' 
     FROM sys.tables st 
     INNER JOIN sys.columns sc ON st.object_id = sc.object_id 
     INNER JOIN sys.types t ON sc.system_type_id = t.system_type_id 
     WHERE t.Name != 'sysname' 
     AND st.name = @tableName 
     ORDER BY 1, 2 

     OPEN cursorFields 
     FETCH NEXT FROM cursorFields INTO @fieldName, @fieldType, @fieldNullable 

     WHILE (@@FETCH_STATUS = 0) 
     BEGIN 
      PRINT '-- ' + @fieldName + ' (' + @fieldType + ', ' + @fieldNullable + ')' 
      FETCH NEXT FROM cursorFields INTO @fieldName, @fieldType, @fieldNullable 
     END 
     CLOSE cursorFields 
     DEALLOCATE cursorFields 

     PRINT '--' 

     FETCH NEXT FROM cursorTables INTO @tableName 
    END 
    CLOSE cursorTables 
    DEALLOCATE cursorTables 
END 
+0

Ciao, ottimo lavoro :) ho trovato un problema: questo '' 'INNER JOIN sys.types t ON sc.system_type_id = t.system_type_id''' creerà colonne duplicate nell'output quando usato con tipi definiti dall'utente di SQLServer della stessa base genere. la colonna '' 'sys.types.user_type_id''' sembra invece dovrebbe essere usata, dal momento che ha lo stesso contenuto di' 'system_type_id''' per i tipi standard. – FrankM

0

Due suggerimenti.

  1. utilizzare SQL Comparison SDK di Redgate (per chi lavoro). Ciò consente l'accesso programmatico alla tecnologia di confronto SQL.
  2. Ci deve essere una caratteristica di una particolare versione dello schema che è possibile verificare per determinare quale è? In tal caso, potresti eseguire lo script appropriato su quella versione per portarlo a quella successiva.Il tuo programma di installazione deve solo includere una catena di tali script di migrazione che vengono eseguiti in successione per portarlo alla versione incrementale successiva. Idealmente, avresti le informazioni sulla versione incorporate nello schema tramite una proprietà estesa o in una tabella delle versioni, che viene aggiornata in seguito all'applicazione corretta di uno script di migrazione.
Problemi correlati