SQL 查询多对多映射 table 以获得匹配输入值集的数据

SQL query many-many mapping table for data matching set of input values

好的,这个很快就变得复杂了。我有一个系统可以收集给定机器的硬件规格。为了简单起见,我将只关注 GPU。一台机器可以有任意数量的GPU,一个GPU(我是按型号存储的)可以存在于多台机器上。

在顶部我有一个 MachineSpec table,它包含一个 SpecID 和一个 GPUConfigID(以及其他但我们忽略它们)。此 GPUConfigID 是 GPU_Map table 中 GPUConfigID 的外键。 GPU_Map table 包含 ID、GPUConfigID 和 GPUID 列。 GPUID与GPU中的GPUID挂钩table,包含GPUID、Model、Speed等

这里是 GPU_Map table 中有效 "configs" 的示例:

我目前使用的方法适用于 table 中的所有情况,但有一个警告。 GPUConfigIDs 1 和 2 之类的情况将强制执行它们的唯一性,因此如果我尝试添加具有 GPUIDs 1 和 3 的新配置,它不会让我这样做(这很好)。不幸的是,在相同的配置中添加重复的 GPUID(如在 GPUConfigIDs 3 和 4 中)会将其注册为一个全新的配置,尽管它是相同的。

请务必注意,插入此 table 仅涉及 GPUID。基本上,我有一个 GPUID 列表,我需要查看它们是否作为配置存在于 GPU_Map table 中。如果他们不这样做,则创建配置。如果他们这样做,那么 return GPUConfigID。

这是我目前拥有的存储过程:

@IDList IntList READONLY, 
@ID int OUTPUT
AS
BEGIN
    BEGIN TRAN gpuconfigupdate
        DECLARE @Count INT
        SELECT @Count = (SELECT COUNT(*)
            FROM GPU_Map as Map1
                LEFT OUTER JOIN @IDList as ID1
                ON Map1.GPUID = ID1.Item
            GROUP BY Map1.GPUConfigID
            HAVING COUNT(Map1.GPUID) = (SELECT COUNT(Item) FROM @IDList)
                AND COUNT(ID1.Item) = (SELECT COUNT(Item) FROM @IDList))

        IF @Count IS NULL BEGIN
            INSERT INTO GPU_Map (GPUConfigID, GPUID) 
            SELECT ((SELECT MAX(GPUConfigID) FROM GPU_Map)+1), Item FROM @IDList
        END

        SELECT @ID = (SELECT GPUConfigID 
                        FROM GPU_Map as Map1
                            LEFT OUTER JOIN @IDList as ID1
                            ON Map1.GPUID = ID1.Item
                        GROUP BY Map1.GPUConfigID
                        HAVING COUNT(Map1.GPUID) = (SELECT COUNT(Item) FROM @IDList)
                            AND COUNT(ID1.Item) = (SELECT COUNT(Item) FROM @IDList))
    COMMIT TRAN gpuconfigupdate
END

另请注意我的用户定义类型 IntList:

CREATE TYPE [dbo].[IntList] AS TABLE(
    [Item] [INT] NULL
);

注意:GPU_Map table 之前的主键为 (GPUConfigID, GPUID),但在同一配置中尝试输入重复的 GPUID 时会抛出主键错误(例如GPUConfigIDs 3 和 4)。这就是我创建 ID 列并将其设置为主键的原因,这导致了我目前的情况。

来自未来的人们,欢欣鼓舞!因为我设法找到了解决这个问题的方法。

有问题的查询是这个:

SELECT COUNT(*)
    FROM GPU_Map as Map1
        LEFT OUTER JOIN @IDList as ID1
        ON Map1.GPUID = ID1.Item
    GROUP BY Map1.GPUConfigID
    HAVING COUNT(Map1.GPUID) = (SELECT COUNT(Item) FROM @IDList)
        AND COUNT(ID1.Item) = (SELECT COUNT(Item) FROM @IDList)

除@IDList 包含重复值(有效)的情况外,它按预期工作。解决方案是将最后两行更改为:

    HAVING COUNT(Map1.RAMID) = COUNT(ID1.Item)
        AND COUNT(DISTINCT ID1.Item) = (SELECT COUNT(DISTINCT Item) FROM @IDList))

请注意,COMMIT 之前 OP 中存储过程的最后两行也需要以相同的方式更改。