我有一个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
获取所有'divisions'和'clans'注册到它们。
我想显示剩余的分区(某个战队未注册的其余分区),所以我可以将它绑定到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
答案 0 :(得分: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
)
答案 1 :(得分: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
请注意,第二个查询使用LEFT JOIN
来获取连接两侧的所有行,而WHERE
子句仅显示该族没有匹配游戏分区的行。您还可以使用表名别名(如上所述)来缩短查询。
修改强>
我应该使用RIGHT OUTER JOIN
,但在测试中甚至没有用。但是,@ Vincent James使用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的条目链接到#B,ID为1,2或3(不是4或5)。运行上面的查询显示NOT IN
方法返回4和5,这是正确的。我不完全确定为什么RIGHT OUTER JOIN
不起作用,因为这样做的目的是从#B返回每一行,无论它是否在#A中找到。
编辑2:
删除了右外连接方法,因为我有两个冲突的WHERE
子句会阻止返回任何行。使用具有给定表结构的外连接是不可能的,因为您需要通过左侧的ID进行选择,但只能选择左侧为空的位置。 NOT IN
是正确的方法,如上所示。
编辑3 这是您需要创建的存储过程。这比对查询进行硬编码更好,因为它可以保护您免受SQL injection攻击。
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