谷歌表格员工排班表转置需求:自定义公式或脚本方案咨询
嘿,我来帮你搞定这个排班表转置的问题!先给你两种实用方案:不用写代码的纯公式解法,以及更灵活的Google App Script自定义函数,你可以根据自己的需求来选。
方案一:纯公式解法(无需代码)
Google Sheets的新函数(比如LET、FLATTEN、SEQUENCE)可以轻松实现这个需求,不用依赖脚本。假设你的原始排班数据在Sheet1,第一行是班次表头(Shift A、Shift B…),从第二行开始每两行对应一天(第一行是日期,第二行是补充排班),可以用下面的公式生成所有员工的排班记录,再筛选特定员工的班次:
生成全量排班映射表
先在空白单元格输入这个公式,它会把所有日期、班次、员工对应起来:
=LET( rawData, Sheet1!A:E, // 提取所有日期(每两行取一次第一行的日期) dates, INDEX(rawData, SEQUENCE((ROWS(rawData)-1)/2, 1, 2, 2), 1), // 把每个日期重复两次,对应当天的两行排班 repeatedDates, FLATTEN(ARRAYFORMULA(REPT(dates&"|", 2))), // 提取所有班次的员工数据并扁平化 shiftAssignments, FLATTEN(INDEX(rawData, 2:ROWS(rawData), 2:COLUMNS(rawData))), // 把班次名称重复对应每一行数据 repeatedShiftNames, FLATTEN(ARRAYFORMULA(REPT(Sheet1!B1:E1&"|", ROWS(rawData)-1))), // 合并并拆分数据,得到日期、班次、员工三列 combinedData, SPLIT(FLATTEN(repeatedDates&repeatedShiftNames&shiftAssignments), "|"), // 过滤掉空员工的记录 FILTER(combinedData, INDEX(combinedData, , 3) <> "") )
提取特定员工的班次
如果要单独提取某个员工(比如单元格A1是员工名字)的所有班次,用QUERY嵌套上面的逻辑即可:
=QUERY(LET( rawData, Sheet1!A:E, dates, INDEX(rawData, SEQUENCE((ROWS(rawData)-1)/2, 1, 2, 2), 1), repeatedDates, FLATTEN(ARRAYFORMULA(REPT(dates&"|", 2))), shiftAssignments, FLATTEN(INDEX(rawData, 2:ROWS(rawData), 2:COLUMNS(rawData))), repeatedShiftNames, FLATTEN(ARRAYFORMULA(REPT(Sheet1!B1:E1&"|", ROWS(rawData)-1))), combinedData, SPLIT(FLATTEN(repeatedDates&repeatedShiftNames&shiftAssignments), "|"), FILTER(combinedData, INDEX(combinedData, , 3) <> "") ), "SELECT Col1, Col2 WHERE Col3 = '"&A1&"'")
逻辑解释:用LET简化变量命名,先把日期、班次名称分别重复对应每行排班数据,再通过分隔符合并拆分,最后过滤出有效记录,完美解决单日多班次的情况。
方案二:Google App Script自定义函数
如果数据量很大或者需要更灵活的扩展(比如自动更新、批量导出),用自定义函数会更高效。
步骤1:编写脚本
- 打开你的Google表格,点击顶部菜单的「扩展」→「Apps Script」
- 清空默认代码,粘贴下面的脚本:
function GET_EMPLOYEE_SHIFTS(employeeName, dataRange) { // 初始化结果数组,添加表头 const result = [["日期", "班次"]]; // 跳过表头行,从第二行开始处理 const shiftHeaders = dataRange[0]; const rows = dataRange.slice(1); // 每两行对应一天,循环处理 for (let i = 0; i < rows.length; i += 2) { // 获取当天日期(取两行中第一行的日期,第二行日期为空) const currentDate = rows[i][0]; if (!currentDate) break; // 防止数据结束时越界 // 处理当天的两行排班数据 const dayShifts = [rows[i], rows[i+1] || []]; dayShifts.forEach(row => { row.forEach((employee, colIndex) => { // 跳过日期列,只处理班次列 if (colIndex === 0) return; // 如果当前单元格是目标员工,添加记录到结果 if (employee === employeeName) { result.push([currentDate, shiftHeaders[colIndex]]); } }); }); } return result; }
步骤2:使用自定义函数
回到表格,在空白单元格输入:
=GET_EMPLOYEE_SHIFTS("员工姓名", Sheet1!A:E)
把"员工姓名"换成实际的员工名字,或者引用单元格(比如A1),Sheet1!A:E换成你的原始数据范围。函数会自动返回该员工的所有班次记录,包括单日多班次的情况。
优势:脚本逻辑更直观,数据量较大时性能比公式更好,还可以后续扩展比如自动发送排班提醒等功能。
内容的提问来源于stack exchange,提问作者Andrea Volontè
相关产品推荐
相关产品推荐

