2017-06-29 31 views
1

我有一個場景,我想通過使用排他或關係類型的多對多關係來查找表中的記錄列表。鑑於下面這個人爲的例子,我需要一個分配給至少一篇文章的類別列表,但不是所有的文章。我可以通過遍歷所有類別來蠻力,但這是非常低效的。 MS SQL Server上的T-SQL有沒有一種很好的乾淨方法?獨佔或在SQL中多對多關係

CREATE TABLE [dbo].[ArticleCategories](
    [ArticleId] [int] NOT NULL, 
    [CategoryId] [int] NOT NULL, 
CONSTRAINT [PK_ArticleCategories] PRIMARY KEY CLUSTERED 
(
    [ArticleId] ASC, 
    [CategoryId] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 


CREATE TABLE [dbo].[Articles](
    [Id] [int] NOT NULL, 
    [Title] [nvarchar](100) NOT NULL, 
CONSTRAINT [PK_Articles] PRIMARY KEY CLUSTERED 
(
    [Id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 


CREATE TABLE [dbo].[Categories](
    [Id] [int] NOT NULL, 
    [CategoryName] [nvarchar](100) NULL, 
CONSTRAINT [PK_Categories] PRIMARY KEY CLUSTERED 
(
    [Id] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 


insert into Articles (Id, Title) values (1, 'Jon Snow') 
insert into Articles (Id, Title) values (2, 'Joffry Baratheon') 
insert into Articles (Id, Title) values (3, 'Cercei Lanister') 
insert into Articles (Id, Title) values (4, 'Sansa Stark') 
insert into Articles (Id, Title) values (5, 'Khal Drogo') 
insert into Articles (Id, Title) values (6, 'Ramsey Bolton') 
insert into Articles (Id, Title) values (7, 'Melisandre') 

insert into Categories (Id, CategoryName) values (1, 'Orange') 
insert into Categories (Id, CategoryName) values (2, 'Blue') 
insert into Categories (Id, CategoryName) values (3, 'Purple') 
insert into Categories (Id, CategoryName) values (4, 'Green') 
insert into Categories (Id, CategoryName) values (5, 'Violet') 
insert into Categories (Id, CategoryName) values (6, 'Yellow') 
insert into Categories (Id, CategoryName) values (7, 'Black') 

insert into ArticleCategories (ArticleId, CategoryId) values (1, 1) 
insert into ArticleCategories (ArticleId, CategoryId) values (2, 1) 
insert into ArticleCategories (ArticleId, CategoryId) values (3, 1) 
insert into ArticleCategories (ArticleId, CategoryId) values (4, 1) 
insert into ArticleCategories (ArticleId, CategoryId) values (5, 1) 
insert into ArticleCategories (ArticleId, CategoryId) values (6, 1) 
insert into ArticleCategories (ArticleId, CategoryId) values (7, 1) 
insert into ArticleCategories (ArticleId, CategoryId) values (2, 2) 
insert into ArticleCategories (ArticleId, CategoryId) values (3, 2) 
insert into ArticleCategories (ArticleId, CategoryId) values (5, 3) 
insert into ArticleCategories (ArticleId, CategoryId) values (7, 3) 

在這種情況下,查詢不會返回類別'Orange',因爲它被分配到所有文章。它會返回'藍色'和'紫色',因爲它們被分配到至少一篇文章,但不是全部。其他類別根本不會返回,因爲它們根本沒有分配。

預期的結果將是:

2|Blue 
3|Purple 

更新以包括採樣數據和預期的輸出。

+2

你可以發佈一點樣品數據和所需的輸出嗎?我想我知道你在找什麼,但不完全是積極的。 –

+0

@SeanLange示例數據已更新。 – Darthg8r

回答

2

的條件可以進行測試。在結果

SELECT AC.CategoryId, C.CategoryName 
FROM 
    ArticleCategories AC 
    INNER JOIN Categories C 
     ON AC.CategoryId = C.CategoryId 
GROUP BY AC.CategoryID 
HAVING Count(*) < (SELECT Count(*) FROM Articles) 

ArticleCategories包含已分配到的一篇文章至少一次組的信息,因此需要爲此不需要附加條件的加盟只爲類別名稱必要。

由於ArticleCategories的主鍵包括兩列(ArticleIdCategoryId),因此每個類別不能有重複的文章。因此,每個類別的計數等於該類別分配給的文章數量。

請注意,我使用的是HAVING子句,而不是WHERE子句。 WHERE子句在分組之前應用。 HAVING子句在分組後應用,並可以參考聚合結果。

+0

我調整了我的答案以反映更新的預期結果集。 –

+0

看起來不錯,並認爲你所做的事情符號很有用! – xQbert

1

使用您的樣本:http://rextester.com/THCJ13143

,並使用GROUP BY查詢,並具有:

SELECT AC.CategoryID, c.categoryName 
FROM ArticleCategories AC 
LEFT JOIN Categories C 
    on C.ID = AC.CategoryID 
GROUP BY AC.CategoryID, c.Categoryname 
HAVING count(AC.ArticleID) < (SELECT count(*) FROM Articles) 

我們得到:不加入

CategoryID categoryName 
2   Blue 
3   Purple