1

業種を格納する [Sectors] というテーブルがあります。[SectorId] は INT として定義され、このテーブルの主キーです。これらのセクターは、主キーを使用してデータベース全体で参照されますが、他のテーブルではこの主キーに対する外部キー制約はありません。

このテーブルには 2 つのセクターがあり、1 つにマージする必要があります。セクター X とセクター Y があります。セクター Y はセクター X にマージする必要があります。したがって、基本的には、他のテーブルのセクター Y へのすべての参照をセクター X への参照に置き換え、[セクターからセクター Y を削除する必要があります。 ] テーブル。

問題は、外部キー制約がないため、セクター Y を参照しているいくつかのテーブルが失われる可能性があることです。

これを行う最善の方法は何ですか?

4

4 に答える 4

3
SET NOCOUNT ON

DECLARE 
  @SQL AS NVARCHAR(MAX),
  @name AS NVARCHAR(128)

SELECT name
    INTO #tables
    FROM sys.sysobjects AS O
    WHERE EXISTS (SELECT *
                    FROM sys.syscolumns
                    WHERE id = O.id
                      AND name = 'SectorID')

WHILE EXISTS (SELECT * FROM #tables)
BEGIN
    SELECT TOP 1
      @name = name
        FROM #tables

    SET @SQL = 'IF EXISTS (SELECT * FROM ' + @name + ' WHERE SectorID = 2)' + CHAR(13) + CHAR(10)
    SET @SQL = @SQL + 'BEGIN' + CHAR(13) + CHAR(10)
    SET @SQL = @SQL + ' UPDATE ' + @name + ' SET SectorID = 1 WHERE SectorID = 2' + CHAR(13) + CHAR(10)
    SET @SQL = @SQL + 'END' + CHAR(13) + CHAR(10)
    PRINT @SQL

    DELETE
        FROM #tables
        WHERE name = @name
END

DROP TABLE #tables
于 2010-07-30T11:16:48.373 に答える
1

すべてのテーブルでフィールド SectorID を呼び出していない場合は、整数フィールドを持つすべてのテーブルをループして、「セクター Y」レコードが存在するかどうかを確認できます。

これは、syscolumns を sysobjects (user-table の WHERE xtype = 'U') と結合することで実行できます。

于 2010-07-30T09:01:42.060 に答える
0

私は非常によく似た質問の解決策を見つけるためにいくつかの作業を行いました。結果は、マージするレコードのIDを取得し、最初にそれらを残し、関連するテーブルのすべての外部キーを更新し、残りを削除するストアドプロシージャです。

たとえば、topicstarterの質問について。これらのテーブルがあると仮定しましょう:

[Sectors]
ID Name
10  'SectorA'
20  'Sector A'
30  'Sector B'
40  'sector a'

[RelatedRecords]
ID, SectorID, SomeField
1,  10        'value 1'
2,  20        'value 2'
3,  30        'value 3'
4,  40        'value 4'

(IDは主キーである必要があり、SectorIDは外部キーである必要があります)そして、レコード10、20、40をマージしてレコード20を残します。これを行うには、次のように呼び出す必要があります。

dbo.MergeRecords '20, 10, 40', 'Sectors'

結果は次のようになります。

[Sectors]
ID Name
20  'Sector A'
30  'Sector B'

[RelatedRecords]
ID, SectorID, SomeField
1,  20        'value 1'
2,  20        'value 2'
3,  30        'value 3'
4,  20        'value 4'

関連するテーブルがない場合は、削除のみが実行されます。このソリューションは、単一値の主キー(私が覚えているように3NF)がある場合をカバーします。

したがって、ストアドプロシージャコードは次のとおりです。

-- =============================================
-- Description: Merging table records.
-- First record will be leaved, other will be deleted.
-- Depended foreign keys in all tables will be updated.
-- Example:
-- exec MergeRecords '1, 2, 3', 'SomeRecords'
-- =============================================
CREATE PROCEDURE [dbo].[MergeRecords]
    @Id nvarchar(max),      -- Comma-separated IDs
    @PKTable nvarchar(50)   -- Name of a table where merge records in
AS
BEGIN
    SET NOCOUNT ON; 

    declare @PKField nvarchar(50),
            @FKTable nvarchar(50),
            @FKField nvarchar(50)

    declare @updateSql nvarchar(max),
            @deleteSql nvarchar(max)

    declare @firstId nvarchar(max),
            @otherId nvarchar(max)

    set @firstId = LEFT(@Id, CHARINDEX(',', @Id) - 1)
    set @otherId = RIGHT(@Id, LEN(@Id) - CHARINDEX(',', @Id))

    -- Primary key name
    select @PKField = ccu.COLUMN_NAME 
        from INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
        join INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE ccu on ccu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
        where tc.CONSTRAINT_TYPE = 'PRIMARY KEY'
        and tc.TABLE_NAME = @PKTable

    -- Loop foreign keys
    declare constraints_cursor cursor local fast_forward
    for select 
            --tc.CONSTRAINT_NAME, 
            --ccu_pk.TABLE_NAME PK_TABLE_NAME, 
            --ccu_pk.COLUMN_NAME PK_COLUMN_NAME, 
            ccu_fk.TABLE_NAME FK_TABLE_NAME, 
            ccu_fk.COLUMN_NAME FK_COLUMN_NAME

        from INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc 
        join INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc on rc.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
        join INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE ccu_fk on ccu_fk.CONSTRAINT_NAME = rc.CONSTRAINT_NAME
        join INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE ccu_pk on ccu_pk.CONSTRAINT_NAME = rc.UNIQUE_CONSTRAINT_NAME

        where ccu_pk.TABLE_NAME = @PKTable
        and tc.CONSTRAINT_TYPE = 'FOREIGN KEY'

        --Example, @PKTable = 'SomeRecords'
        --CONSTRAINT_NAME                           PK_TABLE_NAME   PK_COLUMN_NAME  FK_TABLE_NAME               FK_COLUMN_NAME
        --FK_SomeRecords_SomeRelatedRecords1        SomeRecords     Id              SomeRelatedRecords          FirstSomeRecordId
        --FK_SomeRecords_SomeRelatedRecords2        SomeRecords     Id              SomeRelatedRecords          SecondSomeRecordId
        --FK_SomeRecords_AnotherRelatedRecords      SomeRecords     Id              AnotherRelatedRecords       SomeRecordId

    open constraints_cursor 
    fetch next from constraints_cursor 
    into @FKTable, @FKField

    while @@fetch_status = 0
    begin
        -- Update foreign keys
        set @updateSql = '
            update @FKTable
            set @FKField = @firstId
            where @FKField in (@otherId)'

        set @updateSql = replace(@updateSql, '@FKTable', @FKTable)
        set @updateSql = replace(@updateSql, '@FKField', @FKField)
        set @updateSql = replace(@updateSql, '@firstId', @firstId)
        set @updateSql = replace(@updateSql, '@otherId', @otherId)
        exec sp_executesql @updateSql

        fetch next from constraints_cursor 
        into @FKTable, @FKField
    end

    close constraints_cursor
    deallocate constraints_cursor 

    -- Delete other records 
    set @deleteSql = 
        'delete from @PKTable
        where @PKField in (@otherId)'

    set @deleteSql = replace(@deleteSql, '@PKTable', @PKTable)  
    set @deleteSql = replace(@deleteSql, '@PKField', @PKField)
    set @deleteSql = replace(@deleteSql, '@otherId', @otherId)
    exec sp_executesql @deleteSql

    select 0    
END
于 2011-06-16T10:07:26.840 に答える
0

on update cascadeセマンティクスを使用して外部キーを追加できますか?

あなたのポイントについて

セクター Y をまだ参照しているいくつかのテーブルが失われる可能性があります。

FK 制約がない場合でも、SQL Server がこれを知る魔法のような方法はありません。ビューまたはセクター テーブルのデータベース依存関係 (ストアド プロシージャ、ビュー) の定義で、同様の名前の列を探すことができますInformation_Schemaが、どちらのアプローチも完全に確実ではありません。

于 2010-07-30T08:56:17.883 に答える