0

私のテーブル構造はおおよそ次のとおりです(除外している列が他にもあります)

WEAPON    MUNITION    RANGE

範囲が異なる多くの WEAPON-MUNITION ペアリングを持つ単一のテーブルをチェックするクエリを作成しています。WEAPON-MUNITION の範囲が異なるすべてのインスタンスを見つける必要があります。このテーブルには複数のデータ セットがあるため、重複が許可されます。はい、正規化に違反していますが、クエリを実行するだけで作成できませんでした。

たとえば、射程の異なる 4 つの武器と弾薬の組み合わせがあるとします。それらを表示して修正できるようにする必要があります。いくつかの複雑な CTE と非常に複雑な自己結合を試しましたが、結果が得られたと思うと、主キーだと思っていた列がデータセット間で重複しているため、元のテーブルに結び付けることができません! 上記のレコードを見つけた後、レコード全体を表示する必要があります。最初の行のほぼ 10 倍の行になってしまい、その理由がわかりません。

DBA に、すべてのレコードに対して一意のキーを生成できるように依頼する以外に、どうすればこれを達成できるかわかりません。

EDIT gregmacの例を使用して、このクエリを思いつきました(一般的で、いくつかの列と独自の情報を除外しています)

WITH range_cte AS 
( 
    SELECT 
        d1.WEAPON
       ,d1.MUNITION
       ,d1.WEAPON
       ,d1.RANGE
       ,d1.ID    --This is NOT a primary key! There are duplicates
    FROM data1 d1 INNER JOIN data2 d2
        ON  d1.WEAPON = d2.WEAPON
        AND d1.MUNITION = d2.MUNITION
        AND d1.RANGE <> d2.RANGE
    GROUP BY 
        d1.WEAPON
       ,d1.MUNITION
       ,d1.WEAPON
       ,d1.RANGE
       ,d1.ID
    ORDER BY 
        d1.WEAPON
       ,d1.MUNITION
)
--Self join the CTE on the original table using the ID (that's not a primary key)
SELECT * FROM range_cte r INNER JOIN data d
    ON r.ID = d.ID

私の考えは、テーブル全体に自動生成されたキーを挿入することですか、それとも CTE (データセットなど) にさらに列を含めて、ある種の自然キーを形成する必要がありますか?

4

3 に答える 3

1

私が誤解していない限り、単純に自己結合して、武器と弾薬が同じで射程が異なる他の列を見つける必要があります。

私はこれを思いついた:

SELECT d1.* 
FROM data d1
INNER JOIN data d2 
  ON d1.weapon = d2.weapon 
    AND d1.munition = d2.munition 
    AND d1.range <> d2.range
GROUP BY d1.weapon, d1.munition, d1.range -- eliminate duplicates which are caused by joining both ways 
         ,d1.other1 ,d1.other2
ORDER BY d1.weapon, d1.munition

テストデータ:

CREATE TABLE data
(
  WEAPON    varchar(20), 
  MUNITION  varchar(20), 
  RANGE     varchar(20),
  other1    varchar(20),
  other2    varchar(20)
);

INSERT INTO data VALUES ('a', 'x', '1', 'aaa','aaa');
INSERT INTO data VALUES ('a', 'x', '2', 'aaa','bbb');
INSERT INTO data VALUES ('a', 'y', '3', 'aaa','bbb');
INSERT INTO data VALUES ('a', 'z', '4', 'ccc','ddd');
INSERT INTO data VALUES ('b', 'x', '5', 'def','ghh');
INSERT INTO data VALUES ('b', 'z', '6', 'ccc','ddd');
INSERT INTO data VALUES ('b', 'z', '7', 'aaa','aaa');
INSERT INTO data VALUES ('b', 'z', '8', 'aaa','bbb');
INSERT INTO data VALUES ('b', 'z', '9', 'aaa','ccc');

そして出力:

WEAPON  MUNITION  RANGE  other1  other2
a       x         1      aaa     aaa 
a       x         2      aaa     bbb 
b       z         6      ccc     ddd 
b       z         7      aaa     aaa 
b       z         8      aaa     bbb 
b       z         9      aaa     ccc 

SQLfiddle: http://sqlfiddle.com/#!6/65590/3/0

于 2012-09-27T21:55:32.800 に答える
0

説明からはわかりませんが、おそらく次のようなものが必要です(「mytable」cteは、「othercolumn」を含むテーブルのテストデータを生成するための私の試みですが、それ以上になる可能性があります)。

WITH mytable AS (
    SELECT * 
    FROM (
    VALUES('w1','m1',10, 'o1'), ('w1','m1',20, 'o2'), 
           ('w2','m2',10, 'o3'),
           ('w3','m3',10, 'o4'), ('w3','m3',20,'o5'), ('w3','m3',30,'o6')
    )x(weapon,munition,[range], othercolumn)
), MultiRange AS (
SELECT weapon, munition FROM mytable
GROUP BY weapon,munition
HAVING COUNT(DISTINCT [range])>1
)
SELECT t.*
FROM mytable t
JOIN MultiRange m ON m.weapon = t.weapon AND m.munition = t.munition
ORDER BY weapon, munition, [range]
于 2012-09-27T21:50:42.323 に答える
0

アイデア: すべての武器と軍需品のペアと正しい範囲を含む新しいテーブルを作成します。新しいテーブルの値に基づいて元のテーブルを更新します。

UPDATE o
SET o.range = n.range
FROM original AS o
JOIN new AS n ON o.weapon = n.weapon
    AND o.munition = n.munition
于 2012-09-27T21:42:11.257 に答える