SQL多对多的关系

时间:2014-06-29 13:47:22

标签: sql sql-server

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

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

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

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

我想做的就是让比赛进行某些分类。结果由具有table-value参数的存储过程返回,该参数保存所需的分类:

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参数中的RaceClassificationTypeID:3和8

输出:所有种族都使用RaceClassificationID 3和8以及可选的任何其他种族(2,29,12)

这意味着只应返回比赛92729和92730,因为它会返回示例中的所有比赛。

2 个答案:

答案 0 :(得分:0)

这是“set-within-sets”子查询的示例。解决此问题的一种方法是使用聚合和having子句。以下是RaceId s:

的方法
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;

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

答案 1 :(得分:0)

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

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,请告诉我!