如何编写查询以计算具有多个约束和匹配的记录?

时间:2016-04-06 22:26:35

标签: mysql sql join jointable

我有5张桌子:

  1. 文件
  2. 标签
  3. join_File_Tags
  4. 配置文件
  5. join_Profile_Tags
  6. “个人档案”和“join_Profile_Tags”表确定用户可以看到的文件。

    数据可能如下所示:

    • File1 包含一个三个
    • 的标签
    • File2 包含标签一个五个
    • File3 包含一个三个六个
    • 的标签
    • Profile1 可以访问标签两个三个四个
    • Profile2 可以访问标签一个两个三个四个

    我需要一个查询,返回与Profile的标签列表中的所有标签匹配的文件。

    我想出了这个:

    SELECT 
        files.id,
        files.FileName,
        (SELECT COUNT(j_file_tags.id) from j_file_tags  WHERE j_file_tags.fileID = files.id ) as fileTagCount
    FROM files
    LEFT JOIN j_file_tags ON j_file_tags.fileID = files.id
    LEFT JOIN tags ON tags.id = j_file_tags.tagID
    WHERE
        files.caseID = '123456'
        AND 
        j_file_tags.tagID IN ("One, Two, Three, Four, Five") /* i can get these before hand */
    GROUP BY 
        files.id
    HAVING 
        COUNT(j_file_tags.id) = fileTagCount /* this makes sure that the user has access to ALL the tags applied to the file*/
    

    这正是我所需要的。但我现在想要的是:每个标签中有多少个文件?

    因此,在顶部的示例数据中, Profile2 用户将看到 File1 File2 ,但 File3 >因为那个标签,哪个profile2无权访问。我需要一个构建标签云的查询(没有基于j_profile_tags表的biggie),但我需要标签包含文件计数。我需要标记一个来显示数字2,三个显示1,五个显示1.我到目前为止尝试的查询包括所有的计数文件,因此即使 Profile2 无法访问该第三个文件,标记一个也会计入3。 这是我的半工作查询:

    SELECT
        tags.id,
        tags.TagName,
        COUNT(tags.id) as tagCount
    FROM
        tags
    INNER JOIN j_file_tags ON tags.id = j_file_tags.tagID
    INNER JOIN files ON j_file_tags.fileID = files.id
    INNER JOIN j_profile_tags ON j_profile_tags.tagID = tags.id AND j_profile_tags.profileID = 'Profile2'
    WHERE
        files.caseID = '123456'
    GROUP BY
        tags.id
    

1 个答案:

答案 0 :(得分:0)

我不完全了解您的表格,尤其是 “员工” 列。 但是,如果您的意思是 每个标记中包含的文件 过滤了多少个文件,那么请尝试以下查询:

DECLARE @TblFiles AS TABLE(ID int identity(1, 1) primary key, TheFileName varchar(50))
DECLARE @TblTags AS TABLE(ID int identity(1, 1) primary key, TheTag varchar(50))
DECLARE @TblProfiles AS TABLE(ID int identity(1, 1) primary key, TheProfile varchar(50))

DECLARE @TblFileTagMapper AS TABLE(ID int identity(1, 1) primary key, FileID int, TagID int)
DECLARE @TblProfileTagMapper AS TABLE(ID int identity(1, 1) primary key, ProfileID int, TagID int)

INSERT INTO @TblFiles(TheFileName) VALUES ('File1'), ('File2'), ('File3')
INSERT INTO @TblTags(TheTag) VALUES ('One'), ('Two'), ('Three'), ('Four'), ('Five'), ('Six')
INSERT INTO @TblProfiles(TheProfile) VALUES ('Profile1'), ('Profile2')
INSERT INTO @TblFileTagMapper(FileID, TagID) VALUES (1,1), (1,3), (2,1), (2,5), (3,1), (3,3), (3,6)
INSERT INTO @TblProfileTagMapper(ProfileID, TagID) VALUES (1,2), (1,3), (1,4), (2,1), (2,2), (2,3), (2,4), (2,5)

--Display File-Tag
SELECT  TheFileName
       ,STUFF((SELECT ', ' + CAST(TheTag AS VARCHAR(10)) [text()]
         FROM (SELECT F.TheFileName, T.TheTag FROM @TblFileTagMapper FT INNER JOIN @TblFiles F ON FT.FileID = F.ID INNER JOIN @TblTags T ON FT.TagID = T.ID) FT 
         WHERE TheFileName = t.TheFileName
         FOR XML PATH(''), TYPE)
        .value('.','NVARCHAR(MAX)'),1,2,' ') Tags
FROM (SELECT F.TheFileName, T.TheTag FROM @TblFileTagMapper FT INNER JOIN @TblFiles F ON FT.FileID = F.ID INNER JOIN @TblTags T ON FT.TagID = T.ID) t
GROUP BY TheFileName

--Display Profile-Tag
SELECT  TheProfile
       ,STUFF((SELECT ', ' + CAST(TheTag AS VARCHAR(10)) [text()]
         FROM (SELECT P.TheProfile, T.TheTag FROM @TblProfileTagMapper PT INNER JOIN @TblProfiles P ON PT.ProfileID = P.ID INNER JOIN @TblTags T ON PT.TagID = T.ID) PT
         WHERE TheProfile = t.TheProfile
         FOR XML PATH(''), TYPE)
        .value('.','NVARCHAR(MAX)'),1,2,' ') Tags
FROM (SELECT P.TheProfile, T.TheTag FROM @TblProfileTagMapper PT INNER JOIN @TblProfiles P ON PT.ProfileID = P.ID INNER JOIN @TblTags T ON PT.TagID = T.ID) t
GROUP BY TheProfile

--> Param Input
DECLARE @ParamProfile VARCHAR(50) = 'Profile2'

--> The Solution Query
SELECT T.TheTag, COALESCE(X.FileCount, 0) AS NumberOfFilesWhichContainTheTag
FROM @TblTags T
LEFT JOIN(
    SELECT FT.TagID, COUNT(FT.FileID) AS FileCount
    FROM @TblFileTagMapper FT
    WHERE EXISTS(SELECT 1 FROM @TblProfileTagMapper PT INNER JOIN @TblProfiles P ON PT.ProfileID = P.ID WHERE PT.TagID = FT.TagID AND P.TheProfile = @ParamProfile)
    GROUP BY FT.TagID

) X ON T.ID = X.TagID

这些可能不是您问题的真正答案,但可能会帮助您实现目标。