Expand/explode 一个 Google 工作表 table 带有工单打开和关闭统计信息以显示每个月所有打开的工单
Expand/explode a Google Sheets table with ticket open and close stats to show all tickets open each month
我的工作example/sampleGoogleSheet:https://docs.google.com/spreadsheets/d/1AvAb_qnrrexYl5W5wAW6aA6P552T-prBxoONOis-XZM/edit?usp=sharing
我有一个来源 table,其中包含有关门票的信息。为了这个问题,只有三列很重要:
- 工单 ID
- 工单开放日期
- 工单关闭日期 -- 如果关闭
根据这些信息,我需要生成 metrics/reports 显示特定月份的内容:
- 当月开的工单
- 当月关闭的工单
- 打开的工单(之前打开但未关闭)
而且,我需要原始数据,而不仅仅是月度摘要。也就是说,我应该能够 select 一个月并显示符合上述三个条件的所有工单 ID。
使用此函数(我的示例 sheet 中的列 E-G)很容易获得前两个:
{
QUERY(A2:C, "SELECT B, 'Opened', A WHERE A IS NOT NULL LABEL 'Opened' '' FORMAT B 'YYYY-MM'");
QUERY(A2:C, "SELECT C, 'Closed', A WHERE C IS NOT NULL LABEL 'Closed' '' FORMAT C 'YYYY-MM'")
}
我卡在第三个了。我想弄清楚如何在每个月打开一张票。对于每个月开放的票证,应该有一行:
- 第一列是月份
- 第二列是"Open"
- 第三列是工单 ID
例如:
- ID0010
- 于 2018-11
开业
- 于 2019-01
关闭
- 打开方式:
- 2018-12
- ID0019
- 于 2018-08
开业
- 于 2019-03
关闭
- 打开方式:
- 2018-09
- 2018-10
- 2018-11
- 2018-12
- 2019-01
- 2019-02
会变成:
| Month | Status | Ticket ID |
|---------|--------|-----------|
| 2018-11 | Opened | ID0010 |
| 2018-12 | Open | ID0010 |
| 2019-01 | Closed | ID0010 |
| 2018-08 | Opened | ID0019 |
| 2018-09 | Open | ID0019 |
| 2018-10 | Open | ID0019 |
| 2018-11 | Open | ID0019 |
| 2018-12 | Open | ID0019 |
| 2019-01 | Open | ID0019 |
| 2019-02 | Open | ID0019 |
| 2019-03 | Closed | ID0019 |
注意:打开和关闭工单的月份不会也显示工单的 "Open"。换句话说,一张票应该只有 "Open" 月份:
- 打开后且不包括打开
- 之前且不包括关闭
而且,如果工单尚未关闭,那么它将在今天之前每个月一行。
我想我可以使用 的公认解决方案中的概念,但由于数据量大,我遇到了错误。公式在我的样本 sheet.
的 I2 中
Text result of CONCATENATE is longer than the limit of 50000 characters.
所以我想知道是否有其他方法可以获得我需要的数据。我知道如何使用自定义函数执行此操作,但我希望尽可能避免使用自定义函数。
更新解决方案
我能够提取 player0 答案的关键部分并将其用于我的原始解决方案。简而言之,不是使用 CONCATENATE
来组合 columns/rows,而是使用 QUERY
和 999^99
作为 header 计数(第三个参数),因为 QUERY
将合并所有行(使用 space 分隔符)。
最终公式为:
=ARRAYFORMULA(
QUERY(
SPLIT(
TRANSPOSE(
SPLIT(
QUERY(
TRANSPOSE(
TRIM(
QUERY(
IF(
A2:A <> "",
A2:A & "," & EDATE(
IFERROR(
SPLIT(
REPT(
EOMONTH(B2:B, -1) + 1 & ",",
DATEDIF(
EOMONTH(B2:B, 0) + 1,
EOMONTH(
IF(
C2:C <> "",
C2:C,
EDATE(TODAY(), 1)
),
0
),
"M"
)
),
","
),
0
),
TRANSPOSE(
ROW(
INDIRECT(
"A1:A" & MAX(
IF(
B2:B <> "",
IFERROR(
DATEDIF(
EOMONTH(B2:B, 0) + 1,
EOMONTH(
IF(
C2:C <> "",
C2:C,
EDATE(TODAY(), 1)
),
0
),
"M"
),
0
),
)
)
)
)
)
) & ";",
),
,
999^99
)
)
),
,
999^99
) & " ",
"; "
)
),
","
),
"SELECT Col2, 'Open', Col1 WHERE Col2 > 4000 LABEL 'Open' '' FORMAT Col2 'YYYY-MM'",
0
)
)
更新以使用 SEQUENCE
=ARRAYFORMULA(
QUERY(
SPLIT(
TRANSPOSE(
SPLIT(
QUERY(
TRANSPOSE(
TRIM(
QUERY(
IF(
A2:A <> "",
A2:A & "," & EDATE(
IFERROR(
SPLIT(
REPT(
EOMONTH(B2:B, -1) + 1 & ",",
DATEDIF(
EOMONTH(B2:B, 0) + 1,
EOMONTH(
IF(
C2:C <> "",
C2:C,
EDATE(TODAY(), 1)
),
0
),
"M"
)
),
","
),
0
),
SEQUENCE(
1,
MAX(
IF(
B2:B <> "",
IFERROR(
DATEDIF(
EOMONTH(B2:B, 0) + 1,
EOMONTH(
IF(
C2:C <> "",
C2:C,
EDATE(TODAY(), 1)
),
0
),
"M"
),
0
),
)
)
)
) & ";",
),
,
999^99
)
)
),
,
999^99
) & " ",
"; "
)
),
","
),
"SELECT Col2, 'Open', Col1 WHERE Col2 > 4000 LABEL 'Open' '' FORMAT Col2 'YYYY-MM'",
0
)
)
同样的逻辑:
=ARRAYFORMULA(UNIQUE(QUERY(SPLIT(TRANSPOSE(SPLIT(QUERY(TRANSPOSE(QUERY(TRANSPOSE(
"♦"&FILTER(A2:A, B2:B<>"", C2:C<>"")&"♠"&SPLIT(REPT(FILTER(B2:B, B2:B<>"", C2:C<>"")+1&"♣",
NETWORKDAYS(FILTER(B2:B, B2:B<>"", C2:C<>"")+1, FILTER(C2:C, B2:B<>"", C2:C<>""))), "♣")+
TRANSPOSE(ROW(INDIRECT("A1:A"&MAX(
NETWORKDAYS(FILTER(B2:B, B2:B<>"", C2:C<>"")+1, FILTER(C2:C, B2:B<>"", C2:C<>"")))))-1)&"♠")
,,999^99)),,999^99), "♦")), "♠"),
"select Col2,'Open',Col1 where Col2>4000 label 'Open''' format Col2 'YYYY-MM'", 0)))
更新:
=ARRAYFORMULA(UNIQUE(QUERY(SPLIT(TRANSPOSE(SPLIT(QUERY(TRANSPOSE(QUERY(TRANSPOSE("♦"&
FILTER(A2:A, B2:B<>"", C2:C<>"", MONTH(B2:B)<>MONTH(C2:C), YEAR(B2:B)<>YEAR(C2:C))&"♠"&EOMONTH(SPLIT(REPT(
FILTER(B2:B, B2:B<>"", C2:C<>"", MONTH(B2:B)<>MONTH(C2:C), YEAR(B2:B)<>YEAR(C2:C))+1&"♣", DATEDIF(
FILTER(B2:B, B2:B<>"", C2:C<>"", MONTH(B2:B)<>MONTH(C2:C), YEAR(B2:B)<>YEAR(C2:C))+1,
FILTER(C2:C, B2:B<>"", C2:C<>"", MONTH(B2:B)<>MONTH(C2:C), YEAR(B2:B)<>YEAR(C2:C)), "M")-1), "♣"),
TRANSPOSE(ROW(INDIRECT("A1:A"&MAX(NETWORKDAYS(
FILTER(B2:B, B2:B<>"", C2:C<>"", MONTH(B2:B)<>MONTH(C2:C), YEAR(B2:B)<>YEAR(C2:C))+1,
FILTER(C2:C, B2:B<>"", C2:C<>"", MONTH(B2:B)<>MONTH(C2:C), YEAR(B2:B)<>YEAR(C2:C))))))))&"♠")
,,999^99)),,999^99), "♦")), "♠"),
"select Col2,'Open',Col1 where Col2>4000 label 'Open''' format Col2 'YYYY-MM'", 0)))
更新:
我已经更新了我的解决方案,以使用一种我喜欢用来将 2D 数组转换为 2 列数据集的重新制表方法。下面这个公式在这个 sample sheet. 的 C1 中
您会在 F1 中看到一个类似的公式,它跳过爆炸,如果这是图表的目标,则只按月计算票数。 A1 中还有一个小公式,仅计算以月为单位的未结票证的最大长度。这在公式中多次使用,因此在视觉上为它提供一个辅助单元格很有帮助。如果您想避免使用任何辅助单元格,可以很容易地将其替换为大型公式来代替 A1 参考。
=ARRAYFORMULA(QUERY(VLOOKUP(SEQUENCE(COUNTA(Sheet1!A2:A)*A1,1,0)/A1+2,{ROW(Sheet1!A2:A),Sheet1!A2:A,IF(EDATE(EOMONTH(Sheet1!B2:B,-1)+1,SEQUENCE(1,A1,0))>EOMONTH(IFERROR(1/(1/Sheet1!C2:C),TODAY()),-1)+1,,EDATE(EOMONTH(Sheet1!B2:B,-1)+1,SEQUENCE(1,A1,0)))},MOD(SEQUENCE(COUNTA(Sheet1!A2:A)*A1,1,0),A1)*{0,1}+{2,3}),"where Col2 is not null label Col1'Ticket',Col2'Month'"))
我的工作example/sampleGoogleSheet:https://docs.google.com/spreadsheets/d/1AvAb_qnrrexYl5W5wAW6aA6P552T-prBxoONOis-XZM/edit?usp=sharing
我有一个来源 table,其中包含有关门票的信息。为了这个问题,只有三列很重要:
- 工单 ID
- 工单开放日期
- 工单关闭日期 -- 如果关闭
根据这些信息,我需要生成 metrics/reports 显示特定月份的内容:
- 当月开的工单
- 当月关闭的工单
- 打开的工单(之前打开但未关闭)
而且,我需要原始数据,而不仅仅是月度摘要。也就是说,我应该能够 select 一个月并显示符合上述三个条件的所有工单 ID。
使用此函数(我的示例 sheet 中的列 E-G)很容易获得前两个:
{
QUERY(A2:C, "SELECT B, 'Opened', A WHERE A IS NOT NULL LABEL 'Opened' '' FORMAT B 'YYYY-MM'");
QUERY(A2:C, "SELECT C, 'Closed', A WHERE C IS NOT NULL LABEL 'Closed' '' FORMAT C 'YYYY-MM'")
}
我卡在第三个了。我想弄清楚如何在每个月打开一张票。对于每个月开放的票证,应该有一行:
- 第一列是月份
- 第二列是"Open"
- 第三列是工单 ID
例如:
- ID0010
- 于 2018-11 开业
- 于 2019-01 关闭
- 打开方式:
- 2018-12
- ID0019
- 于 2018-08 开业
- 于 2019-03 关闭
- 打开方式:
- 2018-09
- 2018-10
- 2018-11
- 2018-12
- 2019-01
- 2019-02
会变成:
| Month | Status | Ticket ID |
|---------|--------|-----------|
| 2018-11 | Opened | ID0010 |
| 2018-12 | Open | ID0010 |
| 2019-01 | Closed | ID0010 |
| 2018-08 | Opened | ID0019 |
| 2018-09 | Open | ID0019 |
| 2018-10 | Open | ID0019 |
| 2018-11 | Open | ID0019 |
| 2018-12 | Open | ID0019 |
| 2019-01 | Open | ID0019 |
| 2019-02 | Open | ID0019 |
| 2019-03 | Closed | ID0019 |
注意:打开和关闭工单的月份不会也显示工单的 "Open"。换句话说,一张票应该只有 "Open" 月份:
- 打开后且不包括打开
- 之前且不包括关闭
而且,如果工单尚未关闭,那么它将在今天之前每个月一行。
我想我可以使用
Text result of CONCATENATE is longer than the limit of 50000 characters.
所以我想知道是否有其他方法可以获得我需要的数据。我知道如何使用自定义函数执行此操作,但我希望尽可能避免使用自定义函数。
更新解决方案
我能够提取 player0 答案的关键部分并将其用于我的原始解决方案。简而言之,不是使用 CONCATENATE
来组合 columns/rows,而是使用 QUERY
和 999^99
作为 header 计数(第三个参数),因为 QUERY
将合并所有行(使用 space 分隔符)。
最终公式为:
=ARRAYFORMULA(
QUERY(
SPLIT(
TRANSPOSE(
SPLIT(
QUERY(
TRANSPOSE(
TRIM(
QUERY(
IF(
A2:A <> "",
A2:A & "," & EDATE(
IFERROR(
SPLIT(
REPT(
EOMONTH(B2:B, -1) + 1 & ",",
DATEDIF(
EOMONTH(B2:B, 0) + 1,
EOMONTH(
IF(
C2:C <> "",
C2:C,
EDATE(TODAY(), 1)
),
0
),
"M"
)
),
","
),
0
),
TRANSPOSE(
ROW(
INDIRECT(
"A1:A" & MAX(
IF(
B2:B <> "",
IFERROR(
DATEDIF(
EOMONTH(B2:B, 0) + 1,
EOMONTH(
IF(
C2:C <> "",
C2:C,
EDATE(TODAY(), 1)
),
0
),
"M"
),
0
),
)
)
)
)
)
) & ";",
),
,
999^99
)
)
),
,
999^99
) & " ",
"; "
)
),
","
),
"SELECT Col2, 'Open', Col1 WHERE Col2 > 4000 LABEL 'Open' '' FORMAT Col2 'YYYY-MM'",
0
)
)
更新以使用 SEQUENCE
=ARRAYFORMULA(
QUERY(
SPLIT(
TRANSPOSE(
SPLIT(
QUERY(
TRANSPOSE(
TRIM(
QUERY(
IF(
A2:A <> "",
A2:A & "," & EDATE(
IFERROR(
SPLIT(
REPT(
EOMONTH(B2:B, -1) + 1 & ",",
DATEDIF(
EOMONTH(B2:B, 0) + 1,
EOMONTH(
IF(
C2:C <> "",
C2:C,
EDATE(TODAY(), 1)
),
0
),
"M"
)
),
","
),
0
),
SEQUENCE(
1,
MAX(
IF(
B2:B <> "",
IFERROR(
DATEDIF(
EOMONTH(B2:B, 0) + 1,
EOMONTH(
IF(
C2:C <> "",
C2:C,
EDATE(TODAY(), 1)
),
0
),
"M"
),
0
),
)
)
)
) & ";",
),
,
999^99
)
)
),
,
999^99
) & " ",
"; "
)
),
","
),
"SELECT Col2, 'Open', Col1 WHERE Col2 > 4000 LABEL 'Open' '' FORMAT Col2 'YYYY-MM'",
0
)
)
同样的逻辑:
=ARRAYFORMULA(UNIQUE(QUERY(SPLIT(TRANSPOSE(SPLIT(QUERY(TRANSPOSE(QUERY(TRANSPOSE(
"♦"&FILTER(A2:A, B2:B<>"", C2:C<>"")&"♠"&SPLIT(REPT(FILTER(B2:B, B2:B<>"", C2:C<>"")+1&"♣",
NETWORKDAYS(FILTER(B2:B, B2:B<>"", C2:C<>"")+1, FILTER(C2:C, B2:B<>"", C2:C<>""))), "♣")+
TRANSPOSE(ROW(INDIRECT("A1:A"&MAX(
NETWORKDAYS(FILTER(B2:B, B2:B<>"", C2:C<>"")+1, FILTER(C2:C, B2:B<>"", C2:C<>"")))))-1)&"♠")
,,999^99)),,999^99), "♦")), "♠"),
"select Col2,'Open',Col1 where Col2>4000 label 'Open''' format Col2 'YYYY-MM'", 0)))
更新:
=ARRAYFORMULA(UNIQUE(QUERY(SPLIT(TRANSPOSE(SPLIT(QUERY(TRANSPOSE(QUERY(TRANSPOSE("♦"&
FILTER(A2:A, B2:B<>"", C2:C<>"", MONTH(B2:B)<>MONTH(C2:C), YEAR(B2:B)<>YEAR(C2:C))&"♠"&EOMONTH(SPLIT(REPT(
FILTER(B2:B, B2:B<>"", C2:C<>"", MONTH(B2:B)<>MONTH(C2:C), YEAR(B2:B)<>YEAR(C2:C))+1&"♣", DATEDIF(
FILTER(B2:B, B2:B<>"", C2:C<>"", MONTH(B2:B)<>MONTH(C2:C), YEAR(B2:B)<>YEAR(C2:C))+1,
FILTER(C2:C, B2:B<>"", C2:C<>"", MONTH(B2:B)<>MONTH(C2:C), YEAR(B2:B)<>YEAR(C2:C)), "M")-1), "♣"),
TRANSPOSE(ROW(INDIRECT("A1:A"&MAX(NETWORKDAYS(
FILTER(B2:B, B2:B<>"", C2:C<>"", MONTH(B2:B)<>MONTH(C2:C), YEAR(B2:B)<>YEAR(C2:C))+1,
FILTER(C2:C, B2:B<>"", C2:C<>"", MONTH(B2:B)<>MONTH(C2:C), YEAR(B2:B)<>YEAR(C2:C))))))))&"♠")
,,999^99)),,999^99), "♦")), "♠"),
"select Col2,'Open',Col1 where Col2>4000 label 'Open''' format Col2 'YYYY-MM'", 0)))
更新:
我已经更新了我的解决方案,以使用一种我喜欢用来将 2D 数组转换为 2 列数据集的重新制表方法。下面这个公式在这个 sample sheet. 的 C1 中 您会在 F1 中看到一个类似的公式,它跳过爆炸,如果这是图表的目标,则只按月计算票数。 A1 中还有一个小公式,仅计算以月为单位的未结票证的最大长度。这在公式中多次使用,因此在视觉上为它提供一个辅助单元格很有帮助。如果您想避免使用任何辅助单元格,可以很容易地将其替换为大型公式来代替 A1 参考。
=ARRAYFORMULA(QUERY(VLOOKUP(SEQUENCE(COUNTA(Sheet1!A2:A)*A1,1,0)/A1+2,{ROW(Sheet1!A2:A),Sheet1!A2:A,IF(EDATE(EOMONTH(Sheet1!B2:B,-1)+1,SEQUENCE(1,A1,0))>EOMONTH(IFERROR(1/(1/Sheet1!C2:C),TODAY()),-1)+1,,EDATE(EOMONTH(Sheet1!B2:B,-1)+1,SEQUENCE(1,A1,0)))},MOD(SEQUENCE(COUNTA(Sheet1!A2:A)*A1,1,0),A1)*{0,1}+{2,3}),"where Col2 is not null label Col1'Ticket',Col2'Month'"))