Constraint for only one record marked as default










31















How could I set a constraint on a table so that only one of the records has its isDefault bit field set to 1?



The constraint is not table scope, but one default per set of rows, specified by a FormID.










share|improve this question
























  • Is the default mandatory? There must be a default for each FormID? Or could some IDs be without a default?

    – David Balažic
    Mar 18 '17 at 17:31











  • @DavidBalažic I can no longer remember.

    – ProfK
    Mar 19 '17 at 4:24











  • check out this one stackoverflow.com/questions/4810615/…

    – Joe B
    Aug 28 '17 at 13:19











  • Has anyone solved the problem of how to enforce having that one mandatory default (i.e. if any records exist, then there must be a default. If only one record exists, then it must be the one marked as default)?

    – DaveBoltman
    Aug 6 '18 at 16:52
















31















How could I set a constraint on a table so that only one of the records has its isDefault bit field set to 1?



The constraint is not table scope, but one default per set of rows, specified by a FormID.










share|improve this question
























  • Is the default mandatory? There must be a default for each FormID? Or could some IDs be without a default?

    – David Balažic
    Mar 18 '17 at 17:31











  • @DavidBalažic I can no longer remember.

    – ProfK
    Mar 19 '17 at 4:24











  • check out this one stackoverflow.com/questions/4810615/…

    – Joe B
    Aug 28 '17 at 13:19











  • Has anyone solved the problem of how to enforce having that one mandatory default (i.e. if any records exist, then there must be a default. If only one record exists, then it must be the one marked as default)?

    – DaveBoltman
    Aug 6 '18 at 16:52














31












31








31


6






How could I set a constraint on a table so that only one of the records has its isDefault bit field set to 1?



The constraint is not table scope, but one default per set of rows, specified by a FormID.










share|improve this question
















How could I set a constraint on a table so that only one of the records has its isDefault bit field set to 1?



The constraint is not table scope, but one default per set of rows, specified by a FormID.







sql sql-server






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Mar 12 '09 at 16:12







ProfK

















asked Mar 12 '09 at 9:41









ProfKProfK

14.6k85319631




14.6k85319631












  • Is the default mandatory? There must be a default for each FormID? Or could some IDs be without a default?

    – David Balažic
    Mar 18 '17 at 17:31











  • @DavidBalažic I can no longer remember.

    – ProfK
    Mar 19 '17 at 4:24











  • check out this one stackoverflow.com/questions/4810615/…

    – Joe B
    Aug 28 '17 at 13:19











  • Has anyone solved the problem of how to enforce having that one mandatory default (i.e. if any records exist, then there must be a default. If only one record exists, then it must be the one marked as default)?

    – DaveBoltman
    Aug 6 '18 at 16:52


















  • Is the default mandatory? There must be a default for each FormID? Or could some IDs be without a default?

    – David Balažic
    Mar 18 '17 at 17:31











  • @DavidBalažic I can no longer remember.

    – ProfK
    Mar 19 '17 at 4:24











  • check out this one stackoverflow.com/questions/4810615/…

    – Joe B
    Aug 28 '17 at 13:19











  • Has anyone solved the problem of how to enforce having that one mandatory default (i.e. if any records exist, then there must be a default. If only one record exists, then it must be the one marked as default)?

    – DaveBoltman
    Aug 6 '18 at 16:52

















Is the default mandatory? There must be a default for each FormID? Or could some IDs be without a default?

– David Balažic
Mar 18 '17 at 17:31





Is the default mandatory? There must be a default for each FormID? Or could some IDs be without a default?

– David Balažic
Mar 18 '17 at 17:31













@DavidBalažic I can no longer remember.

– ProfK
Mar 19 '17 at 4:24





@DavidBalažic I can no longer remember.

– ProfK
Mar 19 '17 at 4:24













check out this one stackoverflow.com/questions/4810615/…

– Joe B
Aug 28 '17 at 13:19





check out this one stackoverflow.com/questions/4810615/…

– Joe B
Aug 28 '17 at 13:19













Has anyone solved the problem of how to enforce having that one mandatory default (i.e. if any records exist, then there must be a default. If only one record exists, then it must be the one marked as default)?

– DaveBoltman
Aug 6 '18 at 16:52






Has anyone solved the problem of how to enforce having that one mandatory default (i.e. if any records exist, then there must be a default. If only one record exists, then it must be the one marked as default)?

– DaveBoltman
Aug 6 '18 at 16:52













10 Answers
10






active

oldest

votes


















9














Here's a modification of Damien_The_Unbeliever's solution that allows one default per FormID.



CREATE VIEW form_defaults
AS
SELECT FormID
FROM whatever
WHERE isDefault = 1
GO
CREATE UNIQUE CLUSTERED INDEX ix_form_defaults on form_defaults (FormID)
GO


But the serious relational folks will tell you this information should just be in another table.



CREATE TABLE form
FormID int NOT NULL PRIMARY KEY
DefaultWhateverID int FOREIGN KEY REFERENCES Whatever(ID)





share|improve this answer




















  • 7





    +1 for what "serious relational folks would do" answer.. I went from having a boolean to splitting it out into a separate table

    – Asfand Qazi
    May 5 '15 at 4:56











  • You can only create an index on a view that has WITH SCHEMABINDING.

    – DaveBoltman
    Aug 6 '18 at 15:14


















46














Use a unique filtered index



On SQL Server 2008 or higher you can simply use a unique filtered index



CREATE UNIQUE INDEX IX_TableName_FormID_isDefault
ON TableName(FormID)
WHERE isDefault = 1


Where the table is



CREATE TABLE TableName(
FormID INT NOT NULL,
isDefault BIT NOT NULL
)


For example if you try to insert many rows with the same FormId and isDefault set to 1 you will have this error:




Cannot insert duplicate key row in object 'dbo.TableName' with unique
index 'IX_TableName_FormID_isDefault'. The duplicate key value is (1).




Source: http://technet.microsoft.com/en-us/library/cc280372.aspx






share|improve this answer




















  • 2





    Filtered indexes require ANSI PADDING ON. So execute SET ANSI PADDING ON before creating a filtered index.

    – naXa
    May 11 '17 at 8:37



















8














From a normalization perspective, this would be an inefficient way of storing a single fact.



I would opt to hold this information at a higher level, by storing (in a different table) a foreign key to the identifier of the row which is considered to be the default.



CREATE TABLE [dbo].[Foo](
[Id] [int] NOT NULL,
CONSTRAINT [PK_Foo] PRIMARY KEY CLUSTERED
(
[Id] ASC
) ON [PRIMARY]
) ON [PRIMARY]

GO

CREATE TABLE [dbo].[DefaultSettings](
[DefaultFoo] [int] NULL
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[DefaultSettings] WITH CHECK ADD CONSTRAINT [FK_DefaultSettings_Foo] FOREIGN KEY([DefaultFoo])
REFERENCES [dbo].[Foo] ([Id])
GO

ALTER TABLE [dbo].[DefaultSettings] CHECK CONSTRAINT [FK_DefaultSettings_Foo]
GO





share|improve this answer

























  • This method will not ensure that only one row has isDefault = 1

    – Andy Jones
    Mar 12 '09 at 14:00











  • @Andy Jones, you're right, it won't. I wouldn't have an isDefault column at all. I'm suggesting an alternative solution.

    – Ian Nelson
    Mar 12 '09 at 14:03






  • 3





    Yes, but this alternative solution still allows for multiple defaults by inserting many rows into dbo.DefaultSettings. Could maybe add a trigger to dbo.DefaultSettings to only allow 1 row in there if you chose that method.

    – Andy Jones
    Mar 12 '09 at 14:12











  • @Andy Jones - true, good point.

    – Ian Nelson
    Mar 12 '09 at 14:29











  • @AndyJones In theory, it does allow more than one default. However - if you are using this table as a '1 row table that stores a setting or row of settings' - then you wouldn't ever be inserting rows into that table. I think this is a far clearer, simpler solution less prone to misunderstanding and errors later.

    – niico
    Nov 21 '16 at 16:09


















3














You could use an insert/update trigger.



Within the trigger after an insert or update, if the count of rows with isDefault = 1 is more than 1, then rollback the transaction.






share|improve this answer






























    2














    CREATE VIEW vOnlyOneDefault
    AS
    SELECT 1 as Lock
    FROM <underlying table>
    WHERE Default = 1
    GO
    CREATE UNIQUE CLUSTERED INDEX IX_vOnlyOneDefault on vOnlyOneDefault (Lock)
    GO


    You'll need to have the right ANSI settings turned on for this.






    share|improve this answer























    • This looks good, but complicated. I'd have to build the create view statement dynamically, as the default constraint isn't table wide, it's per FormID in the underlying table.

      – ProfK
      Mar 12 '09 at 16:02











    • When you have a complicated problem, you will need a complicated solution. This will not address all the other problems I mentioned about how you want to handle things as data changes.

      – HLGEM
      Mar 12 '09 at 18:21






    • 4





      Also remember to use WITH SCHEMABINDING when creating the view

      – kristof
      Mar 13 '09 at 10:57











    • This got my vote because it actually answers the original question. It also neatly solved a very similar problem I was having in a way that wasn't covered by any of the other answers.

      – Daniel Schealler
      May 15 '15 at 6:09


















    2














    I don't know about SQLServer.But if it supports Function-Based Indexes like in Oracle, I hope this can be translated, if not, sorry.



    You can do an index like this on suposed that default value is 1234, the column is DEFAULT_COLUMN and ID_COLUMN is the primary key:



    CREATE 
    UNIQUE
    INDEX only_one_default
    ON my_table
    ( DECODE(DEFAULT_COLUMN, 1234, -1, ID_COLUMN) )


    This DDL creates an unique index indexing -1 if the value of DEFAULT_COLUMN is 1234 and ID_COLUMN in any other case. Then, if two columns have DEFAULT_COLUMN value, it raises an exception.






    share|improve this answer
































      2














      The question implies to me that you have a primary table that has some child records and one of those child records will be the default record. Using address and a separate default table here is an example of how to make that happen using third normal form. Of course I don't know if it's valuable to answer something that is so old but it struck my fancy.



      --drop table dev.defaultAddress;
      --drop table dev.addresses;
      --drop table dev.people;

      CREATE TABLE [dev].[people](
      [Id] [int] identity primary key,
      name char(20)
      )
      GO

      CREATE TABLE [dev].[Addresses](
      id int identity primary key,
      peopleId int foreign key references dev.people(id),
      address varchar(100)
      ) ON [PRIMARY]

      GO
      CREATE TABLE [dev].[defaultAddress](
      id int identity primary key,
      peopleId int foreign key references dev.people(id),
      addressesId int foreign key references dev.addresses(id))
      go
      create unique index defaultAddress on dev.defaultAddress (peopleId)
      go
      create unique index idx_addr_id_person on dev.addresses(peopleid,id);
      go
      ALTER TABLE dev.defaultAddress
      ADD CONSTRAINT FK_Def_People_Address
      FOREIGN KEY(peopleID, addressesID)
      REFERENCES dev.Addresses(peopleId, id)
      go
      insert into dev.people (name)
      select 'Bill' union
      select 'John' union
      select 'Harry'
      insert into dev.Addresses (peopleid, address)
      select 1, '123 someplace' union
      select 1,'work place' union
      select 2,'home address' union
      select 3,'some address'
      insert into dev.defaultaddress (peopleId, addressesid)
      select 1,1 union
      select 2,3
      -- so two home addresses are default now
      -- try adding another default address to Bill and you get an error
      select * from dev.people
      join dev.addresses on people.id = addresses.peopleid
      left join dev.defaultAddress on defaultAddress.peopleid = people.id and defaultaddress.addressesid = addresses.id
      insert into dev.defaultaddress (peopleId, addressesId)
      select 1,2

      GO





      share|improve this answer

























      • What if you insert into defaultAddress an address that belongs to someone else? This won't catch it.

        – Kiran Jonnalagadda
        Aug 9 '17 at 6:34











      • How would it programmatically know that the address you entered wasn't the address of the person? If you are saying that the rule you need to enforce is no person can have the same default address as another person you can add the addressId to the unique address but that would assume no married couples/roommates/etc. in the database

        – billpennock
        Aug 10 '17 at 13:24











      • I meant database constraint. Addresses.peopleId links an address to a person. The same row clearly can't link to another person. Therefore defaultAddress needs to validate that the address marked as default for a given peopleId also has a matching peopleId. (I just implemented this in PostgreSQL and addressed it with a trigger validator.)

        – Kiran Jonnalagadda
        Aug 16 '17 at 10:53











      • Sorry it had been awhile since I answered this and I should have spent more time understanding your comment. It's a good catch. I had alot of trouble getting code in this comment, maybe it's not possible. Anyway I added a multi-column foreign key to the code above to answer the very excellent concern. I think this will do what you identified without a trigger.

        – billpennock
        Aug 17 '17 at 15:43


















      0














      You could do it through an instead of trigger, or if you want it as a constraint create a constraint that references a function that checks for a row that has the default set to 1



      EDIT oops, needs to be <=



      Create table mytable(id1 int, defaultX bit not null default(0))
      go

      create Function dbo.fx_DefaultExists()
      returns int as
      Begin
      Declare @Ret int
      Set @ret = 0
      Select @ret = count(1) from mytable
      Where defaultX = 1

      Return @ret
      End
      GO
      Alter table mytable add
      CONSTRAINT [CHK_DEFAULT_SET] CHECK
      (([dbo].fx_DefaultExists()<=(1)))
      GO
      Insert into mytable (id1, defaultX) values (1,1)

      Insert into mytable (id1, defaultX) values (2,1)





      share|improve this answer






























        0














        This is a fairly complex process that cannot be handled through a simple constraint.



        We do this through a trigger. However before you write the trigger you need to be able to answer several things:



        do we want to fail the insert if a default exists, change it to 0 instead of 1 or change the existing default to 0 and leave this one as 1?
        what do we want to do if the default record is deleted and other non default records are still there? Do we make one the default, if so how do we determine which one?



        You will also need to be very, very careful to make the trigger handle multiple row processing. For instance a client might decide that all of the records of a particular type should be the default. You wouldn't change a million records one at a time, so this trigger needs to be able to handle that. It also needs to handle that without looping or the use of a cursor (you really don't want the type of transaction discussed above to take hours locking up the table the whole time).



        You also need a very extensive tesing scenario for this trigger before it goes live. You need to test:
        adding a record with no default and it is the first record for that customer
        adding a record with a default and it is the first record for that customer
        adding a record with no default and it is the not the first record for that customer
        adding a record with a default and it is the not the first record for that customer
        Updating a record to have the default when no other record has it (assuming you don't require one record to always be set as the deafault)
        Updating a record to remove the default
        Deleting the record with the deafult
        Deleting a record without the default
        Performing a mass insert with multiple situations in the data including two records which both have isdefault set to 1 and all of the situations tested when running individual record inserts
        Performing a mass update with multiple situations in the data including two records which both have isdefault set to 1 and all of the situations tested when running individual record updates
        Performing a mass delete with multiple situations in the data including two records which both have isdefault set to 1 and all of the situations tested when running individual record deletes






        share|improve this answer






























          0














          @Andy Jones gave an answer above closest to mine, but bearing in mind the Rule of Three, I placed the logic directly in the stored proc that updates this table. This was my simple solution. If I need to update the table from elsewhere, I will move the logic to a trigger. The one default rule applies to each set of records specified by a FormID and a ConfigID:



          ALTER proc [dbo].[cpForm_UpdateLinkedReport]
          @reportLinkId int,
          @defaultYN bit,
          @linkName nvarchar(150)
          as
          if @defaultYN = 1
          begin
          declare @formId int, @configId int
          select @formId = FormID, @configId = ConfigID from csReportLink where ReportLinkID = @reportLinkId
          update csReportLink set DefaultYN = 0 where isnull(ConfigID, @configId) = @configId and FormID = @formId
          end
          update
          csReportLink
          set
          DefaultYN = @defaultYN,
          LinkName = @linkName
          where
          ReportLinkID = @reportLinkId





          share|improve this answer























          • ALways a bad idea to put required logic in a stored proc vice a trigger. You won't always know when you need to change to a trigger later because multiple applications are using this. You are creating a data integrity nightmare for some future person to fix.

            – HLGEM
            Mar 12 '09 at 18:24











          • I'm responsible for the single application area that maintains that table, and we release tomorrow, so not having to add to our SQL update script reduces risk. The update script for sp's is generated, other objects it's manual, with risk. I will schedule a trigger for next cycle, in 6 weeks time.

            – ProfK
            Mar 12 '09 at 18:34










          Your Answer






          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "1"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader:
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          ,
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );













          draft saved

          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f637894%2fconstraint-for-only-one-record-marked-as-default%23new-answer', 'question_page');

          );

          Post as a guest















          Required, but never shown

























          10 Answers
          10






          active

          oldest

          votes








          10 Answers
          10






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          9














          Here's a modification of Damien_The_Unbeliever's solution that allows one default per FormID.



          CREATE VIEW form_defaults
          AS
          SELECT FormID
          FROM whatever
          WHERE isDefault = 1
          GO
          CREATE UNIQUE CLUSTERED INDEX ix_form_defaults on form_defaults (FormID)
          GO


          But the serious relational folks will tell you this information should just be in another table.



          CREATE TABLE form
          FormID int NOT NULL PRIMARY KEY
          DefaultWhateverID int FOREIGN KEY REFERENCES Whatever(ID)





          share|improve this answer




















          • 7





            +1 for what "serious relational folks would do" answer.. I went from having a boolean to splitting it out into a separate table

            – Asfand Qazi
            May 5 '15 at 4:56











          • You can only create an index on a view that has WITH SCHEMABINDING.

            – DaveBoltman
            Aug 6 '18 at 15:14















          9














          Here's a modification of Damien_The_Unbeliever's solution that allows one default per FormID.



          CREATE VIEW form_defaults
          AS
          SELECT FormID
          FROM whatever
          WHERE isDefault = 1
          GO
          CREATE UNIQUE CLUSTERED INDEX ix_form_defaults on form_defaults (FormID)
          GO


          But the serious relational folks will tell you this information should just be in another table.



          CREATE TABLE form
          FormID int NOT NULL PRIMARY KEY
          DefaultWhateverID int FOREIGN KEY REFERENCES Whatever(ID)





          share|improve this answer




















          • 7





            +1 for what "serious relational folks would do" answer.. I went from having a boolean to splitting it out into a separate table

            – Asfand Qazi
            May 5 '15 at 4:56











          • You can only create an index on a view that has WITH SCHEMABINDING.

            – DaveBoltman
            Aug 6 '18 at 15:14













          9












          9








          9







          Here's a modification of Damien_The_Unbeliever's solution that allows one default per FormID.



          CREATE VIEW form_defaults
          AS
          SELECT FormID
          FROM whatever
          WHERE isDefault = 1
          GO
          CREATE UNIQUE CLUSTERED INDEX ix_form_defaults on form_defaults (FormID)
          GO


          But the serious relational folks will tell you this information should just be in another table.



          CREATE TABLE form
          FormID int NOT NULL PRIMARY KEY
          DefaultWhateverID int FOREIGN KEY REFERENCES Whatever(ID)





          share|improve this answer















          Here's a modification of Damien_The_Unbeliever's solution that allows one default per FormID.



          CREATE VIEW form_defaults
          AS
          SELECT FormID
          FROM whatever
          WHERE isDefault = 1
          GO
          CREATE UNIQUE CLUSTERED INDEX ix_form_defaults on form_defaults (FormID)
          GO


          But the serious relational folks will tell you this information should just be in another table.



          CREATE TABLE form
          FormID int NOT NULL PRIMARY KEY
          DefaultWhateverID int FOREIGN KEY REFERENCES Whatever(ID)






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Jun 3 '11 at 15:18









          Andriy M

          63.5k1378131




          63.5k1378131










          answered Mar 12 '09 at 22:18









          Tom FutureTom Future

          9222914




          9222914







          • 7





            +1 for what "serious relational folks would do" answer.. I went from having a boolean to splitting it out into a separate table

            – Asfand Qazi
            May 5 '15 at 4:56











          • You can only create an index on a view that has WITH SCHEMABINDING.

            – DaveBoltman
            Aug 6 '18 at 15:14












          • 7





            +1 for what "serious relational folks would do" answer.. I went from having a boolean to splitting it out into a separate table

            – Asfand Qazi
            May 5 '15 at 4:56











          • You can only create an index on a view that has WITH SCHEMABINDING.

            – DaveBoltman
            Aug 6 '18 at 15:14







          7




          7





          +1 for what "serious relational folks would do" answer.. I went from having a boolean to splitting it out into a separate table

          – Asfand Qazi
          May 5 '15 at 4:56





          +1 for what "serious relational folks would do" answer.. I went from having a boolean to splitting it out into a separate table

          – Asfand Qazi
          May 5 '15 at 4:56













          You can only create an index on a view that has WITH SCHEMABINDING.

          – DaveBoltman
          Aug 6 '18 at 15:14





          You can only create an index on a view that has WITH SCHEMABINDING.

          – DaveBoltman
          Aug 6 '18 at 15:14













          46














          Use a unique filtered index



          On SQL Server 2008 or higher you can simply use a unique filtered index



          CREATE UNIQUE INDEX IX_TableName_FormID_isDefault
          ON TableName(FormID)
          WHERE isDefault = 1


          Where the table is



          CREATE TABLE TableName(
          FormID INT NOT NULL,
          isDefault BIT NOT NULL
          )


          For example if you try to insert many rows with the same FormId and isDefault set to 1 you will have this error:




          Cannot insert duplicate key row in object 'dbo.TableName' with unique
          index 'IX_TableName_FormID_isDefault'. The duplicate key value is (1).




          Source: http://technet.microsoft.com/en-us/library/cc280372.aspx






          share|improve this answer




















          • 2





            Filtered indexes require ANSI PADDING ON. So execute SET ANSI PADDING ON before creating a filtered index.

            – naXa
            May 11 '17 at 8:37
















          46














          Use a unique filtered index



          On SQL Server 2008 or higher you can simply use a unique filtered index



          CREATE UNIQUE INDEX IX_TableName_FormID_isDefault
          ON TableName(FormID)
          WHERE isDefault = 1


          Where the table is



          CREATE TABLE TableName(
          FormID INT NOT NULL,
          isDefault BIT NOT NULL
          )


          For example if you try to insert many rows with the same FormId and isDefault set to 1 you will have this error:




          Cannot insert duplicate key row in object 'dbo.TableName' with unique
          index 'IX_TableName_FormID_isDefault'. The duplicate key value is (1).




          Source: http://technet.microsoft.com/en-us/library/cc280372.aspx






          share|improve this answer




















          • 2





            Filtered indexes require ANSI PADDING ON. So execute SET ANSI PADDING ON before creating a filtered index.

            – naXa
            May 11 '17 at 8:37














          46












          46








          46







          Use a unique filtered index



          On SQL Server 2008 or higher you can simply use a unique filtered index



          CREATE UNIQUE INDEX IX_TableName_FormID_isDefault
          ON TableName(FormID)
          WHERE isDefault = 1


          Where the table is



          CREATE TABLE TableName(
          FormID INT NOT NULL,
          isDefault BIT NOT NULL
          )


          For example if you try to insert many rows with the same FormId and isDefault set to 1 you will have this error:




          Cannot insert duplicate key row in object 'dbo.TableName' with unique
          index 'IX_TableName_FormID_isDefault'. The duplicate key value is (1).




          Source: http://technet.microsoft.com/en-us/library/cc280372.aspx






          share|improve this answer















          Use a unique filtered index



          On SQL Server 2008 or higher you can simply use a unique filtered index



          CREATE UNIQUE INDEX IX_TableName_FormID_isDefault
          ON TableName(FormID)
          WHERE isDefault = 1


          Where the table is



          CREATE TABLE TableName(
          FormID INT NOT NULL,
          isDefault BIT NOT NULL
          )


          For example if you try to insert many rows with the same FormId and isDefault set to 1 you will have this error:




          Cannot insert duplicate key row in object 'dbo.TableName' with unique
          index 'IX_TableName_FormID_isDefault'. The duplicate key value is (1).




          Source: http://technet.microsoft.com/en-us/library/cc280372.aspx







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Apr 29 '14 at 21:46

























          answered Apr 3 '13 at 0:17









          Yves M.Yves M.

          18.7k127199




          18.7k127199







          • 2





            Filtered indexes require ANSI PADDING ON. So execute SET ANSI PADDING ON before creating a filtered index.

            – naXa
            May 11 '17 at 8:37













          • 2





            Filtered indexes require ANSI PADDING ON. So execute SET ANSI PADDING ON before creating a filtered index.

            – naXa
            May 11 '17 at 8:37








          2




          2





          Filtered indexes require ANSI PADDING ON. So execute SET ANSI PADDING ON before creating a filtered index.

          – naXa
          May 11 '17 at 8:37






          Filtered indexes require ANSI PADDING ON. So execute SET ANSI PADDING ON before creating a filtered index.

          – naXa
          May 11 '17 at 8:37












          8














          From a normalization perspective, this would be an inefficient way of storing a single fact.



          I would opt to hold this information at a higher level, by storing (in a different table) a foreign key to the identifier of the row which is considered to be the default.



          CREATE TABLE [dbo].[Foo](
          [Id] [int] NOT NULL,
          CONSTRAINT [PK_Foo] PRIMARY KEY CLUSTERED
          (
          [Id] ASC
          ) ON [PRIMARY]
          ) ON [PRIMARY]

          GO

          CREATE TABLE [dbo].[DefaultSettings](
          [DefaultFoo] [int] NULL
          ) ON [PRIMARY]

          GO

          ALTER TABLE [dbo].[DefaultSettings] WITH CHECK ADD CONSTRAINT [FK_DefaultSettings_Foo] FOREIGN KEY([DefaultFoo])
          REFERENCES [dbo].[Foo] ([Id])
          GO

          ALTER TABLE [dbo].[DefaultSettings] CHECK CONSTRAINT [FK_DefaultSettings_Foo]
          GO





          share|improve this answer

























          • This method will not ensure that only one row has isDefault = 1

            – Andy Jones
            Mar 12 '09 at 14:00











          • @Andy Jones, you're right, it won't. I wouldn't have an isDefault column at all. I'm suggesting an alternative solution.

            – Ian Nelson
            Mar 12 '09 at 14:03






          • 3





            Yes, but this alternative solution still allows for multiple defaults by inserting many rows into dbo.DefaultSettings. Could maybe add a trigger to dbo.DefaultSettings to only allow 1 row in there if you chose that method.

            – Andy Jones
            Mar 12 '09 at 14:12











          • @Andy Jones - true, good point.

            – Ian Nelson
            Mar 12 '09 at 14:29











          • @AndyJones In theory, it does allow more than one default. However - if you are using this table as a '1 row table that stores a setting or row of settings' - then you wouldn't ever be inserting rows into that table. I think this is a far clearer, simpler solution less prone to misunderstanding and errors later.

            – niico
            Nov 21 '16 at 16:09















          8














          From a normalization perspective, this would be an inefficient way of storing a single fact.



          I would opt to hold this information at a higher level, by storing (in a different table) a foreign key to the identifier of the row which is considered to be the default.



          CREATE TABLE [dbo].[Foo](
          [Id] [int] NOT NULL,
          CONSTRAINT [PK_Foo] PRIMARY KEY CLUSTERED
          (
          [Id] ASC
          ) ON [PRIMARY]
          ) ON [PRIMARY]

          GO

          CREATE TABLE [dbo].[DefaultSettings](
          [DefaultFoo] [int] NULL
          ) ON [PRIMARY]

          GO

          ALTER TABLE [dbo].[DefaultSettings] WITH CHECK ADD CONSTRAINT [FK_DefaultSettings_Foo] FOREIGN KEY([DefaultFoo])
          REFERENCES [dbo].[Foo] ([Id])
          GO

          ALTER TABLE [dbo].[DefaultSettings] CHECK CONSTRAINT [FK_DefaultSettings_Foo]
          GO





          share|improve this answer

























          • This method will not ensure that only one row has isDefault = 1

            – Andy Jones
            Mar 12 '09 at 14:00











          • @Andy Jones, you're right, it won't. I wouldn't have an isDefault column at all. I'm suggesting an alternative solution.

            – Ian Nelson
            Mar 12 '09 at 14:03






          • 3





            Yes, but this alternative solution still allows for multiple defaults by inserting many rows into dbo.DefaultSettings. Could maybe add a trigger to dbo.DefaultSettings to only allow 1 row in there if you chose that method.

            – Andy Jones
            Mar 12 '09 at 14:12











          • @Andy Jones - true, good point.

            – Ian Nelson
            Mar 12 '09 at 14:29











          • @AndyJones In theory, it does allow more than one default. However - if you are using this table as a '1 row table that stores a setting or row of settings' - then you wouldn't ever be inserting rows into that table. I think this is a far clearer, simpler solution less prone to misunderstanding and errors later.

            – niico
            Nov 21 '16 at 16:09













          8












          8








          8







          From a normalization perspective, this would be an inefficient way of storing a single fact.



          I would opt to hold this information at a higher level, by storing (in a different table) a foreign key to the identifier of the row which is considered to be the default.



          CREATE TABLE [dbo].[Foo](
          [Id] [int] NOT NULL,
          CONSTRAINT [PK_Foo] PRIMARY KEY CLUSTERED
          (
          [Id] ASC
          ) ON [PRIMARY]
          ) ON [PRIMARY]

          GO

          CREATE TABLE [dbo].[DefaultSettings](
          [DefaultFoo] [int] NULL
          ) ON [PRIMARY]

          GO

          ALTER TABLE [dbo].[DefaultSettings] WITH CHECK ADD CONSTRAINT [FK_DefaultSettings_Foo] FOREIGN KEY([DefaultFoo])
          REFERENCES [dbo].[Foo] ([Id])
          GO

          ALTER TABLE [dbo].[DefaultSettings] CHECK CONSTRAINT [FK_DefaultSettings_Foo]
          GO





          share|improve this answer















          From a normalization perspective, this would be an inefficient way of storing a single fact.



          I would opt to hold this information at a higher level, by storing (in a different table) a foreign key to the identifier of the row which is considered to be the default.



          CREATE TABLE [dbo].[Foo](
          [Id] [int] NOT NULL,
          CONSTRAINT [PK_Foo] PRIMARY KEY CLUSTERED
          (
          [Id] ASC
          ) ON [PRIMARY]
          ) ON [PRIMARY]

          GO

          CREATE TABLE [dbo].[DefaultSettings](
          [DefaultFoo] [int] NULL
          ) ON [PRIMARY]

          GO

          ALTER TABLE [dbo].[DefaultSettings] WITH CHECK ADD CONSTRAINT [FK_DefaultSettings_Foo] FOREIGN KEY([DefaultFoo])
          REFERENCES [dbo].[Foo] ([Id])
          GO

          ALTER TABLE [dbo].[DefaultSettings] CHECK CONSTRAINT [FK_DefaultSettings_Foo]
          GO






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Mar 12 '09 at 11:29

























          answered Mar 12 '09 at 9:53









          Ian NelsonIan Nelson

          35.4k196699




          35.4k196699












          • This method will not ensure that only one row has isDefault = 1

            – Andy Jones
            Mar 12 '09 at 14:00











          • @Andy Jones, you're right, it won't. I wouldn't have an isDefault column at all. I'm suggesting an alternative solution.

            – Ian Nelson
            Mar 12 '09 at 14:03






          • 3





            Yes, but this alternative solution still allows for multiple defaults by inserting many rows into dbo.DefaultSettings. Could maybe add a trigger to dbo.DefaultSettings to only allow 1 row in there if you chose that method.

            – Andy Jones
            Mar 12 '09 at 14:12











          • @Andy Jones - true, good point.

            – Ian Nelson
            Mar 12 '09 at 14:29











          • @AndyJones In theory, it does allow more than one default. However - if you are using this table as a '1 row table that stores a setting or row of settings' - then you wouldn't ever be inserting rows into that table. I think this is a far clearer, simpler solution less prone to misunderstanding and errors later.

            – niico
            Nov 21 '16 at 16:09

















          • This method will not ensure that only one row has isDefault = 1

            – Andy Jones
            Mar 12 '09 at 14:00











          • @Andy Jones, you're right, it won't. I wouldn't have an isDefault column at all. I'm suggesting an alternative solution.

            – Ian Nelson
            Mar 12 '09 at 14:03






          • 3





            Yes, but this alternative solution still allows for multiple defaults by inserting many rows into dbo.DefaultSettings. Could maybe add a trigger to dbo.DefaultSettings to only allow 1 row in there if you chose that method.

            – Andy Jones
            Mar 12 '09 at 14:12











          • @Andy Jones - true, good point.

            – Ian Nelson
            Mar 12 '09 at 14:29











          • @AndyJones In theory, it does allow more than one default. However - if you are using this table as a '1 row table that stores a setting or row of settings' - then you wouldn't ever be inserting rows into that table. I think this is a far clearer, simpler solution less prone to misunderstanding and errors later.

            – niico
            Nov 21 '16 at 16:09
















          This method will not ensure that only one row has isDefault = 1

          – Andy Jones
          Mar 12 '09 at 14:00





          This method will not ensure that only one row has isDefault = 1

          – Andy Jones
          Mar 12 '09 at 14:00













          @Andy Jones, you're right, it won't. I wouldn't have an isDefault column at all. I'm suggesting an alternative solution.

          – Ian Nelson
          Mar 12 '09 at 14:03





          @Andy Jones, you're right, it won't. I wouldn't have an isDefault column at all. I'm suggesting an alternative solution.

          – Ian Nelson
          Mar 12 '09 at 14:03




          3




          3





          Yes, but this alternative solution still allows for multiple defaults by inserting many rows into dbo.DefaultSettings. Could maybe add a trigger to dbo.DefaultSettings to only allow 1 row in there if you chose that method.

          – Andy Jones
          Mar 12 '09 at 14:12





          Yes, but this alternative solution still allows for multiple defaults by inserting many rows into dbo.DefaultSettings. Could maybe add a trigger to dbo.DefaultSettings to only allow 1 row in there if you chose that method.

          – Andy Jones
          Mar 12 '09 at 14:12













          @Andy Jones - true, good point.

          – Ian Nelson
          Mar 12 '09 at 14:29





          @Andy Jones - true, good point.

          – Ian Nelson
          Mar 12 '09 at 14:29













          @AndyJones In theory, it does allow more than one default. However - if you are using this table as a '1 row table that stores a setting or row of settings' - then you wouldn't ever be inserting rows into that table. I think this is a far clearer, simpler solution less prone to misunderstanding and errors later.

          – niico
          Nov 21 '16 at 16:09





          @AndyJones In theory, it does allow more than one default. However - if you are using this table as a '1 row table that stores a setting or row of settings' - then you wouldn't ever be inserting rows into that table. I think this is a far clearer, simpler solution less prone to misunderstanding and errors later.

          – niico
          Nov 21 '16 at 16:09











          3














          You could use an insert/update trigger.



          Within the trigger after an insert or update, if the count of rows with isDefault = 1 is more than 1, then rollback the transaction.






          share|improve this answer



























            3














            You could use an insert/update trigger.



            Within the trigger after an insert or update, if the count of rows with isDefault = 1 is more than 1, then rollback the transaction.






            share|improve this answer

























              3












              3








              3







              You could use an insert/update trigger.



              Within the trigger after an insert or update, if the count of rows with isDefault = 1 is more than 1, then rollback the transaction.






              share|improve this answer













              You could use an insert/update trigger.



              Within the trigger after an insert or update, if the count of rows with isDefault = 1 is more than 1, then rollback the transaction.







              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered Mar 12 '09 at 9:54









              Andy JonesAndy Jones

              1,265813




              1,265813





















                  2














                  CREATE VIEW vOnlyOneDefault
                  AS
                  SELECT 1 as Lock
                  FROM <underlying table>
                  WHERE Default = 1
                  GO
                  CREATE UNIQUE CLUSTERED INDEX IX_vOnlyOneDefault on vOnlyOneDefault (Lock)
                  GO


                  You'll need to have the right ANSI settings turned on for this.






                  share|improve this answer























                  • This looks good, but complicated. I'd have to build the create view statement dynamically, as the default constraint isn't table wide, it's per FormID in the underlying table.

                    – ProfK
                    Mar 12 '09 at 16:02











                  • When you have a complicated problem, you will need a complicated solution. This will not address all the other problems I mentioned about how you want to handle things as data changes.

                    – HLGEM
                    Mar 12 '09 at 18:21






                  • 4





                    Also remember to use WITH SCHEMABINDING when creating the view

                    – kristof
                    Mar 13 '09 at 10:57











                  • This got my vote because it actually answers the original question. It also neatly solved a very similar problem I was having in a way that wasn't covered by any of the other answers.

                    – Daniel Schealler
                    May 15 '15 at 6:09















                  2














                  CREATE VIEW vOnlyOneDefault
                  AS
                  SELECT 1 as Lock
                  FROM <underlying table>
                  WHERE Default = 1
                  GO
                  CREATE UNIQUE CLUSTERED INDEX IX_vOnlyOneDefault on vOnlyOneDefault (Lock)
                  GO


                  You'll need to have the right ANSI settings turned on for this.






                  share|improve this answer























                  • This looks good, but complicated. I'd have to build the create view statement dynamically, as the default constraint isn't table wide, it's per FormID in the underlying table.

                    – ProfK
                    Mar 12 '09 at 16:02











                  • When you have a complicated problem, you will need a complicated solution. This will not address all the other problems I mentioned about how you want to handle things as data changes.

                    – HLGEM
                    Mar 12 '09 at 18:21






                  • 4





                    Also remember to use WITH SCHEMABINDING when creating the view

                    – kristof
                    Mar 13 '09 at 10:57











                  • This got my vote because it actually answers the original question. It also neatly solved a very similar problem I was having in a way that wasn't covered by any of the other answers.

                    – Daniel Schealler
                    May 15 '15 at 6:09













                  2












                  2








                  2







                  CREATE VIEW vOnlyOneDefault
                  AS
                  SELECT 1 as Lock
                  FROM <underlying table>
                  WHERE Default = 1
                  GO
                  CREATE UNIQUE CLUSTERED INDEX IX_vOnlyOneDefault on vOnlyOneDefault (Lock)
                  GO


                  You'll need to have the right ANSI settings turned on for this.






                  share|improve this answer













                  CREATE VIEW vOnlyOneDefault
                  AS
                  SELECT 1 as Lock
                  FROM <underlying table>
                  WHERE Default = 1
                  GO
                  CREATE UNIQUE CLUSTERED INDEX IX_vOnlyOneDefault on vOnlyOneDefault (Lock)
                  GO


                  You'll need to have the right ANSI settings turned on for this.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Mar 12 '09 at 15:22









                  Damien_The_UnbelieverDamien_The_Unbeliever

                  195k17252338




                  195k17252338












                  • This looks good, but complicated. I'd have to build the create view statement dynamically, as the default constraint isn't table wide, it's per FormID in the underlying table.

                    – ProfK
                    Mar 12 '09 at 16:02











                  • When you have a complicated problem, you will need a complicated solution. This will not address all the other problems I mentioned about how you want to handle things as data changes.

                    – HLGEM
                    Mar 12 '09 at 18:21






                  • 4





                    Also remember to use WITH SCHEMABINDING when creating the view

                    – kristof
                    Mar 13 '09 at 10:57











                  • This got my vote because it actually answers the original question. It also neatly solved a very similar problem I was having in a way that wasn't covered by any of the other answers.

                    – Daniel Schealler
                    May 15 '15 at 6:09

















                  • This looks good, but complicated. I'd have to build the create view statement dynamically, as the default constraint isn't table wide, it's per FormID in the underlying table.

                    – ProfK
                    Mar 12 '09 at 16:02











                  • When you have a complicated problem, you will need a complicated solution. This will not address all the other problems I mentioned about how you want to handle things as data changes.

                    – HLGEM
                    Mar 12 '09 at 18:21






                  • 4





                    Also remember to use WITH SCHEMABINDING when creating the view

                    – kristof
                    Mar 13 '09 at 10:57











                  • This got my vote because it actually answers the original question. It also neatly solved a very similar problem I was having in a way that wasn't covered by any of the other answers.

                    – Daniel Schealler
                    May 15 '15 at 6:09
















                  This looks good, but complicated. I'd have to build the create view statement dynamically, as the default constraint isn't table wide, it's per FormID in the underlying table.

                  – ProfK
                  Mar 12 '09 at 16:02





                  This looks good, but complicated. I'd have to build the create view statement dynamically, as the default constraint isn't table wide, it's per FormID in the underlying table.

                  – ProfK
                  Mar 12 '09 at 16:02













                  When you have a complicated problem, you will need a complicated solution. This will not address all the other problems I mentioned about how you want to handle things as data changes.

                  – HLGEM
                  Mar 12 '09 at 18:21





                  When you have a complicated problem, you will need a complicated solution. This will not address all the other problems I mentioned about how you want to handle things as data changes.

                  – HLGEM
                  Mar 12 '09 at 18:21




                  4




                  4





                  Also remember to use WITH SCHEMABINDING when creating the view

                  – kristof
                  Mar 13 '09 at 10:57





                  Also remember to use WITH SCHEMABINDING when creating the view

                  – kristof
                  Mar 13 '09 at 10:57













                  This got my vote because it actually answers the original question. It also neatly solved a very similar problem I was having in a way that wasn't covered by any of the other answers.

                  – Daniel Schealler
                  May 15 '15 at 6:09





                  This got my vote because it actually answers the original question. It also neatly solved a very similar problem I was having in a way that wasn't covered by any of the other answers.

                  – Daniel Schealler
                  May 15 '15 at 6:09











                  2














                  I don't know about SQLServer.But if it supports Function-Based Indexes like in Oracle, I hope this can be translated, if not, sorry.



                  You can do an index like this on suposed that default value is 1234, the column is DEFAULT_COLUMN and ID_COLUMN is the primary key:



                  CREATE 
                  UNIQUE
                  INDEX only_one_default
                  ON my_table
                  ( DECODE(DEFAULT_COLUMN, 1234, -1, ID_COLUMN) )


                  This DDL creates an unique index indexing -1 if the value of DEFAULT_COLUMN is 1234 and ID_COLUMN in any other case. Then, if two columns have DEFAULT_COLUMN value, it raises an exception.






                  share|improve this answer





























                    2














                    I don't know about SQLServer.But if it supports Function-Based Indexes like in Oracle, I hope this can be translated, if not, sorry.



                    You can do an index like this on suposed that default value is 1234, the column is DEFAULT_COLUMN and ID_COLUMN is the primary key:



                    CREATE 
                    UNIQUE
                    INDEX only_one_default
                    ON my_table
                    ( DECODE(DEFAULT_COLUMN, 1234, -1, ID_COLUMN) )


                    This DDL creates an unique index indexing -1 if the value of DEFAULT_COLUMN is 1234 and ID_COLUMN in any other case. Then, if two columns have DEFAULT_COLUMN value, it raises an exception.






                    share|improve this answer



























                      2












                      2








                      2







                      I don't know about SQLServer.But if it supports Function-Based Indexes like in Oracle, I hope this can be translated, if not, sorry.



                      You can do an index like this on suposed that default value is 1234, the column is DEFAULT_COLUMN and ID_COLUMN is the primary key:



                      CREATE 
                      UNIQUE
                      INDEX only_one_default
                      ON my_table
                      ( DECODE(DEFAULT_COLUMN, 1234, -1, ID_COLUMN) )


                      This DDL creates an unique index indexing -1 if the value of DEFAULT_COLUMN is 1234 and ID_COLUMN in any other case. Then, if two columns have DEFAULT_COLUMN value, it raises an exception.






                      share|improve this answer















                      I don't know about SQLServer.But if it supports Function-Based Indexes like in Oracle, I hope this can be translated, if not, sorry.



                      You can do an index like this on suposed that default value is 1234, the column is DEFAULT_COLUMN and ID_COLUMN is the primary key:



                      CREATE 
                      UNIQUE
                      INDEX only_one_default
                      ON my_table
                      ( DECODE(DEFAULT_COLUMN, 1234, -1, ID_COLUMN) )


                      This DDL creates an unique index indexing -1 if the value of DEFAULT_COLUMN is 1234 and ID_COLUMN in any other case. Then, if two columns have DEFAULT_COLUMN value, it raises an exception.







                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited Jan 28 '13 at 9:15









                      Mridang Agarwalla

                      17.1k54172323




                      17.1k54172323










                      answered Mar 12 '09 at 11:34









                      FerranBFerranB

                      20.3k175880




                      20.3k175880





















                          2














                          The question implies to me that you have a primary table that has some child records and one of those child records will be the default record. Using address and a separate default table here is an example of how to make that happen using third normal form. Of course I don't know if it's valuable to answer something that is so old but it struck my fancy.



                          --drop table dev.defaultAddress;
                          --drop table dev.addresses;
                          --drop table dev.people;

                          CREATE TABLE [dev].[people](
                          [Id] [int] identity primary key,
                          name char(20)
                          )
                          GO

                          CREATE TABLE [dev].[Addresses](
                          id int identity primary key,
                          peopleId int foreign key references dev.people(id),
                          address varchar(100)
                          ) ON [PRIMARY]

                          GO
                          CREATE TABLE [dev].[defaultAddress](
                          id int identity primary key,
                          peopleId int foreign key references dev.people(id),
                          addressesId int foreign key references dev.addresses(id))
                          go
                          create unique index defaultAddress on dev.defaultAddress (peopleId)
                          go
                          create unique index idx_addr_id_person on dev.addresses(peopleid,id);
                          go
                          ALTER TABLE dev.defaultAddress
                          ADD CONSTRAINT FK_Def_People_Address
                          FOREIGN KEY(peopleID, addressesID)
                          REFERENCES dev.Addresses(peopleId, id)
                          go
                          insert into dev.people (name)
                          select 'Bill' union
                          select 'John' union
                          select 'Harry'
                          insert into dev.Addresses (peopleid, address)
                          select 1, '123 someplace' union
                          select 1,'work place' union
                          select 2,'home address' union
                          select 3,'some address'
                          insert into dev.defaultaddress (peopleId, addressesid)
                          select 1,1 union
                          select 2,3
                          -- so two home addresses are default now
                          -- try adding another default address to Bill and you get an error
                          select * from dev.people
                          join dev.addresses on people.id = addresses.peopleid
                          left join dev.defaultAddress on defaultAddress.peopleid = people.id and defaultaddress.addressesid = addresses.id
                          insert into dev.defaultaddress (peopleId, addressesId)
                          select 1,2

                          GO





                          share|improve this answer

























                          • What if you insert into defaultAddress an address that belongs to someone else? This won't catch it.

                            – Kiran Jonnalagadda
                            Aug 9 '17 at 6:34











                          • How would it programmatically know that the address you entered wasn't the address of the person? If you are saying that the rule you need to enforce is no person can have the same default address as another person you can add the addressId to the unique address but that would assume no married couples/roommates/etc. in the database

                            – billpennock
                            Aug 10 '17 at 13:24











                          • I meant database constraint. Addresses.peopleId links an address to a person. The same row clearly can't link to another person. Therefore defaultAddress needs to validate that the address marked as default for a given peopleId also has a matching peopleId. (I just implemented this in PostgreSQL and addressed it with a trigger validator.)

                            – Kiran Jonnalagadda
                            Aug 16 '17 at 10:53











                          • Sorry it had been awhile since I answered this and I should have spent more time understanding your comment. It's a good catch. I had alot of trouble getting code in this comment, maybe it's not possible. Anyway I added a multi-column foreign key to the code above to answer the very excellent concern. I think this will do what you identified without a trigger.

                            – billpennock
                            Aug 17 '17 at 15:43















                          2














                          The question implies to me that you have a primary table that has some child records and one of those child records will be the default record. Using address and a separate default table here is an example of how to make that happen using third normal form. Of course I don't know if it's valuable to answer something that is so old but it struck my fancy.



                          --drop table dev.defaultAddress;
                          --drop table dev.addresses;
                          --drop table dev.people;

                          CREATE TABLE [dev].[people](
                          [Id] [int] identity primary key,
                          name char(20)
                          )
                          GO

                          CREATE TABLE [dev].[Addresses](
                          id int identity primary key,
                          peopleId int foreign key references dev.people(id),
                          address varchar(100)
                          ) ON [PRIMARY]

                          GO
                          CREATE TABLE [dev].[defaultAddress](
                          id int identity primary key,
                          peopleId int foreign key references dev.people(id),
                          addressesId int foreign key references dev.addresses(id))
                          go
                          create unique index defaultAddress on dev.defaultAddress (peopleId)
                          go
                          create unique index idx_addr_id_person on dev.addresses(peopleid,id);
                          go
                          ALTER TABLE dev.defaultAddress
                          ADD CONSTRAINT FK_Def_People_Address
                          FOREIGN KEY(peopleID, addressesID)
                          REFERENCES dev.Addresses(peopleId, id)
                          go
                          insert into dev.people (name)
                          select 'Bill' union
                          select 'John' union
                          select 'Harry'
                          insert into dev.Addresses (peopleid, address)
                          select 1, '123 someplace' union
                          select 1,'work place' union
                          select 2,'home address' union
                          select 3,'some address'
                          insert into dev.defaultaddress (peopleId, addressesid)
                          select 1,1 union
                          select 2,3
                          -- so two home addresses are default now
                          -- try adding another default address to Bill and you get an error
                          select * from dev.people
                          join dev.addresses on people.id = addresses.peopleid
                          left join dev.defaultAddress on defaultAddress.peopleid = people.id and defaultaddress.addressesid = addresses.id
                          insert into dev.defaultaddress (peopleId, addressesId)
                          select 1,2

                          GO





                          share|improve this answer

























                          • What if you insert into defaultAddress an address that belongs to someone else? This won't catch it.

                            – Kiran Jonnalagadda
                            Aug 9 '17 at 6:34











                          • How would it programmatically know that the address you entered wasn't the address of the person? If you are saying that the rule you need to enforce is no person can have the same default address as another person you can add the addressId to the unique address but that would assume no married couples/roommates/etc. in the database

                            – billpennock
                            Aug 10 '17 at 13:24











                          • I meant database constraint. Addresses.peopleId links an address to a person. The same row clearly can't link to another person. Therefore defaultAddress needs to validate that the address marked as default for a given peopleId also has a matching peopleId. (I just implemented this in PostgreSQL and addressed it with a trigger validator.)

                            – Kiran Jonnalagadda
                            Aug 16 '17 at 10:53











                          • Sorry it had been awhile since I answered this and I should have spent more time understanding your comment. It's a good catch. I had alot of trouble getting code in this comment, maybe it's not possible. Anyway I added a multi-column foreign key to the code above to answer the very excellent concern. I think this will do what you identified without a trigger.

                            – billpennock
                            Aug 17 '17 at 15:43













                          2












                          2








                          2







                          The question implies to me that you have a primary table that has some child records and one of those child records will be the default record. Using address and a separate default table here is an example of how to make that happen using third normal form. Of course I don't know if it's valuable to answer something that is so old but it struck my fancy.



                          --drop table dev.defaultAddress;
                          --drop table dev.addresses;
                          --drop table dev.people;

                          CREATE TABLE [dev].[people](
                          [Id] [int] identity primary key,
                          name char(20)
                          )
                          GO

                          CREATE TABLE [dev].[Addresses](
                          id int identity primary key,
                          peopleId int foreign key references dev.people(id),
                          address varchar(100)
                          ) ON [PRIMARY]

                          GO
                          CREATE TABLE [dev].[defaultAddress](
                          id int identity primary key,
                          peopleId int foreign key references dev.people(id),
                          addressesId int foreign key references dev.addresses(id))
                          go
                          create unique index defaultAddress on dev.defaultAddress (peopleId)
                          go
                          create unique index idx_addr_id_person on dev.addresses(peopleid,id);
                          go
                          ALTER TABLE dev.defaultAddress
                          ADD CONSTRAINT FK_Def_People_Address
                          FOREIGN KEY(peopleID, addressesID)
                          REFERENCES dev.Addresses(peopleId, id)
                          go
                          insert into dev.people (name)
                          select 'Bill' union
                          select 'John' union
                          select 'Harry'
                          insert into dev.Addresses (peopleid, address)
                          select 1, '123 someplace' union
                          select 1,'work place' union
                          select 2,'home address' union
                          select 3,'some address'
                          insert into dev.defaultaddress (peopleId, addressesid)
                          select 1,1 union
                          select 2,3
                          -- so two home addresses are default now
                          -- try adding another default address to Bill and you get an error
                          select * from dev.people
                          join dev.addresses on people.id = addresses.peopleid
                          left join dev.defaultAddress on defaultAddress.peopleid = people.id and defaultaddress.addressesid = addresses.id
                          insert into dev.defaultaddress (peopleId, addressesId)
                          select 1,2

                          GO





                          share|improve this answer















                          The question implies to me that you have a primary table that has some child records and one of those child records will be the default record. Using address and a separate default table here is an example of how to make that happen using third normal form. Of course I don't know if it's valuable to answer something that is so old but it struck my fancy.



                          --drop table dev.defaultAddress;
                          --drop table dev.addresses;
                          --drop table dev.people;

                          CREATE TABLE [dev].[people](
                          [Id] [int] identity primary key,
                          name char(20)
                          )
                          GO

                          CREATE TABLE [dev].[Addresses](
                          id int identity primary key,
                          peopleId int foreign key references dev.people(id),
                          address varchar(100)
                          ) ON [PRIMARY]

                          GO
                          CREATE TABLE [dev].[defaultAddress](
                          id int identity primary key,
                          peopleId int foreign key references dev.people(id),
                          addressesId int foreign key references dev.addresses(id))
                          go
                          create unique index defaultAddress on dev.defaultAddress (peopleId)
                          go
                          create unique index idx_addr_id_person on dev.addresses(peopleid,id);
                          go
                          ALTER TABLE dev.defaultAddress
                          ADD CONSTRAINT FK_Def_People_Address
                          FOREIGN KEY(peopleID, addressesID)
                          REFERENCES dev.Addresses(peopleId, id)
                          go
                          insert into dev.people (name)
                          select 'Bill' union
                          select 'John' union
                          select 'Harry'
                          insert into dev.Addresses (peopleid, address)
                          select 1, '123 someplace' union
                          select 1,'work place' union
                          select 2,'home address' union
                          select 3,'some address'
                          insert into dev.defaultaddress (peopleId, addressesid)
                          select 1,1 union
                          select 2,3
                          -- so two home addresses are default now
                          -- try adding another default address to Bill and you get an error
                          select * from dev.people
                          join dev.addresses on people.id = addresses.peopleid
                          left join dev.defaultAddress on defaultAddress.peopleid = people.id and defaultaddress.addressesid = addresses.id
                          insert into dev.defaultaddress (peopleId, addressesId)
                          select 1,2

                          GO






                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited Aug 17 '17 at 15:41

























                          answered Jul 30 '16 at 0:46









                          billpennockbillpennock

                          149111




                          149111












                          • What if you insert into defaultAddress an address that belongs to someone else? This won't catch it.

                            – Kiran Jonnalagadda
                            Aug 9 '17 at 6:34











                          • How would it programmatically know that the address you entered wasn't the address of the person? If you are saying that the rule you need to enforce is no person can have the same default address as another person you can add the addressId to the unique address but that would assume no married couples/roommates/etc. in the database

                            – billpennock
                            Aug 10 '17 at 13:24











                          • I meant database constraint. Addresses.peopleId links an address to a person. The same row clearly can't link to another person. Therefore defaultAddress needs to validate that the address marked as default for a given peopleId also has a matching peopleId. (I just implemented this in PostgreSQL and addressed it with a trigger validator.)

                            – Kiran Jonnalagadda
                            Aug 16 '17 at 10:53











                          • Sorry it had been awhile since I answered this and I should have spent more time understanding your comment. It's a good catch. I had alot of trouble getting code in this comment, maybe it's not possible. Anyway I added a multi-column foreign key to the code above to answer the very excellent concern. I think this will do what you identified without a trigger.

                            – billpennock
                            Aug 17 '17 at 15:43

















                          • What if you insert into defaultAddress an address that belongs to someone else? This won't catch it.

                            – Kiran Jonnalagadda
                            Aug 9 '17 at 6:34











                          • How would it programmatically know that the address you entered wasn't the address of the person? If you are saying that the rule you need to enforce is no person can have the same default address as another person you can add the addressId to the unique address but that would assume no married couples/roommates/etc. in the database

                            – billpennock
                            Aug 10 '17 at 13:24











                          • I meant database constraint. Addresses.peopleId links an address to a person. The same row clearly can't link to another person. Therefore defaultAddress needs to validate that the address marked as default for a given peopleId also has a matching peopleId. (I just implemented this in PostgreSQL and addressed it with a trigger validator.)

                            – Kiran Jonnalagadda
                            Aug 16 '17 at 10:53











                          • Sorry it had been awhile since I answered this and I should have spent more time understanding your comment. It's a good catch. I had alot of trouble getting code in this comment, maybe it's not possible. Anyway I added a multi-column foreign key to the code above to answer the very excellent concern. I think this will do what you identified without a trigger.

                            – billpennock
                            Aug 17 '17 at 15:43
















                          What if you insert into defaultAddress an address that belongs to someone else? This won't catch it.

                          – Kiran Jonnalagadda
                          Aug 9 '17 at 6:34





                          What if you insert into defaultAddress an address that belongs to someone else? This won't catch it.

                          – Kiran Jonnalagadda
                          Aug 9 '17 at 6:34













                          How would it programmatically know that the address you entered wasn't the address of the person? If you are saying that the rule you need to enforce is no person can have the same default address as another person you can add the addressId to the unique address but that would assume no married couples/roommates/etc. in the database

                          – billpennock
                          Aug 10 '17 at 13:24





                          How would it programmatically know that the address you entered wasn't the address of the person? If you are saying that the rule you need to enforce is no person can have the same default address as another person you can add the addressId to the unique address but that would assume no married couples/roommates/etc. in the database

                          – billpennock
                          Aug 10 '17 at 13:24













                          I meant database constraint. Addresses.peopleId links an address to a person. The same row clearly can't link to another person. Therefore defaultAddress needs to validate that the address marked as default for a given peopleId also has a matching peopleId. (I just implemented this in PostgreSQL and addressed it with a trigger validator.)

                          – Kiran Jonnalagadda
                          Aug 16 '17 at 10:53





                          I meant database constraint. Addresses.peopleId links an address to a person. The same row clearly can't link to another person. Therefore defaultAddress needs to validate that the address marked as default for a given peopleId also has a matching peopleId. (I just implemented this in PostgreSQL and addressed it with a trigger validator.)

                          – Kiran Jonnalagadda
                          Aug 16 '17 at 10:53













                          Sorry it had been awhile since I answered this and I should have spent more time understanding your comment. It's a good catch. I had alot of trouble getting code in this comment, maybe it's not possible. Anyway I added a multi-column foreign key to the code above to answer the very excellent concern. I think this will do what you identified without a trigger.

                          – billpennock
                          Aug 17 '17 at 15:43





                          Sorry it had been awhile since I answered this and I should have spent more time understanding your comment. It's a good catch. I had alot of trouble getting code in this comment, maybe it's not possible. Anyway I added a multi-column foreign key to the code above to answer the very excellent concern. I think this will do what you identified without a trigger.

                          – billpennock
                          Aug 17 '17 at 15:43











                          0














                          You could do it through an instead of trigger, or if you want it as a constraint create a constraint that references a function that checks for a row that has the default set to 1



                          EDIT oops, needs to be <=



                          Create table mytable(id1 int, defaultX bit not null default(0))
                          go

                          create Function dbo.fx_DefaultExists()
                          returns int as
                          Begin
                          Declare @Ret int
                          Set @ret = 0
                          Select @ret = count(1) from mytable
                          Where defaultX = 1

                          Return @ret
                          End
                          GO
                          Alter table mytable add
                          CONSTRAINT [CHK_DEFAULT_SET] CHECK
                          (([dbo].fx_DefaultExists()<=(1)))
                          GO
                          Insert into mytable (id1, defaultX) values (1,1)

                          Insert into mytable (id1, defaultX) values (2,1)





                          share|improve this answer



























                            0














                            You could do it through an instead of trigger, or if you want it as a constraint create a constraint that references a function that checks for a row that has the default set to 1



                            EDIT oops, needs to be <=



                            Create table mytable(id1 int, defaultX bit not null default(0))
                            go

                            create Function dbo.fx_DefaultExists()
                            returns int as
                            Begin
                            Declare @Ret int
                            Set @ret = 0
                            Select @ret = count(1) from mytable
                            Where defaultX = 1

                            Return @ret
                            End
                            GO
                            Alter table mytable add
                            CONSTRAINT [CHK_DEFAULT_SET] CHECK
                            (([dbo].fx_DefaultExists()<=(1)))
                            GO
                            Insert into mytable (id1, defaultX) values (1,1)

                            Insert into mytable (id1, defaultX) values (2,1)





                            share|improve this answer

























                              0












                              0








                              0







                              You could do it through an instead of trigger, or if you want it as a constraint create a constraint that references a function that checks for a row that has the default set to 1



                              EDIT oops, needs to be <=



                              Create table mytable(id1 int, defaultX bit not null default(0))
                              go

                              create Function dbo.fx_DefaultExists()
                              returns int as
                              Begin
                              Declare @Ret int
                              Set @ret = 0
                              Select @ret = count(1) from mytable
                              Where defaultX = 1

                              Return @ret
                              End
                              GO
                              Alter table mytable add
                              CONSTRAINT [CHK_DEFAULT_SET] CHECK
                              (([dbo].fx_DefaultExists()<=(1)))
                              GO
                              Insert into mytable (id1, defaultX) values (1,1)

                              Insert into mytable (id1, defaultX) values (2,1)





                              share|improve this answer













                              You could do it through an instead of trigger, or if you want it as a constraint create a constraint that references a function that checks for a row that has the default set to 1



                              EDIT oops, needs to be <=



                              Create table mytable(id1 int, defaultX bit not null default(0))
                              go

                              create Function dbo.fx_DefaultExists()
                              returns int as
                              Begin
                              Declare @Ret int
                              Set @ret = 0
                              Select @ret = count(1) from mytable
                              Where defaultX = 1

                              Return @ret
                              End
                              GO
                              Alter table mytable add
                              CONSTRAINT [CHK_DEFAULT_SET] CHECK
                              (([dbo].fx_DefaultExists()<=(1)))
                              GO
                              Insert into mytable (id1, defaultX) values (1,1)

                              Insert into mytable (id1, defaultX) values (2,1)






                              share|improve this answer












                              share|improve this answer



                              share|improve this answer










                              answered Mar 12 '09 at 9:54









                              cmsjrcmsjr

                              38.4k96361




                              38.4k96361





















                                  0














                                  This is a fairly complex process that cannot be handled through a simple constraint.



                                  We do this through a trigger. However before you write the trigger you need to be able to answer several things:



                                  do we want to fail the insert if a default exists, change it to 0 instead of 1 or change the existing default to 0 and leave this one as 1?
                                  what do we want to do if the default record is deleted and other non default records are still there? Do we make one the default, if so how do we determine which one?



                                  You will also need to be very, very careful to make the trigger handle multiple row processing. For instance a client might decide that all of the records of a particular type should be the default. You wouldn't change a million records one at a time, so this trigger needs to be able to handle that. It also needs to handle that without looping or the use of a cursor (you really don't want the type of transaction discussed above to take hours locking up the table the whole time).



                                  You also need a very extensive tesing scenario for this trigger before it goes live. You need to test:
                                  adding a record with no default and it is the first record for that customer
                                  adding a record with a default and it is the first record for that customer
                                  adding a record with no default and it is the not the first record for that customer
                                  adding a record with a default and it is the not the first record for that customer
                                  Updating a record to have the default when no other record has it (assuming you don't require one record to always be set as the deafault)
                                  Updating a record to remove the default
                                  Deleting the record with the deafult
                                  Deleting a record without the default
                                  Performing a mass insert with multiple situations in the data including two records which both have isdefault set to 1 and all of the situations tested when running individual record inserts
                                  Performing a mass update with multiple situations in the data including two records which both have isdefault set to 1 and all of the situations tested when running individual record updates
                                  Performing a mass delete with multiple situations in the data including two records which both have isdefault set to 1 and all of the situations tested when running individual record deletes






                                  share|improve this answer



























                                    0














                                    This is a fairly complex process that cannot be handled through a simple constraint.



                                    We do this through a trigger. However before you write the trigger you need to be able to answer several things:



                                    do we want to fail the insert if a default exists, change it to 0 instead of 1 or change the existing default to 0 and leave this one as 1?
                                    what do we want to do if the default record is deleted and other non default records are still there? Do we make one the default, if so how do we determine which one?



                                    You will also need to be very, very careful to make the trigger handle multiple row processing. For instance a client might decide that all of the records of a particular type should be the default. You wouldn't change a million records one at a time, so this trigger needs to be able to handle that. It also needs to handle that without looping or the use of a cursor (you really don't want the type of transaction discussed above to take hours locking up the table the whole time).



                                    You also need a very extensive tesing scenario for this trigger before it goes live. You need to test:
                                    adding a record with no default and it is the first record for that customer
                                    adding a record with a default and it is the first record for that customer
                                    adding a record with no default and it is the not the first record for that customer
                                    adding a record with a default and it is the not the first record for that customer
                                    Updating a record to have the default when no other record has it (assuming you don't require one record to always be set as the deafault)
                                    Updating a record to remove the default
                                    Deleting the record with the deafult
                                    Deleting a record without the default
                                    Performing a mass insert with multiple situations in the data including two records which both have isdefault set to 1 and all of the situations tested when running individual record inserts
                                    Performing a mass update with multiple situations in the data including two records which both have isdefault set to 1 and all of the situations tested when running individual record updates
                                    Performing a mass delete with multiple situations in the data including two records which both have isdefault set to 1 and all of the situations tested when running individual record deletes






                                    share|improve this answer

























                                      0












                                      0








                                      0







                                      This is a fairly complex process that cannot be handled through a simple constraint.



                                      We do this through a trigger. However before you write the trigger you need to be able to answer several things:



                                      do we want to fail the insert if a default exists, change it to 0 instead of 1 or change the existing default to 0 and leave this one as 1?
                                      what do we want to do if the default record is deleted and other non default records are still there? Do we make one the default, if so how do we determine which one?



                                      You will also need to be very, very careful to make the trigger handle multiple row processing. For instance a client might decide that all of the records of a particular type should be the default. You wouldn't change a million records one at a time, so this trigger needs to be able to handle that. It also needs to handle that without looping or the use of a cursor (you really don't want the type of transaction discussed above to take hours locking up the table the whole time).



                                      You also need a very extensive tesing scenario for this trigger before it goes live. You need to test:
                                      adding a record with no default and it is the first record for that customer
                                      adding a record with a default and it is the first record for that customer
                                      adding a record with no default and it is the not the first record for that customer
                                      adding a record with a default and it is the not the first record for that customer
                                      Updating a record to have the default when no other record has it (assuming you don't require one record to always be set as the deafault)
                                      Updating a record to remove the default
                                      Deleting the record with the deafult
                                      Deleting a record without the default
                                      Performing a mass insert with multiple situations in the data including two records which both have isdefault set to 1 and all of the situations tested when running individual record inserts
                                      Performing a mass update with multiple situations in the data including two records which both have isdefault set to 1 and all of the situations tested when running individual record updates
                                      Performing a mass delete with multiple situations in the data including two records which both have isdefault set to 1 and all of the situations tested when running individual record deletes






                                      share|improve this answer













                                      This is a fairly complex process that cannot be handled through a simple constraint.



                                      We do this through a trigger. However before you write the trigger you need to be able to answer several things:



                                      do we want to fail the insert if a default exists, change it to 0 instead of 1 or change the existing default to 0 and leave this one as 1?
                                      what do we want to do if the default record is deleted and other non default records are still there? Do we make one the default, if so how do we determine which one?



                                      You will also need to be very, very careful to make the trigger handle multiple row processing. For instance a client might decide that all of the records of a particular type should be the default. You wouldn't change a million records one at a time, so this trigger needs to be able to handle that. It also needs to handle that without looping or the use of a cursor (you really don't want the type of transaction discussed above to take hours locking up the table the whole time).



                                      You also need a very extensive tesing scenario for this trigger before it goes live. You need to test:
                                      adding a record with no default and it is the first record for that customer
                                      adding a record with a default and it is the first record for that customer
                                      adding a record with no default and it is the not the first record for that customer
                                      adding a record with a default and it is the not the first record for that customer
                                      Updating a record to have the default when no other record has it (assuming you don't require one record to always be set as the deafault)
                                      Updating a record to remove the default
                                      Deleting the record with the deafult
                                      Deleting a record without the default
                                      Performing a mass insert with multiple situations in the data including two records which both have isdefault set to 1 and all of the situations tested when running individual record inserts
                                      Performing a mass update with multiple situations in the data including two records which both have isdefault set to 1 and all of the situations tested when running individual record updates
                                      Performing a mass delete with multiple situations in the data including two records which both have isdefault set to 1 and all of the situations tested when running individual record deletes







                                      share|improve this answer












                                      share|improve this answer



                                      share|improve this answer










                                      answered Mar 12 '09 at 14:44









                                      HLGEMHLGEM

                                      80.1k889157




                                      80.1k889157





















                                          0














                                          @Andy Jones gave an answer above closest to mine, but bearing in mind the Rule of Three, I placed the logic directly in the stored proc that updates this table. This was my simple solution. If I need to update the table from elsewhere, I will move the logic to a trigger. The one default rule applies to each set of records specified by a FormID and a ConfigID:



                                          ALTER proc [dbo].[cpForm_UpdateLinkedReport]
                                          @reportLinkId int,
                                          @defaultYN bit,
                                          @linkName nvarchar(150)
                                          as
                                          if @defaultYN = 1
                                          begin
                                          declare @formId int, @configId int
                                          select @formId = FormID, @configId = ConfigID from csReportLink where ReportLinkID = @reportLinkId
                                          update csReportLink set DefaultYN = 0 where isnull(ConfigID, @configId) = @configId and FormID = @formId
                                          end
                                          update
                                          csReportLink
                                          set
                                          DefaultYN = @defaultYN,
                                          LinkName = @linkName
                                          where
                                          ReportLinkID = @reportLinkId





                                          share|improve this answer























                                          • ALways a bad idea to put required logic in a stored proc vice a trigger. You won't always know when you need to change to a trigger later because multiple applications are using this. You are creating a data integrity nightmare for some future person to fix.

                                            – HLGEM
                                            Mar 12 '09 at 18:24











                                          • I'm responsible for the single application area that maintains that table, and we release tomorrow, so not having to add to our SQL update script reduces risk. The update script for sp's is generated, other objects it's manual, with risk. I will schedule a trigger for next cycle, in 6 weeks time.

                                            – ProfK
                                            Mar 12 '09 at 18:34















                                          0














                                          @Andy Jones gave an answer above closest to mine, but bearing in mind the Rule of Three, I placed the logic directly in the stored proc that updates this table. This was my simple solution. If I need to update the table from elsewhere, I will move the logic to a trigger. The one default rule applies to each set of records specified by a FormID and a ConfigID:



                                          ALTER proc [dbo].[cpForm_UpdateLinkedReport]
                                          @reportLinkId int,
                                          @defaultYN bit,
                                          @linkName nvarchar(150)
                                          as
                                          if @defaultYN = 1
                                          begin
                                          declare @formId int, @configId int
                                          select @formId = FormID, @configId = ConfigID from csReportLink where ReportLinkID = @reportLinkId
                                          update csReportLink set DefaultYN = 0 where isnull(ConfigID, @configId) = @configId and FormID = @formId
                                          end
                                          update
                                          csReportLink
                                          set
                                          DefaultYN = @defaultYN,
                                          LinkName = @linkName
                                          where
                                          ReportLinkID = @reportLinkId





                                          share|improve this answer























                                          • ALways a bad idea to put required logic in a stored proc vice a trigger. You won't always know when you need to change to a trigger later because multiple applications are using this. You are creating a data integrity nightmare for some future person to fix.

                                            – HLGEM
                                            Mar 12 '09 at 18:24











                                          • I'm responsible for the single application area that maintains that table, and we release tomorrow, so not having to add to our SQL update script reduces risk. The update script for sp's is generated, other objects it's manual, with risk. I will schedule a trigger for next cycle, in 6 weeks time.

                                            – ProfK
                                            Mar 12 '09 at 18:34













                                          0












                                          0








                                          0







                                          @Andy Jones gave an answer above closest to mine, but bearing in mind the Rule of Three, I placed the logic directly in the stored proc that updates this table. This was my simple solution. If I need to update the table from elsewhere, I will move the logic to a trigger. The one default rule applies to each set of records specified by a FormID and a ConfigID:



                                          ALTER proc [dbo].[cpForm_UpdateLinkedReport]
                                          @reportLinkId int,
                                          @defaultYN bit,
                                          @linkName nvarchar(150)
                                          as
                                          if @defaultYN = 1
                                          begin
                                          declare @formId int, @configId int
                                          select @formId = FormID, @configId = ConfigID from csReportLink where ReportLinkID = @reportLinkId
                                          update csReportLink set DefaultYN = 0 where isnull(ConfigID, @configId) = @configId and FormID = @formId
                                          end
                                          update
                                          csReportLink
                                          set
                                          DefaultYN = @defaultYN,
                                          LinkName = @linkName
                                          where
                                          ReportLinkID = @reportLinkId





                                          share|improve this answer













                                          @Andy Jones gave an answer above closest to mine, but bearing in mind the Rule of Three, I placed the logic directly in the stored proc that updates this table. This was my simple solution. If I need to update the table from elsewhere, I will move the logic to a trigger. The one default rule applies to each set of records specified by a FormID and a ConfigID:



                                          ALTER proc [dbo].[cpForm_UpdateLinkedReport]
                                          @reportLinkId int,
                                          @defaultYN bit,
                                          @linkName nvarchar(150)
                                          as
                                          if @defaultYN = 1
                                          begin
                                          declare @formId int, @configId int
                                          select @formId = FormID, @configId = ConfigID from csReportLink where ReportLinkID = @reportLinkId
                                          update csReportLink set DefaultYN = 0 where isnull(ConfigID, @configId) = @configId and FormID = @formId
                                          end
                                          update
                                          csReportLink
                                          set
                                          DefaultYN = @defaultYN,
                                          LinkName = @linkName
                                          where
                                          ReportLinkID = @reportLinkId






                                          share|improve this answer












                                          share|improve this answer



                                          share|improve this answer










                                          answered Mar 12 '09 at 16:19









                                          ProfKProfK

                                          14.6k85319631




                                          14.6k85319631












                                          • ALways a bad idea to put required logic in a stored proc vice a trigger. You won't always know when you need to change to a trigger later because multiple applications are using this. You are creating a data integrity nightmare for some future person to fix.

                                            – HLGEM
                                            Mar 12 '09 at 18:24











                                          • I'm responsible for the single application area that maintains that table, and we release tomorrow, so not having to add to our SQL update script reduces risk. The update script for sp's is generated, other objects it's manual, with risk. I will schedule a trigger for next cycle, in 6 weeks time.

                                            – ProfK
                                            Mar 12 '09 at 18:34

















                                          • ALways a bad idea to put required logic in a stored proc vice a trigger. You won't always know when you need to change to a trigger later because multiple applications are using this. You are creating a data integrity nightmare for some future person to fix.

                                            – HLGEM
                                            Mar 12 '09 at 18:24











                                          • I'm responsible for the single application area that maintains that table, and we release tomorrow, so not having to add to our SQL update script reduces risk. The update script for sp's is generated, other objects it's manual, with risk. I will schedule a trigger for next cycle, in 6 weeks time.

                                            – ProfK
                                            Mar 12 '09 at 18:34
















                                          ALways a bad idea to put required logic in a stored proc vice a trigger. You won't always know when you need to change to a trigger later because multiple applications are using this. You are creating a data integrity nightmare for some future person to fix.

                                          – HLGEM
                                          Mar 12 '09 at 18:24





                                          ALways a bad idea to put required logic in a stored proc vice a trigger. You won't always know when you need to change to a trigger later because multiple applications are using this. You are creating a data integrity nightmare for some future person to fix.

                                          – HLGEM
                                          Mar 12 '09 at 18:24













                                          I'm responsible for the single application area that maintains that table, and we release tomorrow, so not having to add to our SQL update script reduces risk. The update script for sp's is generated, other objects it's manual, with risk. I will schedule a trigger for next cycle, in 6 weeks time.

                                          – ProfK
                                          Mar 12 '09 at 18:34





                                          I'm responsible for the single application area that maintains that table, and we release tomorrow, so not having to add to our SQL update script reduces risk. The update script for sp's is generated, other objects it's manual, with risk. I will schedule a trigger for next cycle, in 6 weeks time.

                                          – ProfK
                                          Mar 12 '09 at 18:34

















                                          draft saved

                                          draft discarded
















































                                          Thanks for contributing an answer to Stack Overflow!


                                          • Please be sure to answer the question. Provide details and share your research!

                                          But avoid


                                          • Asking for help, clarification, or responding to other answers.

                                          • Making statements based on opinion; back them up with references or personal experience.

                                          To learn more, see our tips on writing great answers.




                                          draft saved


                                          draft discarded














                                          StackExchange.ready(
                                          function ()
                                          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f637894%2fconstraint-for-only-one-record-marked-as-default%23new-answer', 'question_page');

                                          );

                                          Post as a guest















                                          Required, but never shown





















































                                          Required, but never shown














                                          Required, but never shown












                                          Required, but never shown







                                          Required, but never shown

































                                          Required, but never shown














                                          Required, but never shown












                                          Required, but never shown







                                          Required, but never shown







                                          這個網誌中的熱門文章

                                          What does pagestruct do in Eviews?

                                          Dutch intervention in Lombok and Karangasem

                                          Channel Islands