Any *easy* way to compare database schemas, without a 3rd party tool?

  • I've been asked to compare an older copy of a DB to a current copy, to look for any schema changes. The problem is, while I suspect Red Gates SQL Compare would do this zip-zip-easy, due to the security of the environment it's a PITA to get a 3rd party tool approved.

    So, is there any easy way in SSMS to compare two DBs? Everything I've found so far indicates no, seeing as I have no access to Visual Studio (which has a tool built-in, but while this is approved software it has it's own issues with getting it,) and my comment above about a 3rd party tool.

    Am I going to be reduced to coding up something to list each column, its datatype, FK relationships, etc, then running it against the current and previous DB and eyeballing the list for changes?

    Thanks,

    Jason

  • I was going to suggest SQL Server Data Tools, which is Visual Studio of course...

    Need an answer? No, you need a question
    My blog at https://sqlkover.com.
    MCSE Business Intelligence - Microsoft Data Platform MVP

  • Not sure if this will give you all you require, have you tried:

    Using SSMS

    Right click on DB

    Select Reports

    Click on Schema change history

    If everything seems to be going well, you have obviously overlooked something.

    Ron

    Please help us, help you -before posting a question please read[/url]
    Before posting a performance problem please read[/url]

  • Ron, that may do some good. One question on the report, does it only go back to the last time the SQL Server service was restarted? I'm presuming yes based on the report I'm currently looking at.

    Thanks,

    Jason

  • Checked using my play database and it went back to 9/17 (2 days) and my play DB gets shut down each night.

    But of course that is a very, very short duration - so I can not say for sure.

    If everything seems to be going well, you have obviously overlooked something.

    Ron

    Please help us, help you -before posting a question please read[/url]
    Before posting a performance problem please read[/url]

  • Have you tried using the view INFORMATION_SCHEMA.COLUMNS?

    It might have the information you need to compare.

    Luis C.
    General Disclaimer:
    Are you seriously taking the advice and code from someone from the internet without testing it? Do you at least understand it? Or can it easily kill your server?

    How to post data/code on a forum to get the best help: Option 1 / Option 2
  • Am I going to be reduced to coding up something to list each column, its datatype, FK relationships, etc, then running it against the current and previous DB and eyeballing the list for changes?

    Luis mentioned the information_schema.

    You could get most (maybe all) of what you need by querying the tables information_schema (tables, constraints, views, stored procs, functions, etc...) Below are a couple examples.

    --CHECK Constraints

    (

    -- stuff that's in db1 that's not in db2

    SELECT --CONSTRAINT_CATALOG

    Constraint_schema, constraint_name, check_clause

    FROM db1.INFORMATION_SCHEMA.CHECK_CONSTRAINTS

    EXCEPT

    SELECT Constraint_schema, constraint_name, check_clause

    FROM db2.INFORMATION_SCHEMA.CHECK_CONSTRAINTS

    )

    UNION ALL

    (

    -- stuff that's in db2 that's not in db1

    SELECT Constraint_schema, constraint_name, check_clause

    FROM db2.INFORMATION_SCHEMA.CHECK_CONSTRAINTS

    EXCEPT

    SELECT Constraint_schema, constraint_name, check_clause

    FROM db1.INFORMATION_SCHEMA.CHECK_CONSTRAINTS

    )

    --TABLES

    (

    SELECT -- TABLE_CATALOG

    TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE

    FROM db1.INFORMATION_SCHEMA.TABLES

    EXCEPT

    SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE

    FROM db2.INFORMATION_SCHEMA.TABLES

    )

    UNION ALL

    (

    SELECT table_schema, table_name, table_type

    FROM db2.INFORMATION_SCHEMA.TABLES

    EXCEPT

    SELECT table_schema, table_name, table_type

    FROM db1.INFORMATION_SCHEMA.TABLES

    )

    A couple things to note:

    1) Exclude the column that defines the DB name; it's usually the first one (e.g. CONSTRAINT_CATALOG or TABLE_CATALOG)

    2) You will have to use the object_ID function for routine_definitions (e.g. stored procs, functions)

    EDIT: Typo in my code

    "I cant stress enough the importance of switching from a sequential files mindset to set-based thinking. After you make the switch, you can spend your time tuning and optimizing your queries instead of maintaining lengthy, poor-performing code."

    -- Itzik Ben-Gan 2001

  • Thanks for the suggestions, and I'm still working on this. I did come up with something to give a very quick-and-dirty overview of the tables / columns / datatypes within the DBs using sys.tables and sys.all_columns.

    I'm sure there are plenty of ways this could be improved, but so far for what I need it's a start...

    use [ExistingDB];

    select

    SCHEMA_NAME(st.schema_id) as [SchemaName],

    st.name as [TableName],

    sac.name as [ColumnName],

    (select name from sys.types where user_type_id = sac.user_type_id) as [DataType],

    sac.max_length as [MaxLen],

    sac.precision as [Precision]

    into #currentDB

    from sys.tables as st

    inner join sys.all_columns as sac

    on st.object_id = sac.object_id

    use [RestoredDB];

    select

    SCHEMA_NAME(st.schema_id) as [SchemaName],

    st.name as [TableName],

    sac.name as [ColumnName],

    (select name from sys.types where user_type_id = sac.user_type_id) as [DataType],

    sac.max_length as [MaxLen],

    sac.precision as [Precision]

    into #OldDB

    from sys.tables as st

    inner join sys.all_columns as sac

    on st.object_id = sac.object_id

    select

    CDB.schemaname as [Current Schema]

    , OldDB.schemaname as [Old Schema]

    , CDB.TableName as [Current Table]

    , OldDB.TableName as [Old Table]

    , CDB.ColumnName as [Current Column]

    , OldDB.ColumnName as [Old Column]

    /*, CDB.DataType as [Current Datatype]

    , OldDB.DataType as [Current Datatype]

    , CDB.MaxLen as [Current MaxLength]

    , OldDB.MaxLen as [Current MaxLength]

    , CDB.Precision as [Current Precision]

    , OldDB.Precision as [Current Precision]*/

    from #currentDB as CDB

    full join #OldDB as OldDB

    on CDB.TableName = OldDB.TableName

    order by CDB.SchemaName, CDB.TableName

    drop table #currentDB

    drop table #OldDB

  • You're on the right track; definitely use the sys. views rather than the INFORMATION_SCHEMA views, which are not reliable in SQL Server (from 2005 on).

    These are the basic tables you'll need:

    sys.columns

    sys.foreign_key_columns

    sys.index_columns

    If you need to consider functions and/or stored proc parameters, you'll want to add:

    sys.parameters

    SQL DBA,SQL Server MVP(07, 08, 09) "It's a dog-eat-dog world, and I'm wearing Milk-Bone underwear." "Norm", on "Cheers". Also from "Cheers", from "Carla": "You need to know 3 things about Tortelli men: Tortelli men draw women like flies; Tortelli men treat women like flies; Tortelli men's brains are in their flies".

  • You can use a FULL OUTER JOIN to find columns that are in only one object and not the other.

    I can post sample code for that if you'd like.

    SQL DBA,SQL Server MVP(07, 08, 09) "It's a dog-eat-dog world, and I'm wearing Milk-Bone underwear." "Norm", on "Cheers". Also from "Cheers", from "Carla": "You need to know 3 things about Tortelli men: Tortelli men draw women like flies; Tortelli men treat women like flies; Tortelli men's brains are in their flies".

  • ScottPletcher (9/19/2013)


    You can use a FULL OUTER JOIN to find columns that are in only one object and not the other.

    I can post sample code for that if you'd like.

    I did some checking, a FULL JOIN and FULL OUTER JOIN are the same in SQL2008R2 (which is what the server is.) That's why I set the code up the way I did, you can rather quickly see what tables do and don't exist in which DB, did the schema change, you can even check the datatypes by uncommenting a few lines in the last select...

    I've already found a query to return a listing of FKs in a table, and it won't be any work at all to take that query and this one to generate a similar listing.

  • You might consider using SSMS to create a script for the database/table to a file (right click on table name and choose script as). Then use the Microsoft Word compare option to do a compare. I've used this on occasion and it seems to work out well. The Microsoft Word compare function seems to be pretty good at finding the actual differences and not get fouled up by new lines/fields.

Viewing 12 posts - 1 through 11 (of 11 total)

You must be logged in to reply to this topic. Login to reply