T-SQL - 使用顺序查询多对多关系表

时间:2017-04-11 19:32:58

标签: sql sql-server database many-to-many

我有一个包含关联数据的表。它有三列SubjectId,StudentId和Rank。它是一个多对多关系表。我需要找到对应于排名顺序的给定StudentId列表的SubjectId。

如果订单不重要,我会做类似的事情

SELECT SubjectId
FROM mytable
WHERE StudentId IN (a,b,c) --This is the 'input'. I want order here to make a difference by matching to 'rank' but in this version it doesn't
GROUP BY SubjectId
HAVING COUNT(1) = 3

这也将返回具有学生等级的SubjectIds(a,c,b),(b,c,a)等。

如果a,b,c的顺序很重要,我该如何做同样的事?

修改:包含样本数据和预期结果

示例数据

SubjectId | StudentId | Rank
1|a|2
1|c|1
1|b|3
2|c|1
2|b|2
3|c|2
3|b|1
4|a|1
4|b|2
5|b|2
5|a|1

预期结果 输入:(c,a,b) 输出:1

输入:(c,a) 输出:NULL(无行)

输入:(c,b) 输出:2

输入:(a,b) 输出:4,5 - 单独的行

输入:(a,b,c) 输出:NULL(无行)

2 个答案:

答案 0 :(得分:2)

您需要先将输入插入包含RankStudentId的表格。我想出了一种方法,你可以做到这一点,而无需解析csv。它使用输入中CHARINDEX的{​​{1}}。请注意,如果您的输入值不在表中,则会被忽略。当然你可以解析csv而不是你。

在表中输入后,您需要做的就是将输入加入到表中以仅获取与输入匹配的记录。然后StudentId并获取与您输入中的记录具有相同计数的GROUP BY SubjectId,并将与您表格中SubjectId的记录相同的计数。

所有答案都是这样的。 (出于某种原因SubjectId无法保存,所以我做了(*))。

(* )

上一个答案:MySQL并不包括评论请求。 Example Code

答案 1 :(得分:1)

由于我对@ fqhv的答案的编辑遭到拒绝,我在借用他的时候扩展了我之前的答案:

DECLARE @CommaSeparatedStudentIds varchar(max) = 'c,a';

DECLARE @InputTable AS TABLE (
    [Rank] INT IDENTITY(1,1),
    StudentId VARCHAR(25) --make this match your StudentID field
    )

INSERT INTO @InputTable (StudentId)
SELECT value from STRING_SPLIT(@CommaSeparatedStudentIds,',')

/* If STRING_SPLIT isn't available, you can do this other ways (see after code) */

Select
    t.SubjectId
from
    MyTable t
    FULL OUTER JOIN @InputTable i ON
        t.StudentId = i.StudentId AND
        t.Rank = i.Rank
group by
    t.SubjectId
having
    count(*) = sum(case when t.Rank = i.Rank then 1 else 0 end)

有关STRING_SPLIT的替代方案,请参阅此帖子:  Split function equivalent in T-SQL?

如果我们在MySQL中,您在评论中添加的修改版本可以很好地运行:

set @CommaSeparatedStudentIds = 'a,b';

SELECT
t.SubjectId
FROM
MyTable t
group by t.SubjectId
HAVING GROUP_CONCAT(t.StudentId order by t.Rank SEPARATOR ',') = @CommaSeparatedStudentIds