1

USER_ID を介した USER_ACTIVITY_FACT など、そのデータベース内の他のテーブルへの参照を持つデータベース内の USER_DIM テーブルに関する問題。

テーブルの元の設計が、実際には別のデータベースの EXTERNAL_ID に由来する適切な一意の識別子を使用しなかった場合に、問題が発生します。

余分な行を選択または削除する方法はわかりますが、他のテーブルの行を更新して元の USER_ID を指すようにしてから、USER_DIM テーブルの余分な行を削除したいと考えています。

SELECT ACTIVITY_FACT.USER_ID
FROM USER_ACTIVITY_FACT 
WHERE USER_ACTIVITY_FACT.USER_ID IN (
select USER_ID    
  FROM USER_DIM
  WHERE EXTERNAL_ID IN (SELECT ud2.EXTERNAL_ID 
  FROM  USER_DIM as ud2
  where USER_ID > ud2.USER_ID));

これらを最小の USER_ID になるように更新します

次に、USER_DIM で削除ステートメントを実行します。

DELETE      
  FROM USER_DIM   
  WHERE EXTERNAL_ID IN (SELECT ud2.EXTERNAL_ID 
  FROM  USER_DIM as ud2
  where USER_ID > ud2.USER_ID);

その後、テーブルを ALTER して、EXTERNAL_ID 列に一意のインデックスを付けます。

このクエリは、問題のある余分な USER_ID に対して複数の行を一度に更新するよりも、行ごとに更新される可能性があります。

よろしくお願いします。

更新 目的を明確にするには:

USER_ACTIVITY_FACT 
-------------
USER_ID
2 
3
4
5
6

USER_DIM
--------------
USER_ID  EXTERNAL_ID
2        23
3        23
4        24
5        24
6        26

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

USER_ACTIVITY_FACT 
-------------
USER_ID
2 
2
4
4
6

USER_DIM
--------------
USER_ID  EXTERNAL_ID
2        23
4        24
6        26

お役に立てれば

4

3 に答える 3

1

リクエストを正しく受け取ったかどうかはわかりませんが、ここに私が思いついたものがあります。group by を使用して、各 EXTERNAL_ID の最小の USER_ID を見つけ、それをマッピング情報として一時テーブルに入れることができます (OLD_ID => NEW_ID)。その後、一時テーブルで更新する必要があるテーブルに参加し、古い ID から新しい ID に更新します (OLD_ID で参加し、NEW_ID に更新します)。最後に、以前のように削除するか、マッピング テーブルに再び結合できます。

SQLFiddleDemoで確認できます

--prepare data and insert into #mapping temp table from dim
WITH CTE1 AS 
(
    SELECT EXTERNAL_ID, MIN(USER_ID) AS NEW_USER_ID
    FROM dbo.USER_DIM
    GROUP BY EXTERNAL_ID
)
SELECT  CTE1.EXTERNAL_ID ,
        USER_ID AS OLD_USER_ID ,
        NEW_USER_ID
INTO #mapping
FROM dbo.USER_DIM
INNER JOIN CTE1 ON dbo.USER_DIM.EXTERNAL_ID = CTE1.EXTERNAL_ID;

--check your mappings
SELECT * FROM #mapping;

--update fact table based on join on mappings
UPDATE fact 
SET fact.USER_ID = src.NEW_USER_ID
FROM #mapping src
INNER JOIN dbo.USER_ACTIVITY_FACT fact ON src.OLD_USER_ID = fact.USER_ID;

--check your fact table
SELECT * FROM USER_ACTIVITY_FACT;

--delete from dim based on mappings missmatch
DELETE d
FROM dbo.USER_DIM d
INNER JOIN #mapping m ON d.USER_ID = m.OLD_USER_ID
WHERE m.NEW_USER_ID <> m.OLD_USER_ID;

--check your dim table
SELECT * FROM dbo.USER_DIM;
于 2013-04-12T21:13:27.800 に答える
1

OUTPUT句を使用して派生テーブルからUPDATEを使用する

DECLARE @delUserID TABLE(delUserID int) 

UPDATE x
SET x.USER_ID = x.NewUserID
OUTPUT DELETED.USER_ID INTO @delUserID
FROM (  
      SELECT f.USER_ID, 
             MIN(f.USER_ID) OVER(PARTITION BY u.EXTERNAL_ID) AS NewUserID             
      FROM dbo.USER_ATIVITY_FACT f JOIN dbo.USER_DIM u ON f.USER_ID = u.USER_ID
      ) x
WHERE x.USER_ID != x.NewUserID      

DELETE USER_DIM
WHERE USER_ID IN (SELECT delUserID FROM @delUserID)

SQLFiddle のデモ

于 2013-04-12T21:32:21.423 に答える
0

これが私が思いついたものです。@Nenad ソリューションは機能しますが、これを liquibase スクリプトを介してプッシュする必要があり、SQL Server 機能が機能するかどうかはわかりませんでした。これをSQLFiddleに対してもチェックしました。

--prepare data and insert into #mapping temp table from dim
UPDATE USER_ACTIVITY_FACT 
SET 
    USER_ID = (SELECT 
            MIN(ud1.USER_ID)
        FROM
            USER_DIM as ud1
        WHERE
            ud1.EXTERNAL_ID = (SELECT 
                    MIN(ud2.EXTERNAL_ID)
                FROM
                    USER_DIM as ud2,
                    USER_DIM as ud3
                WHERE
                    ud2.EXTERNAL_ID = ud3.EXTERNAL_ID
                        AND ud3.USER_ID = USER_ACTIVITY_FACT.USER_ID)
); 

--delete from dim based on mappings missmatch
DELETE      
  FROM USER_DIM  
WHERE EXISTS
    (SELECT * FROM USER_DIM t1 
     WHERE t1.EXTERNAL_ID = USER_DIM.EXTERNAL_ID
 AND USER_DIM.USER_ID > t1.USER_ID);
于 2013-04-15T13:44:13.600 に答える