我正在为一个我觉得应该很简单的查询而苦苦挣扎,但我无法理解它。
我们有一个单独的表来保存不同方之间的关系。该表应该为每个关系包含一行。然而,我们注意到一些关系缺失了,我们想重建它们。基本上每个关系应该有两行,关系和逆。
所以,一张健康的桌子应该是这样的……
Id | PartyId | OtherPartyId | RelType | RelStatus
1 1111 2211 1 1
2 2211 1111 1 1
3 3344 4444 1 2
4 4444 3344 1 2
Run Code Online (Sandbox Code Playgroud)
但是,我们有这样的情况......
Id | PartyId | OtherPartyId | RelType | RelStatus
1 1111 2211 1 1
2 2211 1111 1 1
3 3344 4444 1 2
4 5555 2224 1 2
5 2224 5555 1 2
Run Code Online (Sandbox Code Playgroud)
方 3344 和 4444 之间的逆关系缺失,所以我只想返回该行,以便我可以插入逆关系。
'id' 列是无关紧要的,因为它只是一个标识列,但 RelType 和 RelStatus 很重要,因为它们对于反向关系需要相同 - 例如,在 4444 和 3344 之间可能存在确实存在的关系,但它是不同的类型和状态,所以我们应该忽略它(当然除非它也缺少逆元!)。
我尝试创建一个复合密钥系统来尝试识别丢失的 rels,但我发现它在某些情况下会带回重复项:
SELECT
CASE WHEN [PartyId] < [OtherPartyId]
THEN CAST([OtherPartyId] AS NVARCHAR(50)) + '.' + CAST([PartyId] AS NVARCHAR(50)) + '.' + CAST([RelType] AS NVARCHAR(50)) + '.' + CAST([RelStatus] AS NVARCHAR(50))
ELSE CAST([PartyId] AS NVARCHAR(50)) + '.' + CAST([OtherPartyId] AS NVARCHAR(50)) + '.' + CAST([RelType] AS NVARCHAR(50)) + '.' + CAST([RelStatus] AS NVARCHAR(50))
END AS CompKey
INTO #partyinvs
FROM PartyRelationships;
SELECT CompKey
FROM #partyinvs
GROUP BY CompKey
HAVING COUNT(*) < 2
Run Code Online (Sandbox Code Playgroud)
我希望这是有道理的?
谢谢,大卫
使用EXCEPT可以帮助您编写此查询。
简而言之,如果第一个 select 的任何行与 inverse + 正确RelType &不匹配RelStatus ,则返回它们。
SELECT PartyId , OtherPartyId, RelType , RelStatus
FROM dbo.Table
EXCEPT
SELECT OtherPartyId , PartyId, RelType , RelStatus
FROM dbo.Table;
Run Code Online (Sandbox Code Playgroud)
请记住,如果存在重复的行(具有反向关系的 EG 3 行),则不会返回这些行。
例子
数据线
CREATE TABLE dbo.bla(ID INT IDENTITY(1,1) PRIMARY KEY NOT NULL,
PartyId int,
OtherPartyId int,
RelType int,
RelStatus int);
Run Code Online (Sandbox Code Playgroud)
数据管理语言
INSERT INTO dbo.Bla(PartyId , OtherPartyId , RelType , RelStatus)
VALUES
(1111,2211 ,1 ,1),
(2211,1111 ,1 ,1),
(3344,4444 ,1 ,2),
(5555,2224 ,1 ,2),
(4444,3344 ,2 ,2),
(1111,2211 ,2 ,2);-- different type or status
Run Code Online (Sandbox Code Playgroud)
询问
SELECT PartyId , OtherPartyId, RelType , RelStatus
FROM dbo.Bla
EXCEPT
SELECT OtherPartyId , PartyId, RelType , RelStatus
FROM dbo.Bla;
Run Code Online (Sandbox Code Playgroud)
结果
PartyId OtherPartyId RelType RelStatus
1111 2211 2 2
3344 4444 1 2
4444 3344 2 2
5555 2224 1 2
Run Code Online (Sandbox Code Playgroud)
另一种解决方案可能是使用NOT EXISTS, EG 当您还需要该Id字段时。
SELECT Id,PartyId , OtherPartyId, RelType , RelStatus
FROM dbo.Bla b
WHERE NOT EXISTS
(
SELECT *
FROM dbo.Bla b2
where b.OtherPartyId = b2.PartyId
AND b.PartyId = b2.OtherPartyId
AND b.RelType = b2.RelType
AND b.RelStatus = b2.RelStatus
);
Run Code Online (Sandbox Code Playgroud)
执行此操作的最常见查询版本类似于:
INSERT INTO PartyRelationships (
PartyId,
OtherPartyId,
RelType,
RelStatus
)
SELECT pr.OtherPartyID,
pr.PartyId,
pr.RelType,
pr.RelStatus
FROM papr
LEFT JOIN PartyRelationships pri
ON pr.PartyId = pri.OtherPartyId
AND pr.otherPartyId = pri.PartyId
AND pr.RelType = pri.RelType
AND pr.RelStatus = pri.RelStatus
WHERE pri.partyId is null
Run Code Online (Sandbox Code Playgroud)
@randi-vertongen 的 EXCEPT 示例也是执行此操作的一种方法,并且可能更有效。另一种不是上述示例的方法是 MERGE 方法
MERGE INTO PartyRelationships AS pr
USING PartyRelationships AS pri
ON pr.PartyID = pri.OtherPartyId
AND pr.OtherPartyId = pri.PartyId
AND pr.RelType = pri.RelType
AND pr.RelStatus = RelStatus
WHEN NOT MATCHED THEN
INSERT(PartyId, OtherPartyId, RelType, RelStatus)
VALUES(pri.OtherPartyId, pri.PartyId, pri.RelType, pri.RelStatus);
Run Code Online (Sandbox Code Playgroud)
这与第一个示例基本相同,只是使用了 MERGE 语法。然而,这个操作是一种自我合并,所以这对我来说是合乎逻辑的。
您选择的任何选项都适用于您的要求。
| 归档时间: |
|
| 查看次数: |
348 次 |
| 最近记录: |