-- Rename article "father" columns to "parent" (SQL Server / MSSQL). -- -- One-off manual migration (no migration code is kept in the repo). -- sqlcmd -S -d -E -i scripts/migrate-parent-rename.mssql.sql -- -- Guarded and safe to re-run. Safe to retry after a partial run. -- -- NOTE ON BATCHING: sp_rename is deferred and its effect is not visible to -- subsequent statements in the SAME batch. Each rename therefore runs in its -- own batch (GO), and constraint/index recreation happens after a GO so the -- new column names resolve. SET XACT_ABORT ON; GO BEGIN TRANSACTION; GO -- Drop the old filtered unique index (references fathersort). IF EXISTS (SELECT 1 FROM sys.indexes WHERE name = 'UQ_article_fatherarticle_fathersort') DROP INDEX UQ_article_fatherarticle_fathersort ON article; GO -- Drop the default constraints bound to the old column names. IF EXISTS (SELECT 1 FROM sys.default_constraints WHERE name = 'DF_article_is_father') ALTER TABLE article DROP CONSTRAINT DF_article_is_father; IF EXISTS (SELECT 1 FROM sys.default_constraints WHERE name = 'DF_article_fathersort') ALTER TABLE article DROP CONSTRAINT DF_article_fathersort; GO -- Drop foreign keys bound to the old columns. IF EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_article_fatherarticle') ALTER TABLE article DROP CONSTRAINT FK_article_fatherarticle; IF EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_article_fatherattributename') ALTER TABLE article DROP CONSTRAINT FK_article_fatherattributename; GO -- Rename the columns (each sp_rename must be its own batch). IF COL_LENGTH('article', 'fatherarticle_id') IS NOT NULL AND COL_LENGTH('article', 'parentarticle_id') IS NULL EXEC sp_rename 'article.fatherarticle_id', 'parentarticle_id', 'COLUMN'; GO IF COL_LENGTH('article', 'fatherattributename_id') IS NOT NULL AND COL_LENGTH('article', 'parentattributename_id') IS NULL EXEC sp_rename 'article.fatherattributename_id', 'parentattributename_id', 'COLUMN'; GO IF COL_LENGTH('article', 'fathersort') IS NOT NULL AND COL_LENGTH('article', 'parentsort') IS NULL EXEC sp_rename 'article.fathersort', 'parentsort', 'COLUMN'; GO IF COL_LENGTH('article', 'is_father') IS NOT NULL AND COL_LENGTH('article', 'is_parent') IS NULL EXEC sp_rename 'article.is_father', 'is_parent', 'COLUMN'; GO COMMIT TRANSACTION; GO -- Recreate the constraints under their new names (after the rename batches). IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_article_parentarticle') ALTER TABLE article ADD CONSTRAINT FK_article_parentarticle FOREIGN KEY (parentarticle_id) REFERENCES article(id) ON DELETE NO ACTION; GO IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_article_parentattributename') ALTER TABLE article ADD CONSTRAINT FK_article_parentattributename FOREIGN KEY (parentattributename_id) REFERENCES attributename(id) ON DELETE NO ACTION; GO IF NOT EXISTS (SELECT 1 FROM sys.default_constraints WHERE name = 'DF_article_is_parent') ALTER TABLE article ADD CONSTRAINT DF_article_is_parent DEFAULT (0) FOR is_parent; GO IF NOT EXISTS (SELECT 1 FROM sys.default_constraints WHERE name = 'DF_article_parentsort') ALTER TABLE article ADD CONSTRAINT DF_article_parentsort DEFAULT (0) FOR parentsort; GO IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = 'UQ_article_parentarticle_parentsort') CREATE UNIQUE INDEX UQ_article_parentarticle_parentsort ON article (parentarticle_id, parentsort) WHERE parentarticle_id IS NOT NULL; GO -- Verify SELECT 'COL:' + c.name AS result FROM sys.columns c WHERE c.object_id = OBJECT_ID('article') AND (c.name LIKE '%father%' OR c.name LIKE '%parent%'); GO