SQL 根据类型字段加入两个实体

SQL join two entities depending on type field

在我使用 MSSQL Server 2016 的 Microsoft Dynamics CRM 2016(本地)中,我尝试创建一个报告(使用 ReportServer),它提供所有开放机会的最新活动:

我想找到机会 (FilteredOpportunity) 最近的 activity(即 FilteredActivityPointer)。这个问题的第一个(也是简单的)解决方案(使用 MSSQL 的高性能查询)是这样提供的:

现在我需要像下面这样扩展场景(遍历从 activity 到机会的 2 条备选路径):

FilteredActivityPointer 包含一个名为 referenceobjecttypecode 的字段:该字段包含: * 1 用于与活动相关的活动,在这种情况下,字段 referenceobjectid 包含帐户的 id * 2 对于与联系人相关的活动,在这种情况下,字段 referenceobjectid 包含联系人的 ID

如何扩展以下查询...

SELECT opp.opportunityid, opp.name as OpportunityName, opp.statecode, opp.statecodename, fac.accountid, fac.name As AccountName, fa.regardingobjecttypecode, fa.activitytypecodename, fa.owneridname, fa.actualend As DateCompleted, fa.description As ActivityDescription
FROM FilteredAccount fac cross apply
     (SELECT TOP 1 *
      FROM FilteredActivityPointer fa
      WHERE fa.regardingobjectid = fac.accountid and fa.statecode = 1 and fa.regardingobjecttypecode=1
      order by fa.actualend desc
     ) fa
JOIN FilteredOpportunity as opp
    ON fac.accountid = opp.accountid
    WHERE opp.statecode = 0

... 这样我就可以通过加入帐户和加入 opps 通过加入联系人、加入帐户加入帐户来获得最新的 FilteredActivityPointer。

我不知道如何才能做到这一点 我这样试过,但我迷路了:

SELECT opp.opportunityid, opp.name as OpportunityName, opp.statecode, opp.statecodename, fac.accountid, fac.name As AccountName, fa.regardingobjecttypecode, fa.activitytypecodename, fa.owneridname, fa.actualend As DateCompleted, fa.description As ActivityDescription
FROM FilteredAccount fac cross apply
     (SELECT TOP 1 *
      FROM FilteredActivityPointer fa
      WHERE fa.regardingobjectid = fac.accountid and fa.statecode = 1 and fa.regardingobjecttypecode=1
      order by fa.actualend desc
     ) fa

    FilteredAccount fac2 cross apply
     (SELECT TOP 1 *
      FROM FilteredActivityPointer fa2
      join FilteredContact as co
      ON fa2.regardingobjectid = co.contactid and fa2.regardingobjecttypecode = 2
      join FilteredAccount as ac
      on ac.accountid = opp.account.id;
      WHERE fa.statecode = 1 
      order by fa.actualend desc
     ) fa2

JOIN FilteredOpportunity as opp
    ON fac.accountid = opp.accountid
    WHERE opp.statecode = 0

我试图在我的 MicrosoftDynamics CRM 2016 中找到所有开放机会 (FilteredOpportunity) 的最新 activity (FilteredActivity)。听起来很简单实际上相当复杂,因为活动可能与联系人或直接相关机会。所以这个问题归结为我如何组合两个结果集的问题,然后 select 最近的 activity 出两个结果集的组合: * 每个机会提供最新的 activity * 为每个帐户(每个联系人)

提供最新的 activity

这需要工会。为了理解整个问题,我在下图中可视化了关系。:

对于结果集 1 Gordon Linoff and delivery this very efficient : 对于结果集 2 GMB delivered a very clever

两个结果都是有效的并且非常高效。两个结果集都可以设计为提供相同的结构:与机会相关的活动。

因此,对于结果集 1,我准备了以下查询:

select fac.name as accountname, fa.actualend, fa.description, fa.activitytypecodename, fa.activitytypecode, fac.accountid, opp.opportunityid, opp.name as opportunityname
from FilteredAccount fac cross apply
     (select top (1) fa.*
      from FilteredActivityPointer fa
      where fa.regardingobjectid = fac.accountid and fa.statecode = 1 and fa.activitytypecode != 10004      
      order by fa.actualend desc
     ) fa
Join FilteredOpportunity opp on opp.accountid = fac.accountid and opp.statecode = 0

对于结果集 2,我准备了以下查询:

select t.name as accountname, t.actualend, t.description, t.activitytypecodename, t.activitytypecode, t.accountid, t.opportunityid, t.opportunityname
from (
    select ac.accountid, opp.name as opportunityname, opp.opportunityid, ac.name, fa.actualend, fa.description, fa.activitytypecodename, fa.activitytypecode, row_number() over(partition by ac.accountid order by fa.actualend desc) rn
    from FilteredContact co 
    inner join FilteredActivityPointer fa
        on  fa.regardingobjectid = co.contactid 
        and fa.regardingobjecttypecode = 2
        and fa.activitytypecode != 10004        
    inner join FilteredAccount ac 
        on  ac.accountid = co.accountid 
    inner join FilteredOpportunity opp 
        on  opp.accountid = ac.accountid 
        and opp.statecode = 0
) t
where rn = 1

我尝试用相同的列名排列结果集。

现在我使用 union 合并两个结果集:

select allactivities.accountname as accountname, allactivities.actualend, allactivities.description, allactivities.activitytypecodename, allactivities.activitytypecode, allactivities.accountid, allactivities.opportunityid, allactivities.opportunityname
from 
(
    (select fac.name as accountname, fa.actualend, fa.description, fa.activitytypecodename, fa.activitytypecode, fac.accountid, opp.opportunityid, opp.name as opportunityname
    from FilteredAccount fac cross apply
         (select top (1) fa.*
          from FilteredActivityPointer fa
          where fa.regardingobjectid = fac.accountid and fa.statecode = 1 and fa.activitytypecode != 10004      
          order by fa.actualend desc
         ) fa
    Join FilteredOpportunity opp on opp.accountid = fac.accountid and opp.statecode = 0
    )
Union
    (select t.name as accountname, t.actualend, t.description, t.activitytypecodename, t.activitytypecode, t.accountid, t.opportunityid, t.opportunityname
    from 
        (
        select ac.accountid, opp.name as opportunityname, opp.opportunityid, ac.name, fa.actualend, fa.description, fa.activitytypecodename, fa.activitytypecode, row_number() over(partition by ac.accountid order by fa.actualend desc) rn
        from FilteredContact co 
        inner join FilteredActivityPointer fa
            on  fa.regardingobjectid = co.contactid 
            and fa.regardingobjecttypecode = 2
            and fa.activitytypecode != 10004        
        inner join FilteredAccount ac 
            on  ac.accountid = co.accountid 
        inner join FilteredOpportunity opp 
            on  opp.accountid = ac.accountid 
            and opp.statecode = 0
        ) t
    where rn = 1
    )
) allactivities

到目前为止,结果似乎还不错。

现在我第二次使用了 "over (partition)" 方法,结果是:

select activity.accountname, activity.actualend, activity.description, activity.activitytypecodename, activity.activitytypecode, activity.accountid, activity.opportunityid, activity.opportunityname
from
    (
        select allactivities.accountname as accountname, allactivities.actualend, allactivities.description, allactivities.activitytypecodename, allactivities.activitytypecode, allactivities.accountid, allactivities.opportunityid, allactivities.opportunityname, row_number() over(partition by allactivities.accountid order by allactivities.actualend desc) row_nr
        from 
        (
            (select fac.name as accountname, fa.actualend, fa.description, fa.activitytypecodename, fa.activitytypecode, fac.accountid, opp.opportunityid, opp.name as opportunityname
            from FilteredAccount fac cross apply
                 (select top (1) fa.*
                  from FilteredActivityPointer fa
                  where fa.regardingobjectid = fac.accountid and fa.statecode = 1 and fa.activitytypecode != 10004      
                  order by fa.actualend desc
                 ) fa
            Join FilteredOpportunity opp on opp.accountid = fac.accountid and opp.statecode = 0
            )
        Union
            (select t.name as accountname, t.actualend, t.description, t.activitytypecodename, t.activitytypecode, t.accountid, t.opportunityid, t.opportunityname
            from 
                (
                select ac.accountid, opp.name as opportunityname, opp.opportunityid, ac.name, fa.actualend, fa.description, fa.activitytypecodename, fa.activitytypecode, row_number() over(partition by ac.accountid order by fa.actualend desc) rn
                from FilteredContact co 
                inner join FilteredActivityPointer fa
                    on  fa.regardingobjectid = co.contactid 
                    and fa.regardingobjecttypecode = 2
                    and fa.activitytypecode != 10004        
                inner join FilteredAccount ac 
                    on  ac.accountid = co.accountid 
                inner join FilteredOpportunity opp 
                    on  opp.accountid = ac.accountid 
                    and opp.statecode = 0
                ) t
            where rn = 1
            )
        ) allactivities
    ) activity
where row_nr = 1

瞧!

请考虑到我在解决方案中添加了 "union"。 Gordon Linoff and GMB 提供了上述问题的真正解决方案。没有那些才华横溢的 SQL 大师的帮助,我做不到!