【问题标题】:Loops through months in Qlik Sense在 Qlik Sense 中循环数月
【发布时间】:2021-07-03 06:41:18
【问题描述】:

谁能帮我为以下场景找到解决方案? (日期格式为 'MM/DD/YYYY')

Cr Date 是帐户创建日期,End Date 是帐户结束日期,# of Months 表示创建日期和结束日期之间的月份,Due Date 表示付款到期的每个月的天数。

我需要将此截止日期字段生成为如下所示的日期,它是创建日期和结束日期之间的连续截止日期。

2020 年 1 月 8 日

2020 年 2 月 8 日

2020 年 3 月 8 日

2020 年 4 月 8 日

2020 年 5 月 8 日

2020 年 6 月 8 日

您能帮我找到解决此任务的方法吗?

【问题讨论】:

    标签: loops date qliksense


    【解决方案1】:

    一种可能的解决方案是遍历所有值并自动生成日期。

    带注释的加载脚本示例:

    // Sample data
    RawData:
    Load * Inline [
      Id, Cr Date   , End Date
      1 , 12/08/2019, 06/08/2020
      2 , 05/07/2019, 16/11/2020
    ];
    
    
    // temp table to keep distinct values 
    // of the concatenation of id, cr date and end date
    // example record:
    // 1^12/08/2019^06/08/2020
    TempTable:
    Load
      distinct
      Id & '^' & [Cr Date] & '^' & [End Date] as Id_Dates
    Resident
      RawData
    ;
    
    // for each record in Id_Dates field
    for i = 1 to FieldValueCount('Id_Dates')
      // get the current iteration value
      let value = FieldValue('Id_Dates', $(i));
      // extract the Id
      let currentId = SubField('$(value)', '^', 1);
      // extract cr date  
      let currentCrDate = Num(SubField('$(value)', '^', 2));
      // extract end date
      let currentEndDate = Num(SubField('$(value)', '^', 3));
    
      // autogenerate all dates between the currentCrDate and currentEndDate
      // add the current Id value (this will link to the RawData table
      DueDates:
      LOAD
        '$(currentId)' as Id,
        date($(currentCrDate) + IterNo() - 1, 'DD/MM/YYYY') AS DueDate
      AUTOGENERATE (1)
      WHILE 
        $(currentCrDate) + IterNo() -1 <= $(currentEndDate)
      ;
    
    next
    
    // we dont need this table anymore
    Drop Table TempTable;
    

    脚本完成后将包含两个表格:

    DueDates 表将包含如下值:

    附:如果源数据有很多不同的Id 值,此解决方案可能效率不高。 如果是这种情况,请告诉我,我会考虑其他解决方案

    更新(2021 年 6 月 10 日)

    另一种避免单独循环遍历所有行的方法是在源数据和具有所有可能日期的日历表之间创建交叉连接(笛卡尔连接)。一旦我们有了这个表,我们就可以过滤掉不需要的行

    这种方法会更快它很可能会在重新加载期间消耗更多的 RAM。重新加载完成后,结果应用程序应具有与“遍历每一行”方法相同的内存占用

    RawData:
    Load * Inline [
      Id, Cr Date   , End Date
      1 , 12/08/2019, 06/08/2020
      2 , 05/07/2019, 16/11/2020
    ];
    
    // Get min and max dates from [Cr Date] and [End Date] fields
    TempTable1:
    Load 
        min([Cr Date]) as MinDate,
        max([Cr Date]) as MaxDate
    Resident
        RawData
    ;
    
    concatenate
    
    Load 
        min([End Date]) as MinDate,
        max([End Date]) as MaxDate
    Resident
        RawData
    ;
    
    // Get the overall min and max dates
    NoConcatenate
    
    TempTable2:
    Load
      min(MinDate) as MinDate,
      max(MaxDate) as MaxDate
    Resident
        TempTable1
    ;
    
    Drop Table TempTable1;
    
    // gnerate all possible dates between the min and max dates
    // once the dates are generated join the result table to RawData
    // since there is no common fields between both tables 
    // the result table will be many to many join (cartesian join)
    // as a result at this point RawData will be quite large table
    // No of rows in RawData (initially) * No of rows in the Calendar table
    // for example if RawData has 10 rows and calendar have 1000 the result table
    // will have 10 000 rows
    // We will reduce the rows a bit in the next step
    let vMinDate = peek('MinDate');
    let vMaxDate = peek('MaxDate');
    
    join (RawData)
    
    Calendar:
    Load
      Date($(vMinDate) + IterNo() - 1, 'DD/MM/YYYY') as DueDate
    Autogenerate 1
    While 
        $(vMinDate) + IterNo() - 1 <= $(vMaxDate)
    ;
    
    Drop Table TempTable2;
    
    // Load resident modified RawData table and while loading we'll create new field
    // This field will be used a flag and we'll filter on it at the end
    // The logic in the field is:
    //   if [Cr Date] >= DueDate <= [End Date] then set it to 1 else 0
    // The final step is to keep only records with TempFlag == 1
    NoConcatenate
    
    RawData_Final:
    Load 
      Id,
      [Cr Date],
      [End Date],
      DueDate
    Where 
      TempFlag = 1  
    ;
    Load 
      Id,
      [Cr Date],
      [End Date],
      DueDate,
      if(DueDate >= [Cr Date] and DueDate <= [End Date], 1, 0) as TempFlag
    Resident
        RawData
    ;
    
    Drop Table RawData;
    

    【讨论】:

    • 非常感谢 Stefan Stoichey。我找到了解决方案。非常感谢。
    【解决方案2】:

    @Stefan Stoichev

    感谢您提供出色的代码...尽管如此,我的 ID 值表包含大约 200000 个条目...这使得加载脚本非常缓慢。 你有没有想过另一种方法?

    谢谢 这是我正在使用的代码的改编

    [ZSQ042_TEMP]:
    LOAD
        key //commande & poste
        ,[COMMANDE]
        ,[POSTE]
        , YEAR_WEEK_REF_TAUX_SERVICE
        , WEEK_SM_REELLE_ZSQ
        
        ,[ORIGINE]
        ,[Business unit]
        ,[Sector]
        ,TYPE_cde
        
     resident [SALES]
     where num(WEEK_SM_REELLE_ZSQ) > num(YEAR_WEEK_REF_TAUX_SERVICE)
     ;
     
     
    //on duplique toutes les lignes qui ne sont pas livrées à la semaine annoncée
     
     TempTable:
    Load
      distinct
      key & '^' & COMMANDE & '^' & POSTE & '^' & YEAR_WEEK_REF_TAUX_SERVICE & '^' & WEEK_SM_REELLE_ZSQ & '^' &
      [ORIGINE] & '^' & [Business unit] & '^' & [Sector] & '^' & TYPE_cde
      as Id_Weeks
    Resident
      [ZSQ042_TEMP]
    ;
    
    
    // for each record in Id_Dates field
    for i = 2 to FieldValueCount('Id_Weeks')
     
     // get the current iteration value
      let value = FieldValue('Id_Weeks', $(i));
      
      // extract the Id
      let currentId = SubField('$(value)', '^', 1);
      
      //Extract Order Number
      let currentOrder = SubField('$(value)', '^', 2);
      
      //Extract Order Line Number
      let currentLine = SubField('$(value)', '^', 3);
        
      // extract week to be delivered  
      let currentWeekStart = Num(SubField('$(value)', '^', 4));
      
      // extract week of delivery
      let currentWeekEnd = Num(SubField('$(value)', '^', 5));
      
      // extract origin
      let currentOrigin = SubField('$(value)', '^', 6);
      
      // extract BU
      let currentBU = SubField('$(value)', '^', 7);
    
    // extract Sector
      let currentSector = SubField('$(value)', '^', 8);
      
      // extract Type de commande
      let currentType = SubField('$(value)', '^', 9);
       
    // autogenerate all weeks between the week to deliver and week of delivery
       // add the current Id value (this will link to the RawData table)
    
    
    Concatenate([SALES])
    LOAD 
        '$(currentId)' as key,
        '$(currentOrder)' as COMMANDE,
        '$(currentLine)' as POSTE,
        '$(currentWeekStart)' as INITIAL_YEAR_WEEK_REF_TAUX_SERVICE,
        $(currentWeekStart) + IterNo() as YEAR_WEEK_REF_TAUX_SERVICE, //IterNo()-1
        '$(currentWeekEnd)' as WEEK_SM_REELLE_ZSQ,
        IterNo() as Nb_Weeks_Late,
       
        
        
        '$(currentOrigin)' as ORIGINE,
        '$(currentBU)' as Business_unit,
        '$(currentSector)' as Sector,
        '$(currentType)' as TYPE_cde
        
        
        
      AUTOGENERATE (1)
      WHILE 
        $(currentWeekStart) + IterNo() <= $(currentWeekEnd) //IterNo()-1
      ;
    
    next
    
    // we dont need this table anymore
    Drop Table TempTable;
    Drop Table ZSQ042_TEMP;
    

    【讨论】:

    • 我更新了我的答案并提供了另一个解决方案。第二种解决方案应该运行得更快,但在重新加载期间应该消耗更多内存。重新加载完成后,结果数据将与第一个解决方案相同
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-16
    • 2021-07-07
    • 2016-08-18
    • 1970-01-01
    • 2016-08-10
    • 1970-01-01
    相关资源
    最近更新 更多