0

我的表结构大致如下(我省略了更多列)

WEAPON    MUNITION    RANGE

我正在编写一个查询来检查一个表,其中包含许多具有不同范围的 WEAPON-MUNITION 配对。我需要找到武器弹药具有不同射程的每个实例。允许重复,因为此表中有多个数据集。是的,它违反了规范化,但我没有做到,我只需要查询它。

所以假设我有四个不同范围的武器弹药配对,我需要能够显示它们以便可以纠正它们。我尝试了一些复杂的 CTE 和非常复杂的自连接,但是当我认为我有结果时,我无法将它绑定回原始表,因为我认为是主键的列在数据集之间有重复!找到上述记录后,我需要显示整个记录。我最终得到的行数几乎是我开始时的 10 倍,但我不知道为什么。

没有要求 DBA 允许我为每条记录生成唯一的密钥,我不知道如何实现这一点。

编辑 使用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

想法:创建一个包含所有武器弹药对和正确射程的新表。根据新表中的值更新原始表。

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 回答
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 回答