SQL Source Control 4

Help for older versions available.

These pages cover SQL Source Control 4, which is not the latest version. Help for other versions is also available.

Example - deploying with migration scripts

This example shows you how to create a migration script for a database so you can deploy automatically without fear of data loss.

In the example, the Magic Widget Company has a SQL Server database running on a live web server. This database contains a number of tables, views, stored procedures, and other database objects.

The Magic Widget Company's development is working on an update to this database. They've already created a copy of the production database as a baseline to develop against. They've linked their development copy of the database to source control, and will now set up the ability to create and manage migration scripts.

The example has four stages:

  1. Set up the databases
  2. Specify a migration scripts location
  3. Create a migration script
  4. Deploy the migration script

Requirements

The example uses:

1. Set up the databases

This example uses the WidgetDev and WidgetStaging databases.

To create the databases on your SQL Server:

  1. View the SQL creation script for the databases (click to expand)

    SQL creation script Toggle source code

    1. /*
    2. Create Widget Staging
    3. */
    4. USE tempdb
    5. GO
    6. IF EXISTS (SELECT name FROM sys.databases
    7. WHERE name = N'WidgetStaging'
    8. )
    9. DROP DATABASE WidgetStaging
    10. GO
    11.  
    12. CREATE DATABASE WidgetStaging
    13. GO
    14. USE WidgetStaging
    15. GO
    16.  
    17. CREATE TABLE [dbo].[WidgetPrices] (
    18. [RecordID] [int] IDENTITY (1, 1) NOT NULL ,
    19. [WidgetID] [int] NULL ,
    20. [Price] [money] NULL
    21. ) ON [PRIMARY]
    22. GO
    23.  
    24. CREATE TABLE [dbo].[WidgetDescriptions] (
    25. [WidgetID] [int] IDENTITY (1, 1) NOT NULL ,
    26. [Description] [varchar] (500) NULL ,
    27. [WidgetName] [varchar] (50) NULL
    28. )ON [PRIMARY]
    29. GO
    30.  
    31. CREATE TABLE [dbo].[Widgets] (
    32. [RecordID] [int] IDENTITY (1, 1) NOT NULL ,
    33. [Description] [varchar] (50) NULL
    34. ) ON [PRIMARY]
    35. GO
    36.  
    37. CREATE TABLE [dbo].[WidgetReferences] (
    38. [WidgetID] [int] IDENTITY NOT NULL ,
    39. [Reference] [varchar] (50) NULL
    40. ) ON [PRIMARY]
    41. GO
    42.  
    43. ALTER TABLE [dbo].[WidgetReferences] WITH NOCHECK ADD
    44. CONSTRAINT [PK_WidgetReferences] PRIMARY KEY NONCLUSTERED
    45. (
    46. [WidgetID]
    47. ) ON [PRIMARY]
    48. GO
    49.  
    50. ALTER TABLE [dbo].[WidgetPrices] WITH NOCHECK ADD
    51. CONSTRAINT [PK_WidgetPrices] PRIMARY KEY NONCLUSTERED
    52. (
    53. [RecordID]
    54. ) ON [PRIMARY]
    55. GO
    56.  
    57. ALTER TABLE [dbo].[Widgets] WITH NOCHECK ADD
    58. CONSTRAINT [PK_Widgets] PRIMARY KEY NONCLUSTERED
    59. (
    60. [RecordID]
    61. ) ON [PRIMARY]
    62. GO
    63.  
    64. SET QUOTED_IDENTIFIER ON SET ANSI_NULLS ON
    65. GO
    66.  
    67. CREATE VIEW dbo.CurrentPrices
    68. AS
    69. SELECT WidgetID, Price, Description
    70. FROM Widgets INNER JOIN
    71. WidgetPrices ON Widgets.RecordID = WidgetPrices.WidgetID
    72.  
    73. GO
    74. SET QUOTED_IDENTIFIER OFF SET ANSI_NULLS ON
    75. GO
    76. /*
    77. Populate WidgetStaging with data
    78. */
    79. USE WidgetStaging
    80. GO
    81. SET NUMERIC_ROUNDABORT OFF
    82. GO
    83. SET ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, ARITHABORT, QUOTED_IDENTIFIER, ANSI_NULLS, NOCOUNT ON
    84. GO
    85. SET DATEFORMAT YMD
    86. GO
    87. SET XACT_ABORT ON
    88. GO
    89. SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
    90. GO
    91. BEGIN TRANSACTION
    92. -- Pointer used for text / image updates. This might not be needed, but is declared here just in case
    93. DECLARE @pv binary(16)
    94.  
    95. -- Add 10 rows to [dbo].[WidgetPrices]
    96. SET IDENTITY_INSERT [dbo].[WidgetPrices] ON
    97. INSERT INTO [dbo].[WidgetPrices] ([RecordID], [WidgetID], [Price]) VALUES (1, 9, 698.1374)
    98. INSERT INTO [dbo].[WidgetPrices] ([RecordID], [WidgetID], [Price]) VALUES (2, 6, 325.4914)
    99. INSERT INTO [dbo].[WidgetPrices] ([RecordID], [WidgetID], [Price]) VALUES (3, 6, 693.4032)
    100. INSERT INTO [dbo].[WidgetPrices] ([RecordID], [WidgetID], [Price]) VALUES (4, 5, 116.1689)
    101. INSERT INTO [dbo].[WidgetPrices] ([RecordID], [WidgetID], [Price]) VALUES (5, 3, 751.7997)
    102. INSERT INTO [dbo].[WidgetPrices] ([RecordID], [WidgetID], [Price]) VALUES (6, 5, 49.3884)
    103. INSERT INTO [dbo].[WidgetPrices] ([RecordID], [WidgetID], [Price]) VALUES (7, 5, 422.2571)
    104. INSERT INTO [dbo].[WidgetPrices] ([RecordID], [WidgetID], [Price]) VALUES (8, 1, 895.2037)
    105. INSERT INTO [dbo].[WidgetPrices] ([RecordID], [WidgetID], [Price]) VALUES (9, 10, 596.7856)
    106. INSERT INTO [dbo].[WidgetPrices] ([RecordID], [WidgetID], [Price]) VALUES (10, 4, 213.4546)
    107. SET IDENTITY_INSERT [dbo].[WidgetPrices] OFF
    108.  
    109. -- Add 10 rows to [dbo].[WidgetReferences]
    110. SET IDENTITY_INSERT [dbo].[WidgetReferences] ON
    111. INSERT INTO [dbo].[WidgetReferences] ([WidgetID], [Reference]) VALUES (1, 'HRGM1S45G9L67Z6M9V74RCKV0ZQCYOW01OXJMLTMGB0')
    112. INSERT INTO [dbo].[WidgetReferences] ([WidgetID], [Reference]) VALUES (2, '0ULCDFPYJID56LL11R7RDK5J1MZN1KNFBGV6EDYIYYHJA')
    113. INSERT INTO [dbo].[WidgetReferences] ([WidgetID], [Reference]) VALUES (3, 'D10RLP49QF')
    114. INSERT INTO [dbo].[WidgetReferences] ([WidgetID], [Reference]) VALUES (4, '1AQF2WZUXTPQENN')
    115. INSERT INTO [dbo].[WidgetReferences] ([WidgetID], [Reference]) VALUES (5, 'OTE3L899YN')
    116. INSERT INTO [dbo].[WidgetReferences] ([WidgetID], [Reference]) VALUES (6, 'YYB2QGHC283V2IODYNAL3XWFFCB3S1GGFL0V')
    117. INSERT INTO [dbo].[WidgetReferences] ([WidgetID], [Reference]) VALUES (7, 'RZAWBKKLYCLXVAMN1612')
    118. INSERT INTO [dbo].[WidgetReferences] ([WidgetID], [Reference]) VALUES (8, 'NE4EJ')
    119. INSERT INTO [dbo].[WidgetReferences] ([WidgetID], [Reference]) VALUES (9, 'RMGGHTR7N0ORCCUHZQ6XQUSDFZTP4L5ISJTYHW3443YNCEOQ1')
    120. INSERT INTO [dbo].[WidgetReferences] ([WidgetID], [Reference]) VALUES (10, 'ED8LAXU20IZ122V6ZTIVZ3M1SMV500B3NY6R968W4E')
    121. SET IDENTITY_INSERT [dbo].[WidgetReferences] OFF
    122.  
    123. -- Add 10 rows to [dbo].[Widgets]
    124. SET IDENTITY_INSERT [dbo].[Widgets] ON
    125. INSERT INTO [dbo].[Widgets] ([RecordID], [Description]) VALUES (1, 'quad trepicandor rarendum quo non Pro quis')
    126. INSERT INTO [dbo].[Widgets] ([RecordID], [Description]) VALUES (2, 'non linguens cognitio, imaginator estis')
    127. INSERT INTO [dbo].[Widgets] ([RecordID], [Description]) VALUES (3, 'estum. travissimantor fecit. homo, et')
    128. INSERT INTO [dbo].[Widgets] ([RecordID], [Description]) VALUES (4, 'non transit. venit. nomen quad esset pladior Sed')
    129. INSERT INTO [dbo].[Widgets] ([RecordID], [Description]) VALUES (5, 'esset quantare Versus et quantare Sed novum Multum')
    130. INSERT INTO [dbo].[Widgets] ([RecordID], [Description]) VALUES (6, 'trepicandor ut egreddior trepicandor apparens')
    131. INSERT INTO [dbo].[Widgets] ([RecordID], [Description]) VALUES (7, 'transit. Multum Sed esset venit. sed pladior quad')
    132. INSERT INTO [dbo].[Widgets] ([RecordID], [Description]) VALUES (8, 'quad habitatio estis quoque Sed et et rarendum')
    133. INSERT INTO [dbo].[Widgets] ([RecordID], [Description]) VALUES (9, 'in vantis. Longam, linguens novum Tam quartu bono')
    134. INSERT INTO [dbo].[Widgets] ([RecordID], [Description]) VALUES (10, 'quis fecit, Longam, linguens Sed gravum funem.')
    135. SET IDENTITY_INSERT [dbo].[Widgets] OFF
    136.  
    137. -- Add 10 rows to [dbo].[WidgetDescriptions]
    138. SET IDENTITY_INSERT [dbo].[WidgetDescriptions] ON
    139. INSERT INTO [dbo].[WidgetDescriptions] ([WidgetID], [Description], [WidgetName]) VALUES (1, 'vantis. fecundio, quad eggredior. nomen nomen quad dolorum gravum ut et quantare vobis quartu bono quad funem.', '89541')
    140. INSERT INTO [dbo].[WidgetDescriptions] ([WidgetID], [Description], [WidgetName]) VALUES (2, 'apparens Id novum Sed estis si gravum apparens gravum dolorum fecundio, quis et glavans cognitio, quoque', '19614')
    141. INSERT INTO [dbo].[WidgetDescriptions] ([WidgetID], [Description], [WidgetName]) VALUES (3, 'Et Pro plorum trepicandor pladior e fecundio, vobis novum bono pars Quad regit, travissimantor e cognitio, nomen', '21711')
    142. INSERT INTO [dbo].[WidgetDescriptions] ([WidgetID], [Description], [WidgetName]) VALUES (4, 'volcans Longam, estis non non estis et Id vantis. esset transit. Sed et fecit, vobis fecit. plurissimum quorum rarendum trepicandor quantare cognitio, si', '51534')
    143. INSERT INTO [dbo].[WidgetDescriptions] ([WidgetID], [Description], [WidgetName]) VALUES (5, 'essit. volcans quad novum in brevens, si manifestum cognitio, non eudis glavans e delerium. eggredior.', '40493')
    144. INSERT INTO [dbo].[WidgetDescriptions] ([WidgetID], [Description], [WidgetName]) VALUES (6, 'glavans eggredior. eudis delerium. cognitio, pars fecit. funem. essit. si pladior eggredior. glavans', '78782')
    145. INSERT INTO [dbo].[WidgetDescriptions] ([WidgetID], [Description], [WidgetName]) VALUES (7, 'quo, plorum quo vobis manifestum Et imaginator eggredior. rarendum et quad fecit. linguens delerium. linguens', '50517')
    146. INSERT INTO [dbo].[WidgetDescriptions] ([WidgetID], [Description], [WidgetName]) VALUES (8, 'Longam, quorum glavans ut Longam, e e venit. brevens, parte dolorum Longam, Quad et esset novum Sed Tam', NULL)
    147. INSERT INTO [dbo].[WidgetDescriptions] ([WidgetID], [Description], [WidgetName]) VALUES (9, 'bono Sed plorum quad quad si plurissimum et Quad gravis homo, bono sed quo egreddior imaginator plorum Sed', '38345')
    148. INSERT INTO [dbo].[WidgetDescriptions] ([WidgetID], [Description], [WidgetName]) VALUES (10, 'pladior cognitio, quartu volcans vobis pladior nomen Id transit. quorum plurissimum sed vantis. in quis', '86125')
    149. SET IDENTITY_INSERT [dbo].[WidgetDescriptions] OFF
    150. COMMIT TRANSACTION
    151. GO
    152.  
    153.  
    154. /*
    155. Create Widget Dev
    156. */
    157.  
    158. IF EXISTS (SELECT name FROM sys.databases
    159. WHERE name = N'WidgetDev'
    160. )
    161.  
    162.  
    163. DROP DATABASE WidgetDev
    164. GO
    165.  
    166. CREATE DATABASE WidgetDev
    167. GO
    168. USE WidgetDev
    169. GO
    170.  
    171. CREATE TABLE [dbo].[WidgetPrices] (
    172. [RecordID] [int] IDENTITY (1, 1) NOT NULL ,
    173. [WidgetID] [int] NULL ,
    174. [Price] [money] NULL ,
    175. [DateValidFrom] [datetime] NULL ,
    176. [DateValidTo] [datetime] NULL ,
    177. [Active] [char] (1) NULL
    178. ) ON [PRIMARY]
    179. GO
    180.  
    181. CREATE TABLE [dbo].[WidgetDescriptions] (
    182. [WidgetID] [int] IDENTITY (1, 1) NOT NULL ,
    183. [Description] [varchar] (500) NULL ,
    184. [WidgetName] [varchar] (50) NULL
    185. )ON [PRIMARY]
    186. GO
    187.  
    188. CREATE TABLE [dbo].[Widgets] (
    189. [RecordID] [int] IDENTITY (1, 1) NOT NULL ,
    190. [Description] [varchar] (50) NULL ,
    191. [SKU] [varchar] (20) NULL
    192. ) ON [PRIMARY]
    193. GO
    194.  
    195. CREATE TABLE [dbo].[WidgetReferences] (
    196. [WidgetID] [int] NOT NULL ,
    197. [Reference] [varchar] (50) NULL
    198. ) ON [PRIMARY]
    199. GO
    200.  
    201. ALTER TABLE [dbo].[WidgetReferences] WITH NOCHECK ADD
    202. CONSTRAINT [PK_WidgetReferences] PRIMARY KEY NONCLUSTERED
    203. (
    204. [WidgetID]
    205. ) ON [PRIMARY]
    206. GO
    207.  
    208. ALTER TABLE [dbo].[WidgetPrices] WITH NOCHECK ADD
    209. CONSTRAINT [DF_WidgetPrices_DateValidFrom] DEFAULT (getdate()) FOR [DateValidFrom],
    210. CONSTRAINT [DF_WidgetPrices_Active] DEFAULT ('N') FOR [Active],
    211. CONSTRAINT [PK_WidgetPrices] PRIMARY KEY NONCLUSTERED
    212. (
    213. [RecordID]
    214. ) ON [PRIMARY]
    215. GO
    216.  
    217. ALTER TABLE [dbo].[Widgets] WITH NOCHECK ADD
    218. CONSTRAINT [PK_Widgets] PRIMARY KEY NONCLUSTERED
    219. (
    220. [RecordID]
    221. ) ON [PRIMARY]
    222. GO
    223.  
    224. CREATE INDEX [IX_WidgetPrices] ON [dbo].[WidgetPrices]([WidgetID]) ON [PRIMARY]
    225. GO
    226.  
    227. CREATE INDEX [IX_WidgetPrices_1] ON [dbo].[WidgetPrices]([DateValidFrom]) ON [PRIMARY]
    228. GO
    229.  
    230. CREATE INDEX [IX_WidgetPrices_2] ON [dbo].[WidgetPrices]([DateValidTo]) ON [PRIMARY]
    231. GO
    232.  
    233. GRANT SELECT ON [dbo].[WidgetPrices] TO [public]
    234. GO
    235.  
    236. DENY REFERENCES , INSERT , DELETE , UPDATE ON [dbo].[WidgetPrices] TO [public] CASCADE
    237. GO
    238.  
    239. GRANT SELECT ON [dbo].[Widgets] TO [public]
    240. GO
    241.  
    242. DENY REFERENCES , INSERT , DELETE , UPDATE ON [dbo].[Widgets] TO [public] CASCADE
    243. GO
    244.  
    245. ALTER TABLE [dbo].[WidgetPrices] ADD
    246. CONSTRAINT [FK_WidgetPrices_Widgets] FOREIGN KEY
    247. (
    248. [WidgetID]
    249. ) REFERENCES [dbo].[Widgets] (
    250. [RecordID]
    251. )
    252. GO
    253.  
    254. SET QUOTED_IDENTIFIER ON SET ANSI_NULLS ON
    255. GO
    256.  
    257. CREATE VIEW dbo.CurrentPrices
    258. AS
    259. SELECT WidgetPrices.WidgetID, WidgetPrices.Price,
    260. Widgets.Description
    261. FROM dbo.Widgets INNER JOIN
    262. dbo.WidgetPrices ON
    263. dbo.Widgets.RecordID = dbo.WidgetPrices.WidgetID
    264. WHERE dbo.WidgetPrices.Active = 'Y'
    265.  
    266. GO
    267. SET QUOTED_IDENTIFIER OFF SET ANSI_NULLS ON
    268. GO
    269.  
    270. GRANT SELECT ON [dbo].[CurrentPrices] TO [public]
    271. GO
    272.  
    273. DENY INSERT , DELETE , UPDATE ON [dbo].[CurrentPrices] TO [public] CASCADE
    274. GO
    275.  
    276. SET QUOTED_IDENTIFIER ON SET ANSI_NULLS ON
    277. GO
    278.  
    279. CREATE PROCEDURE prcActivatePrices AS
    280.  
    281. UPDATE WidgetPrices SET Active='N' WHERE GetDate()<DateValidTo OR GetDate()>DateValidFrom
    282. UPDATE WidgetPrices SET Active='Y' WHERE GetDate()>=DateValidFrom OR GetDate()<=DateValidFrom
    283.  
    284.  
    285. GO
    286. SET QUOTED_IDENTIFIER OFF SET ANSI_NULLS ON
    287. GO
    288.  
    289. DENY EXECUTE ON [dbo].[prcActivatePrices] TO [public] CASCADE
    290. GO
    291.  
    292. /*
    293. Populate WidgetDev with data
    294. */
    295. USE WidgetDev
    296. GO
    297. SET NUMERIC_ROUNDABORT OFF
    298. GO
    299. SET ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, ARITHABORT, QUOTED_IDENTIFIER, ANSI_NULLS, NOCOUNT ON
    300. GO
    301. SET DATEFORMAT YMD
    302. GO
    303. SET XACT_ABORT ON
    304. GO
    305. SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
    306. GO
    307. BEGIN TRANSACTION
    308. -- Pointer used for text / image updates. This might not be needed, but is declared here just in case
    309. DECLARE @pv binary(16)
    310.  
    311. -- Drop constraints from [dbo].[WidgetPrices]
    312. ALTER TABLE [dbo].[WidgetPrices] DROP CONSTRAINT [FK_WidgetPrices_Widgets]
    313.  
    314. -- Add 10 rows to [dbo].[WidgetDescriptions]
    315. SET IDENTITY_INSERT [dbo].[WidgetDescriptions] ON
    316. INSERT INTO [dbo].[WidgetDescriptions] ([WidgetID], [Description], [WidgetName]) VALUES (1, 'vantis. fecundio, quad eggredior. nomen nomen quad dolorum gravum ut et quantare vobis quartu bono quad funem.', '89541')
    317. INSERT INTO [dbo].[WidgetDescriptions] ([WidgetID], [Description], [WidgetName]) VALUES (2, 'apparens Id novum Sed estis si gravum apparens gravum dolorum fecundio, quis et glavans cognitio, quoque', '19614')
    318. INSERT INTO [dbo].[WidgetDescriptions] ([WidgetID], [Description], [WidgetName]) VALUES (3, 'Et Pro plorum trepicandor pladior e fecundio, vobis novum bono pars Quad regit, travissimantor e cognitio, nomen', '21711')
    319. INSERT INTO [dbo].[WidgetDescriptions] ([WidgetID], [Description], [WidgetName]) VALUES (4, 'volcans Longam, estis non non estis et Id vantis. esset transit. Sed et fecit, vobis fecit. plurissimum quorum rarendum trepicandor quantare cognitio, si', '51534')
    320. INSERT INTO [dbo].[WidgetDescriptions] ([WidgetID], [Description], [WidgetName]) VALUES (5, 'essit. volcans quad novum in brevens, si manifestum cognitio, non eudis glavans e delerium. eggredior.', '40493')
    321. INSERT INTO [dbo].[WidgetDescriptions] ([WidgetID], [Description], [WidgetName]) VALUES (6, 'glavans eggredior. eudis delerium. cognitio, pars fecit. funem. essit. si pladior eggredior. glavans', '78782')
    322. INSERT INTO [dbo].[WidgetDescriptions] ([WidgetID], [Description], [WidgetName]) VALUES (7, 'quo, plorum quo vobis manifestum Et imaginator eggredior. rarendum et quad fecit. linguens delerium. linguens', '50517')
    323. INSERT INTO [dbo].[WidgetDescriptions] ([WidgetID], [Description], [WidgetName]) VALUES (8, 'Longam, quorum glavans ut Longam, e e venit. brevens, parte dolorum Longam, Quad et esset novum Sed Tam', NULL)
    324. INSERT INTO [dbo].[WidgetDescriptions] ([WidgetID], [Description], [WidgetName]) VALUES (9, 'bono Sed plorum quad quad si plurissimum et Quad gravis homo, bono sed quo egreddior imaginator plorum Sed', '38345')
    325. INSERT INTO [dbo].[WidgetDescriptions] ([WidgetID], [Description], [WidgetName]) VALUES (10, 'pladior cognitio, quartu volcans vobis pladior nomen Id transit. quorum plurissimum sed vantis. in quis', '86125')
    326. SET IDENTITY_INSERT [dbo].[WidgetDescriptions] OFF
    327.  
    328. -- Add 10 rows to [dbo].[WidgetReferences]
    329. INSERT INTO [dbo].[WidgetReferences] ([WidgetID], [Reference]) VALUES (1, 'HRGM1S45G9L67Z6M9V74RCKV0ZQCYOW01OXJMLTMGB0')
    330. INSERT INTO [dbo].[WidgetReferences] ([WidgetID], [Reference]) VALUES (2, '0ULCDFPYJID56LL11R7RDK5J1MZN1KNFBGV6EDYIYYHJA')
    331. INSERT INTO [dbo].[WidgetReferences] ([WidgetID], [Reference]) VALUES (3, 'D10RLP49QF')
    332. INSERT INTO [dbo].[WidgetReferences] ([WidgetID], [Reference]) VALUES (4, '1AQF2WZUXTPQENN')
    333. INSERT INTO [dbo].[WidgetReferences] ([WidgetID], [Reference]) VALUES (5, 'OTE3L899YN')
    334. INSERT INTO [dbo].[WidgetReferences] ([WidgetID], [Reference]) VALUES (6, 'YYB2QGHC283V2IODYNAL3XWFFCB3S1GGFL0V')
    335. INSERT INTO [dbo].[WidgetReferences] ([WidgetID], [Reference]) VALUES (7, 'RZAWBKKLYCLXVAMN1612')
    336. INSERT INTO [dbo].[WidgetReferences] ([WidgetID], [Reference]) VALUES (8, 'NE4EJ')
    337. INSERT INTO [dbo].[WidgetReferences] ([WidgetID], [Reference]) VALUES (9, 'RMGGHTR7N0ORCCUHZQ6XQUSDFZTP4L5ISJTYHW3443YNCEOQ1')
    338. INSERT INTO [dbo].[WidgetReferences] ([WidgetID], [Reference]) VALUES (10, 'ED8LAXU20IZ122V6ZTIVZ3M1SMV500B3NY6R968W4E')
    339.  
    340. -- Add 10 rows to [dbo].[Widgets]
    341. SET IDENTITY_INSERT [dbo].[Widgets] ON
    342. INSERT INTO [dbo].[Widgets] ([RecordID], [Description]) VALUES (1, 'quad trepicandor rarendum quo non Pro quis')
    343. INSERT INTO [dbo].[Widgets] ([RecordID], [Description]) VALUES (2, 'non linguens cognitio, imaginator estis')
    344. INSERT INTO [dbo].[Widgets] ([RecordID], [Description]) VALUES (3, 'estum. travissimantor fecit. homo, et')
    345. INSERT INTO [dbo].[Widgets] ([RecordID], [Description]) VALUES (4, 'non transit. venit. nomen quad esset pladior Sed')
    346. INSERT INTO [dbo].[Widgets] ([RecordID], [Description]) VALUES (5, 'esset quantare Versus et quantare Sed novum Multum')
    347. INSERT INTO [dbo].[Widgets] ([RecordID], [Description]) VALUES (6, 'trepicandor ut egreddior trepicandor apparens')
    348. INSERT INTO [dbo].[Widgets] ([RecordID], [Description]) VALUES (7, 'transit. Multum Sed esset venit. sed pladior quad')
    349. INSERT INTO [dbo].[Widgets] ([RecordID], [Description]) VALUES (8, 'quad habitatio estis quoque Sed et et rarendum')
    350. INSERT INTO [dbo].[Widgets] ([RecordID], [Description]) VALUES (9, 'in vantis. Longam, linguens novum Tam quartu bono')
    351. INSERT INTO [dbo].[Widgets] ([RecordID], [Description]) VALUES (10, 'quis fecit, Longam, linguens Sed gravum funem.')
    352. SET IDENTITY_INSERT [dbo].[Widgets] OFF
    353.  
    354. -- Add 10 rows to [dbo].[WidgetPrices]
    355. SET IDENTITY_INSERT [dbo].[WidgetPrices] ON
    356. INSERT INTO [dbo].[WidgetPrices] ([RecordID], [WidgetID], [Price]) VALUES (1, 9, 698.1374)
    357. INSERT INTO [dbo].[WidgetPrices] ([RecordID], [WidgetID], [Price]) VALUES (2, 6, 325.4914)
    358. INSERT INTO [dbo].[WidgetPrices] ([RecordID], [WidgetID], [Price]) VALUES (3, 6, 693.4032)
    359. INSERT INTO [dbo].[WidgetPrices] ([RecordID], [WidgetID], [Price]) VALUES (4, 5, 116.1689)
    360. INSERT INTO [dbo].[WidgetPrices] ([RecordID], [WidgetID], [Price]) VALUES (5, 3, 751.7997)
    361. INSERT INTO [dbo].[WidgetPrices] ([RecordID], [WidgetID], [Price]) VALUES (6, 5, 49.3884)
    362. INSERT INTO [dbo].[WidgetPrices] ([RecordID], [WidgetID], [Price]) VALUES (7, 5, 422.2571)
    363. INSERT INTO [dbo].[WidgetPrices] ([RecordID], [WidgetID], [Price]) VALUES (8, 1, 895.2037)
    364. INSERT INTO [dbo].[WidgetPrices] ([RecordID], [WidgetID], [Price]) VALUES (9, 10, 596.7856)
    365. INSERT INTO [dbo].[WidgetPrices] ([RecordID], [WidgetID], [Price]) VALUES (10, 4, 213.4546)
    366. SET IDENTITY_INSERT [dbo].[WidgetPrices] OFF
    367.  
    368. -- Add constraints to [dbo].[WidgetPrices]
    369. ALTER TABLE [dbo].[WidgetPrices] ADD CONSTRAINT [FK_WidgetPrices_Widgets] FOREIGN KEY ([WidgetID]) REFERENCES [dbo].[Widgets] ([RecordID])
    370. COMMIT TRANSACTION
    371. GO
  2. Copy the script, paste it into a query window in SQL Server Management Studio, and run it.

The databases and their schema are created.

2. Specify a migration scripts location

This example assumes WidgetDev is already linked to source control, but no migration scripts folder has been set up.

Linking associates the database with a location in source control. For detailed instruction on linking a database to source control, see Linking to source control.

Migration scripts are customizable change scripts that SQL Compare uses in deployment. They can be used to avoid data loss and to avoid the need to repeatedly make manual configuration changes.

To specify a location to store migration scripts:

  1. Make sure WidgetDev is selected in the Object Explorer.
  2. In SQL Source Control, on the Setup tab, under Source control details, click Set up migration scripts:

    The Link Migrations Repository dialog box opens:

    No migration scripts folder is set up, so we'll create one.

  3. Next to the migration scripts repository URL, click Browse.

    The Select Migration Scripts Repository dialog box is displayed:

    The best place to store your migration scripts depends on your development environment. In this example, we will create a sibling folder at the same level as the database schema.

    For more information, see Working with Migrations.

  4. Click Create Folder.

    The Create Folder dialog box is displayed.

  5. In Folder Name, type a name for the folder.

    In this example, call the folder WidgetMigrations

  6. Click Create.

    The new folder is displayed on the Select Migration Scripts Repository dialog box.

  7. Make sure the Widget Migrations folder is selected, and click Select.

    The new migration scripts location is selected

  8. On the Link Migrations Repository dialog box, click Link.

    Migration scripts are now set up.

3. Create a migration script

In this example, we want to add a NOT NULL constraint to a column in the WidgetDescriptions table in WidgetDev.

In SQL Server Management Studio, open a new query window, and run the following SQL queries:

  1. UPDATE [WidgetDescriptions] SET WidgetName = '<Unset>' WHERE WidgetName IS NULL

This updates all rows in the table with the value <Unset> for the WidgetName column.

  1. ALTER TABLE [WidgetDescriptions] ADD CONSTRAINT CK_WidgetName_NOTNULL CHECK (WidgetName IS NOT NULL)

This adds a NOT NULL constraint on the WidgetName column.

If we commit this change and then try to deploy it to WidgetStaging using SQL Compare, the deployment will fail; a default value is required when adding a NOT NULL constraint to a column with existing data.

We can specify a default value if we commit the change as a migration script:

  1. In SQL Source Control, on the Commit Changes tab, right-click the change to WidgetDescriptions, and click Add New Migration Script:

    The Create migration script dialog box is displayed:

  2. Make sure the table WidgetDescriptions is selected, and click Create and edit script.
    A new query window opens, populated with the script to deploy the change:

    Here you can specify a name for the script and edit it to prevent errors in deployment.

  3. Before the final ALTER TABLE statement in the script, add the following SQL:

    1. UPDATE [WidgetDescriptions] SET WidgetName = '<Unset>' WHERE WidgetName IS NULL
    2.  
    3. GO
  4. Click Proceed to commit.
    SQL Source Control displays a confirmation dialog box:

  5. Click Save.
    The migration script is now listed on the Commit Changes tab:

  6. Type a commit comment, and click Commit.
    The migration script is committed to source control. SQL Compare can now use the script during deployment.

4. Deploy the migration script

Now we have created a migration script for the change, we can deploy it to WidgetStaging using SQL Compare:

  1. In SQL Compare, on the Project Configuration dialog box, select the latest version of WidgetDev as the source, andWidgetStaging as the target:


    Click Compare Now.
    The comparison results are displayed:

    You can see changes to WidgetDev that we will deploy to WidgetStaging.
    The change to the table WidgetDescriptions is covered by the migration script we created.

    When SQL Compare is using a migration script to augment its own generated change script, this is indicated with the icon 

  2. In the comparison results pane, make sure the check boxes for all objects with differences are selected:

  3. Click Deployment Wizard.
  4. On the first page of the Deployment Wizard, select a deployment method.

    In this example we will deploy using SQL Compare.

  5. Click Next.
    The Review migration scripts page of the wizard is displayed:

    The upper pane of the page lists the migration scripts you can select to include in the deployment.
    The lower pane shows where in deployment SQL Compare will use the selected scripts.
    In this example, the migration script we committed is listed, and included by default.

  6. Click Next.
  7. The Review script page of the wizard is displayed, showing the generated deployment script.

    The migration script we selected to include forms part of the deployment script.

  8. Click Deploy Now.
  9. A confirmation dialog box is displayed. Click Deploy Now to continue.
    SQL Compare runs the deployment.
    The comparison results are displayed, showing that WidgetDev and WidgetStaging are now the same. The columnWidgetName now has a default value, and no data was lost in the deployment.

The migration script we created will be re-used in future deployments, so there is no need to manually add the default values each time you deploy.


Didn't find what you were looking for?