2013-05-10 2 views
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 для клана, чтобы увидеть, что они все еще могут подписаться.

Я до сих пор довольно Newbee на запросах SQL, и даже не знаю, как идти об этом ..

Я попытался WHERE (dbo.vwGetClanDivisions.clanName = NULL), но возвращает только подразделение, которые не имеют никакого клана вообще.

EDIT - структуры:

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

Вы можете использовать 'выбрать * из VW, где идентификатор не в (текущее) SELECT, QUERY' – Sachin

+0

структуры таблицы поможет –

+0

Моей плохой :) Добавлена ​​структуры в настоящее время. – TheGeekZn

ответ

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 показывают только строки, в которых нет соответствующего игрового деления для этого клана. Вы также можете использовать псевдонимы таблиц (как указано выше), чтобы сократить ваши запросы.

Edit: я должен был с помощью 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 

В соответствии с этим, для записи #A с идентификатором 1 связаны с #b с идентификатором 1, 2 или 3 (не 4 или 5). Выполнение вышеуказанного запроса показывает, что метод NOT IN возвращает 4 и 5, что является правильным. Я не совсем уверен, почему RIGHT OUTER JOIN не работает, так как цель состоит в том, чтобы возвращать каждую строку из #B независимо от того, была ли она найдена в #A.

Edit 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 
+0

Я боюсь 'FROM dbo.vwGetClanDivisions cd' и' LEFT JOIN dbo.vwGetGameDivisions gd' не делает логики в моей голове. – TheGeekZn

+0

Вид dbo.vwGetGameDivisions переименован в gd по сокращенным причинам. Аналогично, dbo.vwGetClanDivisions переименовывается в cd по той же причине. –

+0

Действительно. Вместо того, чтобы повторять длинный стол несколько раз, вы можете указать более короткую строку после имени таблицы, чтобы передать запрос «Я хочу теперь ссылаться на эту таблицу как x». – Maloric

2

Лучше сделать матч с идентификационным поле вместо поля имени.

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 

     ) 
+0

При использовании этого, есть пустой результат ... – TheGeekZn

+1

Да, об этом. Набрав его из головы –

+0

Даже это, хороший сэр, это то, что я далек от возможности сделать. – TheGeekZn

Смежные вопросы