加入两个父表,其中所有孩子都需要匹配

时间:2011-10-14 23:07:17

标签: sql join relational-division

我有2个表共享一个“类型”的公用表 类型表如下:

CREATE TABLE [ModifierType](
[ModifierTypeID] [int] NOT NULL,
[Code] [varchar](10) NOT NULL,
[Name] [varchar](50) NOT NULL,)

CREATE TABLE [UserRequest](
[UserRequestID] [int] NOT NULL,
[Name] [varchar](50) NOT NULL,)

CREATE TABLE [Matrix](
[MatrixID] [int] NOT NULL,
[Name] [varchar](50) NOT NULL,)

CREATE TABLE [UserRequestModifier](
[UserRequestModifierID] [int] NOT NULL,
[UserRequestID] [int] NOT NULL,
[ModifierTypeID] [int] NOT NULL,
[Value] [varchar](50) NOT NULL,)

CREATE TABLE [MatrixModifier](
[MatrixModifierID] [int] NOT NULL,
[MatrixID] [int] NOT NULL,
[ModifierTypeID] [int] NOT NULL,
[Value] [varchar](50) NOT NULL,)

其他是UserRequestModifier表,并且“MatrixModifier”表包含用于确定对请求的访问的规则应该被配置。在这种情况下,Matrix只是指一组规则,它们将授予对特定应用程序或组的访问权限。这两个表都有一个ModifierTypeID,用于链接这两个表以及一个用于查找匹配项的值字段。

但是,每个UserRequest / Matrix(修饰符表的父项)都可以有多个修饰符记录。

我需要做的是找到UserRequestModifiers满足所有MatrixModifier要求的所有Matrix记录。基本上,我想忽略任何具有1个修饰符值且与任何UserRequestModifier值都不匹配的MatrixID。

到目前为止,我有一个查询可以做到这一点,但它似乎有点倒退,因为我必须首先找到UserRequestModifiers不满足subselect中的要求的所有MatrixID。然后获取不在那些结果中的记录如下:

SELECT 
    UR.[UserRequestModifierID]
    ,UR.[ModifierTypeID]        
    ,UR.[Value] AS [URValue]
    ,MM.[Value] AS [MMValue]
    ,MM.[MatrixModifierID]
    ,MM.[MatrixID]
    ,MM.[ModifierTypeID]        
    ,M.[MatrixID]       
FROM
    AMP.[UserRequestModifier] AS UR
LEFT OUTER JOIN AMP.[MatrixModifier] AS MM
    ON (MM.[ModifierTypeID] = UR.[ModifierTypeID])
LEFT OUTER JOIN AMP.[Matrix] AS M
WHERE
    UR.[UserRequestID] = @UserRequestID
    AND M.[MatrixID] IS NOT NULL
    AND M.[MatrixID] NOT IN
        (SELECT
            DISTINCT MM.[MatrixID]      
        FROM
            AMP.[UserRequestModifier] AS UR
        LEFT OUTER JOIN AMP.[MatrixModifier] AS MM
            ON (MM.[ModifierTypeID] = UR.[ModifierTypeID])
        WHERE
            UR.[UserRequestID] = @UserRequestID
            AND (CASE WHEN LTRIM(RTRIM(MM.[Value])) = LTRIM(RTRIM(UR.[Value])) THEN 1 ELSE 0 END) = 0
            AND MM.[MatrixID] IS NOT NULL)
ORDER BY M.[MatrixID], MM.[ModifierTypeID]

我知道这有点难以理解,但我希望有人可以指出一些我不知道的事情。

2 个答案:

答案 0 :(得分:1)

正如马丁史密斯指出的那样,这是一个关系分裂问题。我认为,解决这个问题的一种方法是:

SELECT
    M.*
FROM
    Matrix AS M
  LEFT JOIN
    MatrixModifier AS MM
        ON MM.MatrixID = M.MatrixID
  LEFT JOIN 
    UserRequestModifier AS URM
        ON URM.ModifierTypeID = MM.ModifierTypeID
GROUP BY
    M.MatrixID
HAVING
    COUNT(DISTINCT MM.ModifierTypeID) = COUNT(DISTINCT URM.ModifierTypeID)

答案 1 :(得分:0)

对于MS SQL Server:

-- ====================
-- sample data
-- ====================
DECLARE @ModifierType TABLE (
[ModifierTypeID] [int] NOT NULL,
[Code] [varchar](10) NOT NULL,
[Name] [varchar](50) NOT NULL)

DECLARE @UserRequest TABLE (
[UserRequestID] [int] NOT NULL,
[Name] [varchar](50) NOT NULL)

DECLARE @Matrix TABLE (
[MatrixID] [int] NOT NULL,
[Name] [varchar](50) NOT NULL)

DECLARE @UserRequestModifier TABLE (
[UserRequestModifierID] [int] NOT NULL,
[UserRequestID] [int] NOT NULL,
[ModifierTypeID] [int] NOT NULL,
[Value] [varchar](50) NOT NULL)

DECLARE @MatrixModifier TABLE (
[MatrixModifierID] [int] NOT NULL,
[MatrixID] [int] NOT NULL,
[ModifierTypeID] [int] NOT NULL,
[Value] [varchar](50) NOT NULL)

insert into @modifiertype
select 1, '1', 'modname1'
union all
select 2, '2', 'modname2'
union all
select 3, '3', 'modname3'
union all
select 4, '4', 'modname4'
union all
select 5, '5', 'modname5'
union all
select 6, '6', 'modname6'

insert into @userrequest
select 1, 'ureq1'
union all
select 2, 'ureq2'
union all
select 3, 'ureq3'
union all
select 4, 'ureq4'

insert into @matrix
select 1, 'm1'
union all
select 2, 'm2'
union all
select 3, 'm3'
union all
select 4, 'm4'


insert into @userrequestmodifier
select 1, 1, 1, 'val1'
union all
select 2, 1, 2, 'val2'
union all
select 3, 1, 3, 'val3'
union all
select 4, 1, 4, 'val4'
union all
select 5, 2, 5, 'val5'
union all
select 6, 1, 5, 'val5'
union all
select 7, 1, 6, 'val6'
union all
select 8, 1, 6, 'val6'




insert into @matrixmodifier
select 1, 1, 1, 'val1'
union all
select 2, 2, 2, 'val2'
union all
select 3, 3, 3, 'val'
union all
select 4, 2, 4, 'val4'
union all
select 5, 2, 5, 'val5'
union all
select 6, 3, 4, 'val4'
union all
select 7, 13, 4, 'val4'

declare @UserRequestID int
set @UserRequestID = 1


-- ====================
-- solution
-- ====================
select
    userrequestmodifierid,
    modifiertypeid,
    urvalue,
    mmvalue,
    matrixmodifierid,
    mmmatrixid,
    mmatrixid
from
(
    select 
        urm.userrequestmodifierid,
        urm.modifiertypeid,
        urvalue = urm.value,
        mmvalue = mm.value,
        mm.matrixmodifierid,
        mmmatrixid = mm.matrixid,
        mmatrixid = m.matrixid,
        f = max(case when urm.value != mm.value then 1 end) over (partition by mm.matrixid)
    from @userrequestmodifier urm
    left join @matrixmodifier mm on
        urm.modifiertypeid = mm.modifiertypeid
    left join @matrix m on
        m.matrixid = mm.matrixid
    where urm.userrequestid = @userrequestid
) t
where f is null or mmatrixid is null