npeterson
npeterson

Reputation: 182

Master / Detail relationship in T-SQL

In a normal t-sql database focused on producing orders, I noticed that there are several tables (think Order Header and Order Lines), that don't have a real contraint defined in the database. Is there ever a downside to defining this constraint? It seems it would prevent orphaning records...

update: One of the reasons I ask is that in the stored procedures that produce the Order Header/Order Line structures, there are pieces of code like this:

SELECT  @sc_count = COUNT(*)
FROM    shopping_cart
WHERE   session_id = @sessionid 

INSERT  INTO log_table
        ( col1 ,
          col2 ,
          col3 ,
          col4 ,
          col5 ,
          col6 
        )
VALUES  ( 'load config' ,
          'count before' ,
          @sc_count ,
          @sessionid ,
          @quoteid ,
          @login_name 
        ) 

DECLARE @quote_product_id UNIQUEIDENTIFIER
DECLARE cart_cur CURSOR
FOR
    SELECT  quote_product_id
    FROM    quote_products
    WHERE   quote_id = @quoteid
OPEN cart_cur
FETCH NEXT FROM cart_cur INTO @quote_product_id

WHILE @@fetch_status = 0 
    BEGIN
        INSERT  INTO log_table
                ( col1 ,
                  col2 ,
                  col3 ,
                  col4 ,
                  col5
                )
        VALUES  ( 'load cart' ,
                  @sessionid ,
                  @quoteid ,
                  'checking product' ,
                  @quote_product_id
                )
        IF NOT EXISTS ( SELECT  session_product_id
                        FROM    shopping_cart
                        WHERE   session_product_id = @quote_product_id ) 
            BEGIN

                BEGIN TRY
                    INSERT  INTO shopping_cart
                            ( session_product_id ,
                              session_id ,
                              product_dim_id ,
                              quantity ,
                              price ,
                              picked_by_user ,
                              category_id ,
                              kit_id ,
                              price_list_id ,
                              configuration_id ,
                              origin_by ,
                              origin_date ,
                              changed_by ,
                              change_date ,
                              from_product ,
                              base_category_id ,
                              discount ,
                              discount_amount
                        )
                            SELECT  quote_product_id ,
                                    @sessionid ,
                                    product_dim_id ,
                                    quantity ,
                                    unit_price ,
                                    picked_by_user ,
                                    category_id ,
                                    kit_id ,
                                    price_list_id ,
                                    configuration_id ,
                                    origin_by ,
                                    origin_date ,
                                    changed_by ,
                                    change_date ,
                                    from_product ,
                                    NULL,
                                    discount ,
                                    discount_amount

                            FROM    quote_products
                            WHERE   quote_product_id = @quote_product_id
                END TRY
                BEGIN CATCH
                    DECLARE @error_number INT
                    DECLARE @error_message NVARCHAR(2048)
                    SELECT  @error_number = ERROR_NUMBER() ,
                            @error_message = ERROR_MESSAGE()

                    DELETE  FROM shopping_cart_header
                    WHERE   session_id = @sessionid
                    INSERT  INTO log_table
                            ( col1 ,
                              col2 ,
                              col3 ,
                              col4 ,
                              col_max
                            )
                    VALUES  ( 'dm load cart error - CATCH' ,
                              @sessionid ,
                              @quoteid ,
                              @error_number ,
                              @error_message
                            )

                    SELECT  @kitid AS kit_id ,
                            @pricelistid AS price_list_id ,
                            NEWID() AS configuration_id ,
                            0 AS cart_number_of_products ,
                            1 AS quote_number_of_products

                    RETURN 
                END CATCH

            END 
        ELSE 
            BEGIN
                UPDATE  shopping_cart
                SET     session_id = @sessionid
                WHERE   session_product_id = @quote_product_id
            END

        FETCH NEXT FROM cart_cur INTO @quote_product_id
    END

CLOSE cart_cur
DEALLOCATE cart_cur

SELECT  @sc_count = COUNT(*)
FROM    shopping_cart
WHERE   session_id = @sessionid 
INSERT  INTO log_table
        ( col1 ,
          col2 ,
          col3 ,
          col4 ,
          col5 ,
          col6 
        )
VALUES  ( 'load config' ,
          'count after' ,
          @sc_count ,
          @sessionid ,
          @quoteid ,
          @login_name 
        )

It seems the stored procedure is trying to identify an incorrect state where a quote_product_id returns more rows from a certain WHERE clause criteria then another. There is a comment that essentially says a quote might save incorrectly and so now it has to be checked to make sure all the quote products (lines) are present and accounted for.

Upvotes: 1

Views: 742

Answers (1)

Michael Goldshteyn
Michael Goldshteyn

Reputation: 74420

I can think of two possible reasons, but I am sure there are many more:

  1. A referential integrity constraint can be a performance hit. That doesn't mean they should not be used or enabled (unless after careful profiling, you determine that this is in fact the case).
  2. The order of insertion does not allow for the constraint to be maintained. Not having the constraint for this reason is a risky proposition, since the database can at times be in an invalid state, unless all such actions are carefully maintained within transactions, leaving the database valid at the end of each transaction.

Upvotes: 2

Related Questions