SQL Server - 仅在满足条件时才加入

时间:2014-03-20 16:20:08

标签: sql sql-server

我有三个表(至少是类似的),具有以下关系:

项目表:

 ID      | Val
---------+---------
 1       | 12
 2       | 5
 3       | 22

组表:

 ID      | Parent  | Range
---------+---------+---------
 1       | NULL    | [10-30]
 2       | 1       | [20-25]
 3       | NULL    | [0-15]

GroupToItem表:

 GroupID | ItemID
---------+---------
 1       | 1
 1       | 3

现在我想使用相同的查询向GroupToItem表添加第2组和第3组的行(因为此处未显示的其他一些条件更复杂)。我想限制我搜索的项目,如果新组有父项,但是如果没有,则查看所有项目。

目前我在两个几乎完全相同的语句上使用IF / ELSE,但是当父项存在时添加另一个JOIN行。是否可以进行连接以减少要查看的项目数量,只有在可以限制的情况下?

我的两个问题如下:

DECLARE @GroupID INT = 2;...

INSERT INTO GroupToItem(GroupID, ItemID)
SELECT  g.ID,
        i.ID,
FROM    Group g
JOIN    Item i ON i.Val IN g.Range
JOIN    GroupToItem gti ON g.Parent = gti.GroupID AND i.ID = gti.ItemID
WHERE   g.ID = @GroupID

-

DECLARE @GroupID INT = 3;...

INSERT INTO GroupToItem(GroupID, ItemID)
SELECT  g.ID,
        i.ID,
FROM    Group g
JOIN    Item i ON i.Val IN g.Range
WHERE   g.ID = @GroupID

所以基本上我只想在给定的组有父级的情况下进行第二次JOIN。这可能在一个查询中吗?重要的是,与范围进行比较的项目数量尽可能小,因为对我来说这是一项密集的操作。

编辑:这似乎已经在这个测试设置中解决了它,类似于Denis Valeev的建议。如果我可以使用我的实时数据,我会接受。我一直有一些奇怪的问题 - 可能会出现更多问题。

SELECT  g.Id,
        i.Id
FROM    Group g
JOIN    Item i ON (i.Val > g.Start AND i.Val < g.End)
WHERE   g.Id = 2
AND     (
            (g.ParentId IS NULL)
            OR 
            (EXISTS(SELECT 1 FROM GroupToItem gti WHERE g.ParentId = gti.GroupId AND i.Id = gti.ItemId))
        )

SQL Fiddle

2 个答案:

答案 0 :(得分:1)

试试这个:

INSERT INTO GroupToItem(GroupID, ItemID)
SELECT  g.ID,
        i.ID,
FROM    Group g
JOIN    Item i ON i.Val IN g.Range
WHERE   g.ID = @GroupID
and (g.ID in (3) or exists (select top 1 1 from GroupToItem gti where g.Parent = gti.GroupID AND i.ID = gti.ItemID))

答案 1 :(得分:0)

如果Range列是varchar数据类型,您可以尝试这样的事情:

INSERT INTO GROUPTOITEM (GROUPID, ITEMID)
SELECT A.ID, B.ID
FROM GROUP AS A
LEFT JOIN ITEM AS B
ON B.VAL BETWEEN CAST(SUBSTRING(SUBSTRING(A.RANGE,1,CHARINDEX('-',A.RANGE,1)-1),2,10) AS INT)
    AND CAST(REPLACE(SUBSTRING(A.RANGE,CHARINDEX('-',A.RANGE,1)+1,10),']','') AS INT)