質問

Our SSDT database project includes a table that has a computed column that can take one of several forms, depending on customer requirements. I'm trying to figure out how to manage this computed column so that we can still use the Publish function without reverting everyone's columns back to the default.

What I'm trying to accomplish can be explained in the following invalid T-SQL code:

CREATE TABLE dbo.Customer
(
  Id INTEGER,
  Region INTEGER,
  Name VARCHAR(50),
  AccountNumber AS dbo.FormatAccountNumber(Id, Region)
)

CREATE FUNCTION [dbo].[FormatAccountNumber]
(
  @Id INTEGER,
  @Region INTEGER
)
RETURNS VARCHAR(20)
AS
BEGIN
  IF '$(AccountType)' = 'Regional'
    RETURN CONVERT(VARCHAR, @Region) + '-' + CONVERT(VARCHAR, @Id)

  IF '$(AccountType)' = 'Merged'
    RETURN CONVERT(VARCHAR, @Region * 100000 + @Id)

  IF '$(AccountType)' = 'Flat'
    RETURN CONVERT(VARCHAR, @Id)
END

This, of course, doesn't work because the $(AccountType) SQLCMD variable can't be used inside of the function, and wouldn't be set properly at run-time anyway. I've also trying putting the SQLCMD conditional around the entire function:

IF '$(AccountType)' = 'Flat'
  CREATE FUNCTION ...

but this produces the error that "CREATE FUNCTION must be the only statement in the batch."

Is there any way to do any sort of conditional compilation of schema in the SSDT project? And if not, what options do I have for maintaining this sort of customizable field within the SSDT publishing process?

役に立ちましたか?

解決

You could use a Post-Deploment script to imperatively deploy your object in dynamic SQL:

IF NOT EXISTS (SELECT * FROM sys.objects 
            WHERE object_id = OBJECT_ID(N'[dbo].[FormatAccountNumber]') 
            AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
EXEC('CREATE FUNCTION [dbo].[FormatAccountNumber] () RETURNS BIT AS BEGIN RETURN 0 END')
GO 

IF '$(AccountType)' = 'Regional'
BEGIN
    EXEC('
        ALTER FUNCTION [dbo].[FormatAccountNumber]
        (
          @Id INTEGER,
          @Region INTEGER
        )
        RETURNS VARCHAR(20)
        AS
        BEGIN
            RETURN CONVERT(VARCHAR, @Region) + ''-'' + CONVERT(VARCHAR, @Id)
        END
    ')
END

Note that by doing this, you won't be able to make any references to the dbo.FormatAccountNumber function in your SSDT Database Project (unless those objects also included in the Post-Deployment script).

I also toyed with an alternate solution which involved addition conditionals within the .sqlproj file itself (within the ItemGroup elements), but this did get a bit messy since MsBuild Properties aren't exactly like-for-like with SQLCMD Variables, but I can post this if you like.

If you find yourself needing to conditionally deploy objects in your database often, you may like to consider moving to an imperative-based deployment solution (as opposed to the declarative style of SSDT projects). Imperative deployment, often called migrations, gives you greater control of deploy-time behaviour.

Disclaimer: I am the founder of ReadyRoll, which makes a product for VS that uses imperative deployment.

他のヒント

I have had an open discussion on MSDN about this need. Have not made much progress. The ideal situation would allow you to flag db objects as "inheritable" in base ssdt projects so that other projects that reference the base project or DAC won't complain of the duplicate object, and would only create the base object or "stub" if it did not exist. This would allow you to have "layers" of database models. See my post on msdn Extending SSDT Composite Solutions with Overriden Stored Procedures

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top