使用JOIN中的大小写而不是SELECT查询语句中的大小写进行更快的SQL查询?

使用JOIN中的大小写而不是SELECT查询语句中的大小写进行更快的SQL查询?,sql,sql-server,Sql,Sql Server,我有一个社区成员的视图,其中每个成员都有ID的主键。一些成员还有来自另一个系统的旧ID,一些成员有配偶ID。所有ID都是唯一的 e、 g: 我还有一个ActivityDates视图,每个社区成员都可以有多个活动日期。旧身份证和配偶身份证都有活动日期。不幸的是,我无法通过将旧ID转换为新ID来清理数据 e、 g: 我可以使用以下方法以我需要的方式选择数据,即运行3次多个案例选择以检查3个可能的ID,尽管速度非常慢,因为它在每个记录上运行多次选择查询: SELECT C.ID,

我有一个社区成员的视图,其中每个成员都有ID的主键。一些成员还有来自另一个系统的旧ID,一些成员有配偶ID。所有ID都是唯一的

e、 g:

我还有一个ActivityDates视图,每个社区成员都可以有多个活动日期。旧身份证和配偶身份证都有活动日期。不幸的是,我无法通过将旧ID转换为新ID来清理数据

e、 g:

我可以使用以下方法以我需要的方式选择数据,即运行3次多个案例选择以检查3个可能的ID,尽管速度非常慢,因为它在每个记录上运行多次选择查询:

SELECT 
    C.ID, 
    C.Name,
    C.OldID,
    C.SpouseID,
    C.SpouseName,
    CASE 
       WHEN C.ID (SELECT ID FROM ActivityDates WHERE ActivityDate > 2016-12-31 AND ActiviyType = 1 AND ActiviyGroup = 1)
            AND NOT EXISTS (SELECT ID FROM ActivityDates WHERE ActivityDate > 2016-12-31 AND ActiviyType > 1 AND ActiviyGroup > 1)
            OR C.OldID (SELECT ID FROM ActivityDates WHERE ActivityDate > 2016-12-31 AND ActiviyType = 1 AND ActiviyGroup = 1)
            AND NOT EXISTS (SELECT ID FROM ActivityDates WHERE ActivityDate > 2016-12-31 AND ActiviyType > 1 AND ActiviyGroup > 1)
            OR C.SpouseID (SELECT ID FROM ActivityDates WHERE ActivityDate > 2016-12-31 AND ActiviyType = 1 AND ActiviyGroup = 1)
            AND NOT EXISTS (SELECT ID FROM ActivityDates WHERE ActivityDate > 2016-12-31 AND ActiviyType > 1 AND ActiviyGroup > 1)
          THEN 'Yes' 
          ELSE '' 
       END AS Result i.e. HasTheCommunityMemberOrTheirSpouseOnlyEverAttendedActivityTypeAndGroup1After2016?
因此,我希望得到以下结果,我得到的结果,只是速度很慢:

ID | Name         | OldID   | SpouseID  | SpouseName   | Result
1  | John.Smith   | o71     | s99       | Jenna.Smith  | 
2  | Jane.Doe     | o72     |           |              | Yes
3  | Jessie.Jones |         |           |              | Yes
我很感激有更好的方法来做到这一点,我很高兴听到建议,尽管我在改变这个系统方面的灵活性有限,所以我想问的是,我如何才能更快地做到这一点?理想情况下,我希望使用表的联接,并使用条件,尽管我无法计算出它。e、 g

SELECT 
    C.ID, C.Name,
    C.OldID, C.SpouseID, C.SpouseName,
    R.Result
FROM 
    CommunityMembers C
JOIN 
    CASE WHEN Date ... Type ... Group ... ELSE ... IN ... Not Exist ... THEN ... ActivityDates R

我怀疑我需要进行多个联接,尽管我不知道如何编写它


谢谢

索引如下:

CREATE INDEX index_name
ON table_name (column1, column2, ...);

有关更多详细信息,请参见此

这里是另一种利用“可选联接”的模式,它可能会或可能不会表现得更好。这和你的输出不太一样——我不确定你在追求什么

SELECT A.*,
COALESCE(C1.Name, C2.Name, C3.Name) As Name
FROM  ActivityDates  A
LEFT OUTER JOIN CommunityMember As C1
ON C1.ID = A.ID
LEFT OUTER JOIN CommunityMember As C2
ON C2.OldID = CAST(A.ID AS VARCHAR(12))
LEFT OUTER JOIN CommunityMember As C3
ON C2.SpouseID = CAST(A.ID AS VARCHAR(12))

在某些情况下,这将“重复计算”,但如果您确定整个id集合是唯一的,您应该可以。如果您只想知道活动记录是否存在,您肯定可以使用exists加快速度,但我不遵循您的逻辑。

您需要每个ID的表ActivityDates中的信息。因此,请按ID分组并筛选所需ID:

您可以将其与EXISTS子句一起使用:

可以使用适当的索引来加速此过程

create index idx1 on ActivityDates (ID, ActivityDate, ActivityType, ActivityGroup);

create index idx2 on ActivityDates (ActivityDate, ID, ActivityType, ActivityGroup);
找出其中一个是否被使用,如果没有一个被使用,则删除另一个或两者

使用非相关子查询(这意味着我们必须多次访问它)可能会执行得更好。如果涉及到不同的执行计划,这取决于优化器:

with good_ids as
(
  select id 
  from activitydates
  where activitydate > '2016-12-31'
  group by id
  having count(case when activiytype = 1 and activiygroup = 1 then 1 end) > 1
     and count(case when activiytype > 1 and activiygroup > 1 then 1 end) = 0
)
select
  c.*,
  case when id       in (select id from good_ids)
         or oldid    in (select id from good_ids)
         or spouseid in (select id from good_ids)
       then 'Yes' else ''
  end as result
from c;

你应该试着解释一下结果。很难找到正确的业务。从错误的查询中删除规则

这样您就可以从这里得到最好的查询。只需再次尝试解释为什么id 2,3是“是”。然后我将重写我的查询

你将要犯的第二大错误是不了解你的业务。如果不编写正确的查询,您将创建索引

试试这个

declare @t table(ID varchar(20),Name varchar(40),OldID varchar(20), SpouseID  varchar(20)
, SpouseName varchar(40))
insert into @t VALUES
('1','John.Smith','o71' ,'s99','Jenna.Smith')
,('2','Jane.Doe' ,'o72',null,null)
,('3','Jessie.Jones',null,null,null)       

--select * from @t
declare @ActivityDates table(ID varchar(20), ActivityDate date
, ActiviyType int, ActivityGroup int)
insert into @ActivityDates VALUES
('1','2017-12-31',1, 1)
,('1','2017-12-31',3, 2)
,('1','2017-12-31',7, 1)
,('2','2017-12-31',1, 1)
,('3','2017-12-31',1, 1)
,('o72','2010-12-31',1, 2)
,('o72','2010-12-31',3, 1)
,('s99','2017-12-31',1, 1)
,('s99','2017-12-31',2, 1)

SELECT t.*
,case when tbl.id is not null then 'Yes' else null end Remarks
 from @t t
left JOIN
(select * from @ActivityDates AD
 WHERE(( ActivityDate > '2016-12-31' AND ActiviyType = 1 AND ActivityGroup = 1
 AND NOT EXISTS (SELECT ID FROM @ActivityDates ad1 WHERE (ad.id=ad1.id) AND
  ActivityDate > '2016-12-31' AND (ActiviyType > 1 or ActivityGroup > 1))
 )
  ))tbl
  on t.ID=tbl.ID

你有索引吗?我不知道什么是索引,所以我怀疑我没有索引?如果你没有索引,你的查询问题是你需要将ActivityDates移动到左联接。谢谢,我该如何写?在ActivityDates ID、ActivityDate、ActivityType、ActivityGroup上创建索引名称;选择C.ID、C.Name、C.OldID、C.SpooseId、C.SpooseName、C.ID从ActivityDates中选择ID时的大小写。。。。。。。。。。。。。。。另外,如果CommunityMembers和ActivityDates都是一个视图,是否有问题?您可以在您的工作数据库本身中执行此操作。。通过查询。。在你的工作台上做
SELECT ID 
FROM ActivityDates
WHERE ActivityDate > '2016-12-31'
GROUP BY ID
HAVING COUNT(CASE WHEN ActiviyType = 1 AND ActiviyGroup = 1 THEN 1 END) > 1
   AND COUNT(CASE WHEN ActiviyType > 1 AND ActiviyGroup > 1 THEN 1 END) = 0
select
  c.*, 
  case when exists 
  (
    SELECT a.ID 
    FROM ActivityDates a
    WHERE a.ActivityDate > '2016-12-31'
      AND a.ID in (c.id, c.oldid, c.spouseid)
    GROUP BY a.ID
    HAVING COUNT(CASE WHEN ActiviyType = 1 AND ActiviyGroup = 1 THEN 1 END) > 1
       AND COUNT(CASE WHEN ActiviyType > 1 AND ActiviyGroup > 1 THEN 1 END) = 0
) then 'Yes' else '' end as result
from c;
create index idx1 on ActivityDates (ID, ActivityDate, ActivityType, ActivityGroup);

create index idx2 on ActivityDates (ActivityDate, ID, ActivityType, ActivityGroup);
with good_ids as
(
  select id 
  from activitydates
  where activitydate > '2016-12-31'
  group by id
  having count(case when activiytype = 1 and activiygroup = 1 then 1 end) > 1
     and count(case when activiytype > 1 and activiygroup > 1 then 1 end) = 0
)
select
  c.*,
  case when id       in (select id from good_ids)
         or oldid    in (select id from good_ids)
         or spouseid in (select id from good_ids)
       then 'Yes' else ''
  end as result
from c;
declare @t table(ID varchar(20),Name varchar(40),OldID varchar(20), SpouseID  varchar(20)
, SpouseName varchar(40))
insert into @t VALUES
('1','John.Smith','o71' ,'s99','Jenna.Smith')
,('2','Jane.Doe' ,'o72',null,null)
,('3','Jessie.Jones',null,null,null)       

--select * from @t
declare @ActivityDates table(ID varchar(20), ActivityDate date
, ActiviyType int, ActivityGroup int)
insert into @ActivityDates VALUES
('1','2017-12-31',1, 1)
,('1','2017-12-31',3, 2)
,('1','2017-12-31',7, 1)
,('2','2017-12-31',1, 1)
,('3','2017-12-31',1, 1)
,('o72','2010-12-31',1, 2)
,('o72','2010-12-31',3, 1)
,('s99','2017-12-31',1, 1)
,('s99','2017-12-31',2, 1)

SELECT t.*
,case when tbl.id is not null then 'Yes' else null end Remarks
 from @t t
left JOIN
(select * from @ActivityDates AD
 WHERE(( ActivityDate > '2016-12-31' AND ActiviyType = 1 AND ActivityGroup = 1
 AND NOT EXISTS (SELECT ID FROM @ActivityDates ad1 WHERE (ad.id=ad1.id) AND
  ActivityDate > '2016-12-31' AND (ActiviyType > 1 or ActivityGroup > 1))
 )
  ))tbl
  on t.ID=tbl.ID