USP_DATALIST_SEGMENTRETENTION

Retrieves a list of years and their retention for a given segment

Parameters

Parameter Parameter Type Mode Description
@SEGMENTID uniqueidentifier IN Segment ID
@CURRENTAPPUSERID uniqueidentifier IN Input parameter indicating the ID of the current user.
@SECURITYFEATUREID uniqueidentifier IN Input parameter indicating the ID of the feature to use for site security checking.
@SECURITYFEATURETYPE tinyint IN Input parameter indicating the type of the feature to use for site security checking.
@NUMYEARS int IN

Definition

Copy


CREATE procedure dbo.[USP_DATALIST_SEGMENTRETENTION]
(
  @SEGMENTID uniqueidentifier = null,
  @CURRENTAPPUSERID uniqueidentifier = null,
  @SECURITYFEATUREID uniqueidentifier = null,
  @SECURITYFEATURETYPE tinyint = null,
  @NUMYEARS int = 5
)
with execute as owner
as
  set nocount on;

  declare @SEGMENTNAME nvarchar(100);
  declare @SEGMENTIDSETREGISTERID uniqueidentifier;
  declare @RECORDTYPEID uniqueidentifier;
  declare @MARKETINGRECORDTYPE tinyint;
  declare @MAILINGSTABLE table([ID] uniqueidentifier not null, [DATATABLE] nvarchar(128) not null, [MAILINGSEGMENTID] uniqueidentifier not null)
  declare @MAILINGSCOUNT int;
  declare @LISTMATCHBACKTABLE nvarchar(128);
  declare @DATATABLE nvarchar(128);
  declare @MAILINGSEGMENTID uniqueidentifier;
  declare @GIFTIDSETNAME nvarchar(128);
  declare @SQL nvarchar(max);
  declare @PARAMETERS nvarchar(max);
  declare @PRESQL nvarchar(max);
  declare @INNERDONORSQL nvarchar(max);
  declare @INNERLISTSQL nvarchar(max);
  declare @INNERGIFTSQL nvarchar(max);
  declare @DONORSCOUNT int;
  declare @MATCHBACKFIELD nvarchar(20);

  select
    @SEGMENTNAME = [NAME],
    @SEGMENTIDSETREGISTERID = [IDSETREGISTERID],
    @RECORDTYPEID = dbo.[UFN_MKTSEGMENT_GETRECORDTYPE]([ID]),
    @MARKETINGRECORDTYPE = dbo.[UFN_MKTSEGMENT_GETMARKETINGRECORDTYPE]([ID]),
    @MATCHBACKFIELD = (case when [MKTSEGMENT].[SEGMENTTYPECODE] = 3 then '[FINDERNUMBER]' else '[DONORID]' end)  --Revenue segments can only be used in acknowledgement mailings which require finder number instead of donor ID for matchback.

  from dbo.[MKTSEGMENT]
  where [ID] = @SEGMENTID;

  insert into @MAILINGSTABLE
    select distinct
      [MKTSEGMENTATION].[ID],
      dbo.[UFN_MKTSEGMENTATIONACTIVATE_MAKETABLENAME]([MKTSEGMENTATION].[ID]),
      [MKTSEGMENTATIONSEGMENT].[ID]
    from dbo.[MKTSEGMENTATIONSEGMENT]
    inner join dbo.[MKTSEGMENTATION] on [MKTSEGMENTATION].[ID] = [MKTSEGMENTATIONSEGMENT].[SEGMENTATIONID]
    where (dbo.UFN_APPUSER_ISSYSADMIN(@CURRENTAPPUSERID) = 1 or exists (select 1 from dbo.UFN_SITESFORUSERONFEATURE(@CURRENTAPPUSERID,@SECURITYFEATUREID,@SECURITYFEATURETYPE) where SITEID=[MKTSEGMENTATION].[SITEID] or (SITEID is null and [MKTSEGMENTATION].[SITEID] is null)))
    and [MKTSEGMENTATION].[ACTIVE] = 1
    and [MKTSEGMENTATIONSEGMENT].[SEGMENTID] = @SEGMENTID;

  -- check if the segment exists, if not, don't execute any code below, just return nothing

  if exists(select top 1 1 from @MAILINGSTABLE)
    begin
      select @MAILINGSCOUNT = count([ID])
      from @MAILINGSTABLE;

      -- get the total count for the segment

      set @SQL = 'select @DONORSCOUNT = count(*) from dbo.' + dbo.[UFN_MKTSELECTION_GETFUNCTIONNAME](@SEGMENTIDSETREGISTERID);
      exec sp_executesql @SQL, N'@DONORSCOUNT int output', @DONORSCOUNT = @DONORSCOUNT output;

      set @SQL = 'select' + char(13) +
                 '  year([GIFTIDSETS].[DATE]) as [YEAR],' + char(13) +
                 '  count(distinct [GIFTIDSETS].[DONORID]) as [DONORCOUNT],' + char(13) + 
                 '  @DONORSCOUNT as [TOTALDONORS],' + char(13) +
                 '  @SEGMENTNAME as [SEGMENTNAME]' + char(13);
      set @PARAMETERS = '@DONORSCOUNT int, @SEGMENTNAME nvarchar(100)';

      -- loop through all the activated mailings that use the segment and join to each mailing's activated data table

      declare MAILINGCURSOR cursor local fast_forward for
        select [DATATABLE], [MAILINGSEGMENTID]
        from @MAILINGSTABLE;

      open MAILINGCURSOR;
      fetch next from MAILINGCURSOR into @DATATABLE, @MAILINGSEGMENTID;

      while (@@FETCH_STATUS = 0)
      begin
        if @INNERDONORSQL is not null
          set @INNERDONORSQL = @INNERDONORSQL + char(13) + space(6) + 'union' + char(13) + space(6);

        set @INNERDONORSQL = isnull(@INNERDONORSQL, '') + 'select ' + @MATCHBACKFIELD + ' from dbo.[' + @DATATABLE + '] where [SEGMENTID] = ''' + cast(@MAILINGSEGMENTID as nvarchar(36)) + '''';

        fetch next from MAILINGCURSOR into @DATATABLE, @MAILINGSEGMENTID;
      end

      close MAILINGCURSOR;
      deallocate MAILINGCURSOR;

      if @MAILINGSCOUNT > 1
        set @INNERDONORSQL = @INNERDONORSQL + char(13) + space(5);

      set @SQL = @SQL + 'from (' + @INNERDONORSQL + ') as [DONORS]' + char(13);

      if @MARKETINGRECORDTYPE = 2 or @MARKETINGRECORDTYPE = 3
        begin
          set @PRESQL = 'declare @MAILINGS table([ID] uniqueidentifier not null primary key);' + char(13) +
                        char(13) +
                        'insert into @MAILINGS' + char(13) +
                        '  select distinct [MKTSEGMENTATION].[ID]' + char(13) +
                        '  from dbo.[MKTSEGMENTATIONSEGMENT]' + char(13) + 
                        '  inner join dbo.[MKTSEGMENTATION] on [MKTSEGMENTATION].[ID] = [MKTSEGMENTATIONSEGMENT].[SEGMENTATIONID]' + char(13) +
                        '  where (dbo.UFN_APPUSER_ISSYSADMIN(@CURRENTAPPUSERID) = 1 or exists (select 1 from dbo.UFN_SITESFORUSERONFEATURE(@CURRENTAPPUSERID,@SECURITYFEATUREID,@SECURITYFEATURETYPE) where SITEID=[MKTSEGMENTATION].[SITEID] or (SITEID is null and [MKTSEGMENTATION].[SITEID] is null)))' + char(13) +
                        '  and [MKTSEGMENTATION].[ACTIVE] = 1' + char(13) +
                        '  and [MKTSEGMENTATIONSEGMENT].[SEGMENTID] = @SEGMENTID;' + char(13) + char(13);
          set @PARAMETERS = @PARAMETERS + ', @SEGMENTID uniqueidentifier, @CURRENTAPPUSERID uniqueidentifier, @SECURITYFEATUREID uniqueidentifier, @SECURITYFEATURETYPE tinyint';

          if @MARKETINGRECORDTYPE = 2  --List

            begin
              select
                @LISTMATCHBACKTABLE = dbo.[UFN_MKTRECORDSOURCE_MAKEMATCHBACKTABLENAME]([MKTLIST].[RECORDSOURCEID])
              from dbo.[MKTSEGMENTLIST]
              inner join dbo.[MKTLIST] on [MKTLIST].[ID] = [MKTSEGMENTLIST].[LISTID]
              where [MKTSEGMENTLIST].[IDSETRECORDTYPEID] = @RECORDTYPEID;

              set @SQL = @SQL + 'inner join (select distinct [ID], [GIFTID] from dbo.[' + @LISTMATCHBACKTABLE + '] where [SEGMENTATIONID] in (select [ID] from @MAILINGS)) as [LISTMATCHBACK] on [LISTMATCHBACK].[ID] = [DONORS].[DONORID]' + char(13);
            end
          else
            begin
              if @MARKETINGRECORDTYPE = 3  --Consolidated list

                begin
                  declare LISTCURSOR cursor local fast_forward for
                    select distinct dbo.[UFN_MKTRECORDSOURCE_MAKEMATCHBACKTABLENAME]([MKTLIST].[RECORDSOURCEID])
                    from dbo.[MKTSEGMENTLIST]
                    inner join dbo.[MKTLIST] on [MKTLIST].[ID] = [MKTSEGMENTLIST].[LISTID]
                    inner join dbo.[QUERYVIEWCATALOG] on [QUERYVIEWCATALOG].[ID] = [MKTSEGMENTLIST].[CONSOLIDATEDQUERYVIEWID]
                    where [QUERYVIEWCATALOG].[RECORDTYPEID] = @RECORDTYPEID;

                  open LISTCURSOR;
                  fetch next from LISTCURSOR into @LISTMATCHBACKTABLE;

                  while (@@FETCH_STATUS = 0)
                  begin
                    if @INNERLISTSQL is not null
                      set @INNERLISTSQL = @INNERLISTSQL + char(13) + space(12) + 'union' + char(13) + space(12);

                    set @INNERLISTSQL = isnull(@INNERLISTSQL, '') + 'select distinct [ID], [GIFTID] from dbo.[' + @LISTMATCHBACKTABLE + '] where [SEGMENTATIONID] in (select [ID] from @MAILINGS)';

                    fetch next from LISTCURSOR into @LISTMATCHBACKTABLE;
                  end

                  close LISTCURSOR;
                  deallocate LISTCURSOR;

                  if charindex(char(13), @INNERLISTSQL) > 0
                    set @INNERLISTSQL = @INNERLISTSQL + char(13) + space(11);

                  set @SQL = @SQL + 'left join (' + @INNERLISTSQL + ') as [LISTMATCHBACK] on cast([LISTMATCHBACK].[ID] as varchar(36)) = [DONORS].[DONORID]' + char(13);
              end
            end
        end

      -- loop through all the activated mailings that use the segment and join to each mailing's normal gift ID sets

      declare GIFTIDSETCURSOR cursor local fast_forward for
        select dbo.[UFN_MKTSELECTION_GETFUNCTIONNAME]([NORMALGIFTIDSETREGISTERID])
        from dbo.[MKTSEGMENTATIONACTIVATE]
        where [SEGMENTATIONID] in (select distinct [ID] from @MAILINGSTABLE);

      open GIFTIDSETCURSOR;
      fetch next from GIFTIDSETCURSOR into @GIFTIDSETNAME;

      while (@@FETCH_STATUS = 0)
      begin
        if @INNERGIFTSQL is not null
          set @INNERGIFTSQL = @INNERGIFTSQL + char(13) + space(12) + 'union' + char(13) + space(12);

        set @INNERGIFTSQL = isnull(@INNERGIFTSQL, '') + 'select [ID], [DONORID], [FINDERNUMBER], [AMOUNT], [DATE] from dbo.' + @GIFTIDSETNAME;

        fetch next from GIFTIDSETCURSOR into @GIFTIDSETNAME;
      end

      close GIFTIDSETCURSOR;
      deallocate GIFTIDSETCURSOR;

      if @MAILINGSCOUNT > 1
        set @INNERGIFTSQL = @INNERGIFTSQL + char(13) + space(11);

      set @SQL = isnull(@PRESQL, '') + @SQL + 
                 'inner join (' + @INNERGIFTSQL + ') as [GIFTIDSETS] on ';

      if @MARKETINGRECORDTYPE = 1
        set @SQL = @SQL + '[GIFTIDSETS].' + @MATCHBACKFIELD + ' = [DONORS].' + @MATCHBACKFIELD + char(13);
      else
        begin
          if @MARKETINGRECORDTYPE = 2
            set @SQL = @SQL + '[GIFTIDSETS].[ID] = [LISTMATCHBACK].[GIFTID]' + char(13);
          else
            begin
              if @MARKETINGRECORDTYPE = 3
                set @SQL = @SQL + '[GIFTIDSETS].[ID] = [LISTMATCHBACK].[GIFTID] or cast([GIFTIDSETS].[DONORID] as varchar(36)) = [DONORS].[DONORID]' + char(13);
            end
        end

      set @SQL = @SQL +
                 'where year([GIFTIDSETS].[DATE]) > year(getdate()) - ' + cast(@NUMYEARS as nvarchar(10)) + char(13) +
                 'and year([GIFTIDSETS].[DATE]) <= year(getdate())' + char(13) +
                 'group by year([GIFTIDSETS].[DATE])' + char(13) +
                 'order by year([GIFTIDSETS].[DATE])';

      -- in case no gifts were given, output to a temp table first, then check the rowcount

      declare @OUTPUTTABLE table ([YEAR] int, [DONORS] int, [TOTALDONORS] int, [NAME] nvarchar(255));

      begin try
        -- try to improve performance by adding a join hint to the sql; if the hint fails, then execute the sql without it

        declare @SQLWITHJOINHINT nvarchar(max);
        set @SQLWITHJOINHINT = @SQL + char(13) + 'option (hash join, merge join);';

        if @MARKETINGRECORDTYPE = 2 or @MARKETINGRECORDTYPE = 3
          insert into @OUTPUTTABLE
            exec sp_executesql @SQLWITHJOINHINT, @PARAMETERS,
                               @DONORSCOUNT = @DONORSCOUNT,
                               @SEGMENTNAME = @SEGMENTNAME,
                               @SEGMENTID = @SEGMENTID,
                               @CURRENTAPPUSERID = @CURRENTAPPUSERID,
                               @SECURITYFEATUREID = @SECURITYFEATUREID,
                               @SECURITYFEATURETYPE = @SECURITYFEATURETYPE;
        else
          insert into @OUTPUTTABLE
            exec sp_executesql @SQLWITHJOINHINT, @PARAMETERS,
                               @DONORSCOUNT = @DONORSCOUNT,
                               @SEGMENTNAME = @SEGMENTNAME;

        if not (select count(*) from @OUTPUTTABLE) > 0 -- gifts were given

          begin -- gifts were not given so enter our basic data so that the report can render something

            insert into @OUTPUTTABLE
              select year(getdate()) [YEAR], 0 [RETENTION], @DONORSCOUNT [DONORSCOUNT], @SEGMENTNAME [NAME];
          end
      end try

      begin catch
        if ERROR_NUMBER() = 8622
          begin
            if @MARKETINGRECORDTYPE = 2 or @MARKETINGRECORDTYPE = 3
              insert into @OUTPUTTABLE
                exec sp_executesql @SQL, @PARAMETERS,
                                   @DONORSCOUNT = @DONORSCOUNT,
                                   @SEGMENTNAME = @SEGMENTNAME,
                                   @SEGMENTID = @SEGMENTID,
                                   @CURRENTAPPUSERID = @CURRENTAPPUSERID,
                                   @SECURITYFEATUREID = @SECURITYFEATUREID,
                                   @SECURITYFEATURETYPE = @SECURITYFEATURETYPE;
            else
              insert into @OUTPUTTABLE
                exec sp_executesql @SQL, @PARAMETERS,
                                   @DONORSCOUNT = @DONORSCOUNT,
                                   @SEGMENTNAME = @SEGMENTNAME;

            if not (select count(*) from @OUTPUTTABLE) > 0 -- gifts were given

              insert into @OUTPUTTABLE
                select year(getdate()) [YEAR], 0 [DONORCOUNT], @DONORSCOUNT [TOTALDONORS], @SEGMENTNAME [SEGMENTNAME];
          end
        else
          begin
            exec dbo.[USP_RAISE_ERROR];
            return 1;
          end
      end catch
    end
  else -- the segment is not used yet

    begin
      insert into @OUTPUTTABLE
        select year(getdate()) [YEAR], 0 [DONORCOUNT], @DONORSCOUNT [TOTALDONORS], @SEGMENTNAME [SEGMENTNAME];
    end

  if not @SEGMENTID is null
    begin
      declare @YEARTABLE table (
        [GIFTYEAR] integer
      )

      declare @NUMBEROFYEARSTOINSERT integer = @NUMYEARS - 1;
      declare @INSERTYEAR bit = 0;
      declare @YEAR int;

      while @NUMBEROFYEARSTOINSERT >= 0
      begin

        set @YEAR = year(getdate()) - @NUMBEROFYEARSTOINSERT;
        set @INSERTYEAR =  case when exists (select 1 from @OUTPUTTABLE AS [RESULTS] where [RESULTS].[YEAR] = @YEAR) then 0 else 1 end;

        -- Insert blank year if no gifts given in that year.  

        if @INSERTYEAR = 1
          begin
            insert into @YEARTABLE
              select @YEAR;
          end

          set @NUMBEROFYEARSTOINSERT = @NUMBEROFYEARSTOINSERT - 1;
      end

      insert into @OUTPUTTABLE
        select
          [GIFTYEAR],
          0,
          @DONORSCOUNT,
          @SEGMENTNAME
        from @YEARTABLE;
    end

  select 
    [OT].[YEAR],
    [OT].[DONORS] AS [RETENTION],
    case when ([OT].[TOTALDONORS] - [OT].[DONORS]) is null then 0 else [OT].[TOTALDONORS] - [OT].[DONORS] end as [DONORSCOUNT],
    [OT].[NAME]
  from @OUTPUTTABLE [OT]
  order by [YEAR];

  return 0;