连接两个表时优化SQL查询。朴素算法为我提供了数百万行

时间:2018-04-04 13:59:11

标签: sql sql-server tableau

我道歉,我不确定如何说出这个问题的标题。如果有人可以为我改革,以便更好地适应我的要求,我将不胜感激。

我有一个很长的问题,我被困在了最长的时间。我将Tableau与SQLServer 2014结合使用。

我有一张表,基本上显示了我们公司内的所有员工。他们的雇用日期和终止日期(如果仍然使用,则为NULL)。我希望能够产生过去的人数。以下是此表的示例:

employeeID    HireDate    TermDate    FavouriteFish    FavouriteColor
    1           1/1/15     1/1/18         Cod               Blue
    2           4/12/16     NULL          Bass              Red
    .
    .
    .
    n

正如你所看到的,这个列表可以继续下去。实际上,我所讨论的表格目前有超过10000行供所有过去和现在的员工使用。

我的目标是构建一个视图,以查看过去5年中每年的每一天我们雇用的员工总人数。以下是踢球者......我需要保留其余的信息,例如:

FavouriteFish    FavouriteColor... and so on

我能想到这样做的唯一方法是,它工作得非常好,因为它非常慢,是为过去5年的每一天创建一个单独的日历表;像这样:

Date       CrossJoinKey
1/1/2013        1
1/2/2013        1
1/3/2013        1
    .
    .
    .
4/4/2018        1

从这里开始,我在原来的Employee Table中添加了一个列:CrossJoinKey;像这样......

employeeID    HireDate    TermDate    FavouriteFish    FavouriteColor    CrossJoinKey
    1           1/1/15     1/1/18         Cod               Blue            1
    2           4/12/16     NULL          Bass              Red             1
    .
    .
    .
    n

从这里我创建一个LEFT JOIN Calendar ON Employee.CrossKeyJoin=Calendar.CrossKeyJoin

希望在这里你可以立即看到问题..它与很多行创造了一种关系!事实上它给了我大约1800万行。它为我提供了我所追求的信息,但是查询需要很长时间,当我将其导入Tableau以创建提取时,它也需要很长时间才能完成。但是,一旦Tableau最终创建了提取它比较快我可以使用内部胆量来隔离并在过去5年内创建一个人数...通过查看date字段是否在termDateHireDate之间。但是整个过程需要经常进行,我觉得当前的方法不实用。

我觉得这是一种天真的方式来完成我所追求的目标,我觉得这个问题必须在过去之前得到解决。这里有没有人能够对如何优化这一点有所了解?

值得注意的是......我已经考虑过本质上创建一个查询,通过查看员工表并“计算”仍然使用的每个员工来填充日历表,但这种方法失去了解决方案,我无法保留员工的任何其他数据。

这样的东西,如下所示,效果更好,但不是我想要的东西:

Date       HeadCount
1/1/2013        1200
1/2/2013        1201
1/3/2013        1200
    .
    .
    .
4/4/2018        5000

非常感谢你花了一些时间。

更新: 这是指向google sheets data sample

的链接

1 个答案:

答案 0 :(得分:0)

我已经编辑了一些数据,您可以在@example表中看到。

我想注意:你要么拼写= D喜欢或颜色不正确,请更正它,要么是FavoriteColor,要么是FavouriteColour。

declare @example as table (
    exampleid int identity(1,1) not null primary key clustered
,   StartDate date not null
,   TermDate  date null
);

insert into @example (StartDate, TermDate)
select '1/1/2016',  '1/1/2018' union all
select '4/3/2017',  '1/10/2018' union all
select '9/3/2016',  '2/4/2018' union all
select '5/9/2017',  '11/21/2017' union all
select '9/18/2016', '11/15/2017' union all
select '12/12/2015', '2/8/2018' union all
select '6/18/2016', '12/20/2017' union all
select '7/26/2015', '11/4/2017' union all
select '1/7/2015',  NULL union all
select '10/2/2013', '10/21/2013' union all
select '10/14/2013',    '12/12/2017' union all
select '10/11/2013',    '11/3/2017' union all
select '6/30/2015', '1/12/2018' union all
select '2/17/2016', NULL union all
select '8/12/2015', '11/26/2017' union all
select '12/2/2015', '11/15/2017' union all
select '3/30/2016', '11/30/2017' union all
select '6/18/2016', '11/9/2017' union all
select '4/3/2017',  '2/12/2018' union all
select '3/26/2017', '1/15/2018' union all
select '1/27/2017', NULL union all
select '7/29/2016', '1/10/2018';

  --| This is an adaption of Aaron Bertrand's work (time dim table)
  --| this will control the start date

  declare @date datetime = '2013-10-01';

   ;with cte as (
             select 1 ID
               , @date date_
           union all

          select ID + 1
               , dateadd(day, 1, date_)
            from cte
                  )
            , cte2 as (
          select top 1000 ID
               , cast(date_ as date) date_
               , 0 Running
               , iif(datepart(weekday, date_) in(1,7), 0,1) isWeekday
               , datepart(weekday, date_) DayOfWeek
               , datename(weekday, date_)  DayOfWeekName
               , month(date_) Month
               , datename(month, date_) MonthName
               , datepart(quarter, date_) Quarter
            from cte 
          --option (maxrecursion 1000)
                    )
        , cte3 as (
        select a.id 
             , Date_
             , b.StartDate
             , iif(b.StartDate is not null, 1, 0) Add_
             , iif(c.TermDate is not null, -1, 0) Remove_
          from cte2 a
          left join @example b
            on a.date_ = b.StartDate
          left join @example c
            on a.date_ = c.TermDate
         -- option (maxrecursion 1000)
                    )

        select date_
             --, Add_
             --, Remove_
             , sum((add_ + remove_)) over (order by date_ rows unbounded preceding) CurrentCount
             from cte3
            option (maxrecursion 1000)
  

结果集:

date_       CurrentCount
2013-10-01  0
2013-10-02  1
2013-10-03  1
2013-10-04  1
2013-10-05  1