将if语句中的这两个计数比较合并到一个查询中以消除游标

时间:2018-04-16 19:47:41

标签: sql sql-server performance

我知道我应该避免使用光标,但我正在努力解决这个问题。所以我认为如果我在优化之前有一些工作是最好的。我的目标是在没有孩子收到电子邮件的情况下更新所有孩子。这意味着如果有任何电子邮件,则不会更新任何孩子。

scons
SCons import failed. Unable to find engine files in:
  C:\Users\D\Anaconda3\envs\py36\Scripts\..\engine
  C:\Users\D\Anaconda3\envs\py36\Scripts\scons-local-3.0.1
  C:\Users\D\Anaconda3\envs\py36\Scripts\scons-local
  C:\Users\D\Anaconda3\scons-3.0.1
  C:\Users\D\Anaconda3\Lib\site-packages\scons-3.0.1
  C:\Users\D\Anaconda3\scons
  C:\Users\D\Anaconda3\Lib\site-packages\scons
Traceback (most recent call last):
  File "C:\Users\D\Anaconda3\envs\py36\Scripts\scons.py", line 192, in <module>
    import SCons.Script
ImportError: No module named 'SCons'

这当然非常慢,所以我尝试使用DECLARE @familyId INT DECLARE @childId INT DECLARE @famEmail NVARCHAR DECLARE famEmailCursor CURSOR FAST_FORWARD READ_ONLY FOR SELECT ID, Email, ChildId FROM #family OPEN famEmailCursor FETCH NEXT FROM famEmailCursor INTO @familyId, @famEmail, @childId WHILE @@FETCH_STATUS = 0 BEGIN -- Check if none of the children have an email address IF((SELECT COUNT(*) FROM #family f INNER JOIN Children a ON a.ID = f.ChildId WHERE f.ID = @familyId AND (RTRIM(LTRIM(a.Email)) = '' OR a.Email IS NULL)) = (SELECT COUNT(*) FROM #family fa WHERE fa.ID = @familyId)) BEGIN -- Update email UPDATE Children SET Email = @famEmail WHERE ID = @childId END FETCH NEXT FROM famEmailCursor INTO @familyId, @famEmail, @childId END GROUP BY组合来优化它,但每次我遇到问题之前我都会遇到实际执行的查询。

如何摆脱光标,并可能在一个查询中执行此操作?

按要求提供一些示例数据。

HAVING

2 个答案:

答案 0 :(得分:1)

好的,处理复杂查询时最有价值的事情之一就是将心理上的任务分解为子查询。

所以,首先:让我们得到一个简单的查询,只列出每个孩子以及他们是否有电子邮件地址:

select id as ChildID,
    case when (RTRIM(LTRIM(a.Email)) = '' OR a.Email IS NULL)
        then 1 else 0 end as HasEmail

...接下来,让我们将其与家庭表联系起来,并使用之前的查询作为子查询来获取子项的计数和电子邮件地址的数量:

select f.ID as familyID, sum(HasEmail) as emails, count(hasEmail) as total
from
#family f
JOIN
(
    select id as ChildId,
        case when (RTRIM(LTRIM(a.Email)) = '' OR a.Email IS NULL)
            then 1 else 0 end as HasEmail
) as childEmailSubQ
ON f.ChildId = childEmailSubQ.ChildID
group by f.ID

到目前为止有意义吗?现在我们有一个包含三个字段的查询:

  • 家庭ID
  • 有电子邮件地址的儿童人数
  • 家庭中的孩子数

现在我们也可以将它用作子查询:

select familyID
from
(
    -- that text from the previous query)
) childrenEmailCountsSubquery
where emails = 0

该子查询为我们提供了一个列表,其中列出了所有未在其子女中拥有单个电子邮件地址的家庭。就个人而言,它变得足够复杂,我只是创建一个临时表来存储数据:

declare @familiesWithNoChildrenHavingEmail table (FamilyID int)
insert into @familiesWithNoChildrenHavingEmail
-- the previous SQL command

...然后,您只需使用该表更新语句。

有意义吗?您不是试图在一个大型查询中解决它,而是将事情分解为具体步骤(您甚至可以通过描述性子查询/表命名来记录您的流程!)

答案 1 :(得分:0)

听起来你正在寻找这样的东西:

UPDATE a
set a.email=b.email 
from Children a
join #family b on a.id=b.id
where b.email is null

根据您的需要调整逻辑,如果这不是您想要的