返回具有一组相关标记的记录

时间:2017-02-04 21:03:59

标签: sql sql-server

我有2个表,作业和Assignment_tags

ASSIGNMENTS
-----------
ASSIGNMENTID     int
ASSIGNMENTNAME   nvarchar(50)

ASSIGNMENT_TAGS
---------------
TAGID            int
ASSIGNMENTID     int
TAGNAME          nvarchar(50)

每个作业可以有多个标签。

我需要一个SQL查询来返回给定标记列表的分配。我需要这些作业才能拥有所有这些标签。

ASSIGNMENTS Table
-----------------
ASSIGNMENTID        ASSIGNMENTNAME
1                   Assignment 1
2                   Assignment 2
3                   Assignment 3

ASSIGNMENT_TAGS Table
---------------------
TAGID               ASSIGNMENTID       TAGNAME
1                   1                  Some Tag
2                   2                  Some Tag
3                   1                  Another Tag
4                   3                  A Different Tag
5                   2                  A Different Tag

如果我将“Some Tag,Another Tag”作为逗号分隔标记列表作为存储过程的输入参数提供,我希望查询返回ASSIGNMENTID 1,因为此赋值具有两个标记。

我确信这很容易,但我的大脑今天似乎没有用。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:0)

使用逗号分隔的列表很痛苦。但你可以这样做:

select att.assignmentid
from assignmenttags att
where ',' + @tags + ',' = '%,' + att.tagname + ',%'
group by att.assignmentid
having count(distinct att.tagname) = (length(@tags) - 
                                       length(replace(@tags, ',', '')
                                      ) + 1;

这假设输入列表只有逗号分隔值,并且列表中没有重复值。

答案 1 :(得分:0)

首先我建议使用这个有用的函数将anychar-delimited-list字符串转换为表。

CREATE FUNCTION [dbo].[Split]
(
@String NVARCHAR(4000),
@Delimiter NCHAR(1)
)
RETURNS TABLE
AS

RETURN
(
    WITH Split(stpos,endpos)
    AS(
        SELECT 0 AS stpos, CHARINDEX(@Delimiter,@String) AS endpos
        UNION ALL
        SELECT endpos+1, CHARINDEX(@Delimiter,@String,endpos+1)
            FROM Split
            WHERE endpos > 0
    )
    SELECT 'ID_Split' = ROW_NUMBER() OVER (ORDER BY (SELECT 1)),
        'Data' = RTRIM(LTRIM(SUBSTRING(@String,stpos,COALESCE(NULLIF(endpos,0),LEN(@String)+1)-stpos)))
    FROM Split
)
GO

使用此功能,您可以知道哪个ASSINGMENTSID至少与列表中的一个标签无关。

DECLARE @Comma_delimited_tag_list VARCHAR(500) = 'Some Tag,Another Tag'
DECLARE @Delimiter VARCHAR(1) = ','

SELECT
        A.ASSIGNMENTID, B.*, AT.*
    FROM [dbo].[Split](@Comma_delimited_tag_list, @Delimiter) B
        FULL JOIN ASSIGNMENTS A ON 1 = 1
        LEFT JOIN ASSIGNMENT_TAGS AT ON AT.ASSIGNMENTID = A.ASSIGNMENTID AND AT.TAGNAME = B.Data
    WHERE
        AT.ASSIGNMENTID IS NULL

结果:

ASSIGNMENTID ID_Split             Data        TAGID       ASSIGNMENTID TAGNAME
------------ -------------------- ----------- ----------- ------------ ----------------
2            2                    Another Tag NULL        NULL         NULL
3            1                    Some Tag    NULL        NULL         NULL
3            2                    Another Tag NULL        NULL         NULL

最后知道这一点,我们可以知道哪些ASSIGNMENTID适合嵌套以下查询的所有标签。

DECLARE @Comma_delimited_tag_list VARCHAR(500) = 'Some Tag,Another Tag'
DECLARE @Delimiter VARCHAR(1) = ','

SELECT
        A.*
    FROM ASSIGNMENTS A
        LEFT JOIN
        (
            SELECT
                    A.ASSIGNMENTID
                FROM [dbo].[Split](@Comma_delimited_tag_list, @Delimiter) B
                    FULL JOIN ASSIGNMENTS A ON 1 = 1
                    LEFT JOIN ASSIGNMENT_TAGS AT ON AT.ASSIGNMENTID = A.ASSIGNMENTID AND AT.TAGNAME = B.Data
                WHERE
                    AT.ASSIGNMENTID IS NULL
        ) B
        ON A.ASSIGNMENTID = B.ASSIGNMENTID
    WHERE
        B.ASSIGNMENTID IS NULL


ASSIGNMENTID | ASSIGNMENTNAME
------------ | --------------
1            | Assignment 1

适用于任何@Delimiter值的列表。

希望它适合你。