0

我有一个 SQL Server 数据库,我需要从两个视图中选择剩余的行。

其背后的想法是:我将游戏分区存储在一张桌子上,而将部落存储在另一张桌子上。

  • vwGetGameDivisions得到所有可以划分的游戏 。
  • vwGetClanDivisions获取氏族订阅的所有当前游戏部门。

目前,使用

SELECT dbo.vwGetGameDivisions.name, dbo.vwGetClanDivisions.clanName
FROM   dbo.vwGetClanDivisions 
RIGHT OUTER JOIN
       dbo.vwGetGameDivisions
    ON dbo.vwGetClanDivisions.gameName = dbo.vwGetGameDivisions.name

获取注册到他们的所有“部门”和“氏族”。

我想显示剩余的部门(某个氏族未注册的其余部门),因此我可以将其绑定到dropDownList一个氏族以查看他们仍然可以订阅的内容。

我仍然是 SQL 查询的新手,甚至不知道该怎么做。

我试过WHERE (dbo.vwGetClanDivisions.clanName = NULL)了,但这只会返回根本没有氏族的师。

编辑 - 结构:

CREATE TABLE [dbo].[tblSiteClanGameDivision](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [clanId] [int] NOT NULL,
    [gameId] [int] NOT NULL,
    [removed] [tinyint] NOT NULL,
    [dateAdded] [datetime] NOT NULL,
 CONSTRAINT [PK_tblSiteClanGameDivision] PRIMARY KEY CLUSTERED 

CREATE TABLE [dbo].[tblSiteGame](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [name] [nvarchar](200) NOT NULL,
    [description] [nvarchar](700) NULL,
    [thumbnailLocation] [nvarchar](100) NULL,
    [genreId] [int] NOT NULL,
    [isDivision] [tinyint] NOT NULL,
 CONSTRAINT [PK__tblGame__3213E83F03317E3D] PRIMARY KEY CLUSTERED 

CREATE VIEW [dbo].[vwGetClanDivisions]
AS
SELECT dbo.tblSiteClanDetail.clanId, dbo.tblSiteClanDetail.clanName, dbo.tblSiteGame.id AS gameId, dbo.tblSiteGame.name AS gameName, 
                         dbo.tblSiteClanGameDivision.removed, dbo.tblSiteClanGameDivision.dateAdded
FROM   dbo.tblSiteClanDetail 
INNER JOIN  dbo.tblSiteClanGameDivision ON dbo.tblSiteClanDetail.id = dbo.tblSiteClanGameDivision.clanId 
INNER JOIN dbo.tblSiteGame ON dbo.tblSiteClanGameDivision.gameId = dbo.tblSiteGame.id

GO

CREATE VIEW [dbo].[vwGetGameDivisions]
AS
SELECT  id, name, thumbnailLocation, isDivision
FROM    dbo.tblSiteGame
WHERE   (isDivision = 1)

GO
4

2 回答 2

2

关键是用来INNER JOIN获取氏族注册的部门,并LEFT JOIN获取他们没有注册的部门。 LEFT JOIN即使氏族没有注册他们也会返回部门,然后你过滤掉他们所在的部门,如下所示:

-- Get matching divisions
SELECT gd.ID, gd.name, cd.clanName
FROM dbo.vwGetClanDivisions cd
INNER JOIN dbo.vwGetGameDivisions gd ON cd.gameId = gd.id

-- Get remaining divisions
SELECT gd.ID, gd.name, cd.clanName
FROM dbo.vwGetClanDivisions cd
LEFT JOIN dbo.vwGetGameDivisions gd ON cd.gameId = gd.id
WHERE gd.gameName IS NULL

请注意,第二个查询使用 aLEFT JOIN来获取连接两侧的所有行,并且该WHERE子句仅显示该氏族没有匹配的游戏分区的行。您还可以使用表名别名(如上)来缩短查询。

编辑: 我应该一直在使用 a RIGHT OUTER JOIN,但在测试中即使这样也没有用。但是@Vincent James 给出的 using 方法NOT IN确实如此(需要注意的是,您必须指定要搜索的部落,否则您只会得到一个空部门的列表)。这是一个非常基本的 SQL 示例:

CREATE TABLE #A (ID int, bID int)
CREATE TABLE #B (ID int)

INSERT INTO #B (ID) SELECT 1
INSERT INTO #B (ID) SELECT 2
INSERT INTO #B (ID) SELECT 3
INSERT INTO #B (ID) SELECT 4
INSERT INTO #B (ID) SELECT 5

INSERT INTO #A (ID, bID) SELECT 1,1
INSERT INTO #A (ID, bID) SELECT 1,2
INSERT INTO #A (ID, bID) SELECT 1,3
INSERT INTO #A (ID, bID) SELECT 2,1
INSERT INTO #A (ID, bID) SELECT 2,2
INSERT INTO #A (ID, bID) SELECT 3,3
INSERT INTO #A (ID, bID) SELECT 3,4

SELECT DISTINCT #B.ID 
FROM #B 
WHERE ID NOT IN(SELECT bID FROM #A WHERE ID = 1)

DROP TABLE #A
DROP TABLE #B

据此,ID 为 1 的#A 的条目链接到 ID 为 1、2 或 3(不是 4 或 5)的 #B。运行上面的查询显示该NOT IN方法返回 4 和 5,这是正确的。我不完全确定为什么RIGHT OUTER JOIN不起作用,因为这样做的目的是从 #B 返回每一行,无论它是否在 #A 中找到。

编辑 2: 删除了 Right Outer join 方法,因为我有两个冲突的WHERE子句会阻止返回任何行。使用具有给定表结构的外连接是不可能的,因为您需要通过左侧的 ID 进行选择,但只能在左侧为空的地方进行选择。 NOT IN是正确的方法,如上图。

编辑 3 这是您应该需要创建的存储过程。这比硬编码查询要好,因为它可以保护您免受SQL 注入攻击。

CREATE PROCEDURE [dbo].[GetEmptyClanDivisions]
(
    @ClanID INT
)
AS
BEGIN
    -- Get the clan name
    DECLARE @ClanName nvarchar(255)
    SET @ClanName = SELECT TOP 1 clanName FROM tblSiteClanDetail WHERE clanId = @ClanID 

    -- Get a list of divisions the clan is registered for
    SELECT DISTINCT ID, name, @ClanName 
    FROM vwGetGameDivisions
    WHERE ID NOT IN(
        SELECT gameId 
        FROM tblSiteClanGameDivision 
        WHERE clanId = @ClanID
    )
END
于 2013-05-10T10:14:09.060 回答
2

最好使用 ID 字段而不是名称字段进行匹配。

SELECT dbo.vwGetGameDivisions.name
FROM dbo.vwGetGameDivisions
WHERE dbo.vwGetGameDivisions.name NOT IN (
    SELECT dbo.vwGetGameDivisions.name
    FROM   dbo.vwGetClanDivisions 
        INNER JOIN dbo.vwGetGameDivisions ON dbo.vwGetClanDivisions.gameName = dbo.vwGetGameDivisions.name

        )   
于 2013-05-10T10:08:32.303 回答