繁体   English   中英

SQL多对多关系

[英]SQL Many to Many relationship

我在编写SQL查询时遇到困难。 这是3个表的结构,表Race_ClassificationType是多对多表。

Table Race
---------------------------- 
RaceID
Name

Table Race_ClassificationType
----------------------------
Race_ClassificationTypeID
RaceID
RaceClassificationID

Table RaceClassificationType
----------------------------
RaceClassificationTypeID
Name

我想做的是让某些类别的比赛。 结果由存储过程返回,该存储过程具有一个表值参数,该参数包含所需的分类:

CREATE TYPE [dbo].[RaceClassificationTypeTable]
AS TABLE
(
  RaceClassificationTypeID INT NULL
);
GO

CREATE PROCEDURE USP_GetRaceList
    (@RaceClassificationTypeTable AS [RaceClassificationTypeTable] READONLY,
     @RaceTypeID INT = NULL,
     @IsCompleted BIT = NULL,
     @MinDateTime DATETIME = NULL,
     @MaxDateTime DATETIME = NULL,
     @MaxRaces INT = NULL)
     WITH RECOMPILE
AS
BEGIN
    SET NOCOUNT ON;

    SELECT   DISTINCT
             R.[RaceID]
            ,R.[RaceTypeID]
            ,R.[Name]
            ,R.[Abbreviation]
            ,R.[DateTime]
            ,R.[IsCompleted]
    FROM    [Race] R,[Race_ClassificationType] R_CT, [RaceClassificationType] RCT
    WHERE   (R.[RaceTypeID] = @RaceTypeID OR @RaceTypeID IS NULL)
    AND     (R.[IsCompleted] = @IsCompleted OR @IsCompleted IS NULL)
    AND     (R.[DateTime] >= @MinDateTime OR @MinDateTime IS NULL)
    AND     (R.[DateTime] <= @MaxDateTime OR @MaxDateTime IS NULL)
    AND     (R.RaceID = R_CT.RaceID)
    AND     (R_CT.RaceClassificationTypeID = RCT.RaceClassificationTypeID)
    AND     (RCT.RaceClassificationTypeID IN (SELECT DISTINCT T.RaceClassificationTypeID FROM @RaceClassificationTypeTable T))
    ORDER BY [DateTime] DESC
    OFFSET 0 ROWS FETCH NEXT @MaxRaces ROWS ONLY
END
GO

因为此存储过程无法正确运行,因为它返回所有在分类类型ID的表值参数中具有至少一个分类类型ID的种族(由于IN子句)。 我希望存储过程仅返回具有在表值参数中提供的所有分类的种族。

例:

RaceClassificationTypeID    RaceID
3   92728
3   92729
8   92729
29  92729
12  92729
2   92729
3   92730
8   92730
8   92731
1   92731

RaceClassificationTypeTable参数中的RaceClassificationTypeIDs:3和8

输出:所有具有RaceClassificationID 3和8的种族,以及其他任意种族(2、29、12)

这意味着仅应返回种族92729和92730,因为示例中的所有种族均已返回。

这是“集内集”子查询的示例。 解决此问题的一种方法是使用聚合和having子句。 这是如何获取RaceId的:

select RaceID
from RaceClassification rc
group by RaceID
having sum(case when RaceClassificationTypeId = 3 then 1 else 0 end) > 0 and
       sum(case when RaceClassificationTypeId = 8 then 1 else 0 end) > 0;

中每个条件having子句数有多少行有各类型。 仅保留每个比赛(因为> 0 )。

您可以使用以下子查询来获取所有比赛信息:

select r.*
from Races r join
     (select RaceID
      from RaceClassification rc
      group by RaceID
      having sum(case when RaceClassificationTypeId = 3 then 1 else 0 end) > 0 and
             sum(case when RaceClassificationTypeId = 8 then 1 else 0 end) > 0
     ) rc
     on r.RaceID = rc.RaceId;

您的存储过程似乎还有其他条件。 这些也可以添加。

我已经建立了两个表,一个表存储您的结果集,另一个表表示存储过程的表值参数中的值。 见下文。

CREATE TABLE ABC
(
RCTID INT,
RID INT
)
INSERT INTO ABC VALUES (3,92728)
INSERT INTO ABC VALUES (3,92729)
INSERT INTO ABC VALUES (8,92729)
INSERT INTO ABC VALUES (29,92729)
INSERT INTO ABC VALUES (12,92729)
INSERT INTO ABC VALUES (2,92729)
INSERT INTO ABC VALUES (3,92730)
INSERT INTO ABC VALUES (8,92730)
INSERT INTO ABC VALUES (8,92731)
INSERT INTO ABC VALUES (1,92731)
GO
CREATE TABLE TABLEVALUEPARAMETER
(
VID INT
)
INSERT INTO TABLEVALUEPARAMETER VALUES (3)
INSERT INTO TABLEVALUEPARAMETER VALUES (8)
GO
SELECT RID FROM ABC WHERE RCTID IN (SELECT VID FROM TABLEVALUEPARAMETER) GROUP BY
RID HAVING COUNT(RID) = (SELECT COUNT(VID) FROM TABLEVALUEPARAMETER)
GO

如果在计算机上运行此命令,您会注意到它会生成您要使用的两个ID。

因为您的存储过程中选择了很多列,所以有必要使用CTE(公用表表达式)。 这是因为如果要尝试将当前select语句中的所有列分组,则必须按所有列分组,然后您将得到重复项。

如果第一个CTE提供了结果集,然后您使用上面选择的版本,则您应该只能产生所需的ID。

如果您不知道CTE,请告诉我!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM