Best Of
Bridge - Copy all attachment names to another sheet & get data from an array with a Child Workflow
This solution copies all attachment names from a source row and adds one row for each attachment name onto a target sheet. Each target row contains one attachment name and the source row primary key. The solution uses a Child Workflow to get individual data values from an array in the Parent Workflow. The solution is very detailed and should be relatively easy to replicate and modify.
Workflow summary
Provides a summary of the workflow input and output.
- Source data on source sheet
- Source data on target sheet
- Trigger is a user changes a source sheet “Status - Source” column cell to “Complete” and saves.
- Source data transfers to target data as per below.
- Multiple attachments on a source row become multiple target rows.
Smartsheet items
These are Smartsheet items for this solution.
- Bridge
- Workspace: Basic Workflows
- Parent Workflow: Copy all attachment names to another sheet
- Gets row data and determines if row data should be added to target sheet
- Triggers Child Workflow
- Child Workflow: Retrieve data from array
- Isolates attachment array data for each item and adds to target sheet
- Smartsheet
- Workspace > folder: Bridge > Basic workflow sheets
- Source sheet: Copy all attachment names to a sheet - Source
- Target sheet: Copy all attachment names to a sheet - Target
Workflow details
The details of each element in the Workflow, the element configurable values, and the value sources.
Parent workflow overview
Gets row data. If multiple attachments are present, the attachments details are stored in an array.
Child workflow overview
Repeats once for each attachment. Isolates array data and puts in on a new row on the target sheet.
Trigger element
Clicking the gear icon beside Smartsheet on the Trigger pane on the right allows adjustment of the trigger.
Get Row element
Fields, values, and sources
Value source for Get Rows “Sheet ID” and “Row ID”
Clicking “Copy Data Reference” for these items provides {{runtime.event.sheetId}} and {{runtime.event.rowId}}. Data Reference must be copied for each item.
Junction: Status – Source is Complete element
This is a Condition Junctions > Match element. It checks if the first value matches the second value.
Fields, values, and sources
Value source for Junction “First Value”
Clicking “Copy Data Reference” provides
{{states.startstate.smartsheet.get_row.row.cells.Status - Source.value}}
Child Workflow: Retrieve data from array element
Triggers Child Workflow using the Get Row – Attachment array. The Child Workflow will run one time for each data set in the Get Row – Attachment array. Each time the Child Workflow runs, it starts with the data from the array data set.
Fields, value, and sources
Value source for “Number of Runs”
Clicking “Copy Data Reference” provides
{{states.startstate.smartsheet.get_row.row.attachments}}
Value source for “Value #1”
Clicking “Copy Data Reference” provides
{{states.startstate.smartsheet.get_row.row.cells.ID - Source.value}}
Child Workflow Trigger element
Fields, values, and sources
Child Workflow Add Row element
Fields, values, and sources
Value source for “Value #1”
Clicking “Copy Data Reference” provides {{runtime.entities.ID - Source value}}
Value source for “Value #2”
Clicking “Copy Data Reference” provides {{runtime.data.name}}
Regards,
Neil Egsgard
Business Systems Architect
Southern Alberta Institute of Technology
Split Multiple Selections In Single Form Into Individual Rows (Core Product)
There have been a number of people asking how to make multiple selections in a single form and then have those selections broken down into individual rows, and the previous answer was always to use a 3rd party app, a premium add-on, or the API.
Below is a set of detailed instructions on how to accomplish this within the core product using two sheets and a copy row automation. The below is set up with new form entries being populated at the top of the sheet for ease of formulas, but it can be adjusted so that new form entries are made at the bottom of the sheet. I wasn't too worried about the look of the initial submission sheet though as the selections get parsed out and put on individual rows on a second sheet.
Here is how we take form submissions that look like this:
And turn them into static entries that look like this:
STEP 1 - Set Up the Base Form Sheet
The first thing to do is set up the Form Sheet. This sheet is the one that has the form attached to it and is also used to shift each form submission from horizontal to vertical. This example is a basic setup where we capture a name and 5 separate options. You are also going to need an auto-number column with no special formatting. This solution can be adapted to use special formatting in the auto-number column, but I am keeping things simple here to get the basic ideas across. In this example, I called the auto-number column [Submission #]. The other columns below are all text/number type columns, and these are the ones we will find on the form.
STEP 2 - Set Up the Formatting Section of the Form Sheet
Next we need to set up our formatting section.
There is a checkbox column called [Copy Section] that is manually checked on 5 rows. If we had more or less options available that needed to be split, we would use that same number of rows manually checked.
We need a text/number column called [Option]. This has a formula in each of the 5 rows. This is what converts our horizontal format into a vertical format. We use an INDEX function to pull the top row from each of the individual option columns.
=INDEX([Option 1]:[Option 1], 1)
=INDEX([Option 2]:[Option 2], 1)
=INDEX([Option 3]:[Option 3], 1)
=INDEX([Option 4]:[Option 4], 1)
=INDEX([Option 5]:[Option 5], 1)
Then I used the Primary Column and called it [Name]. You can use any text/number column, but I used it this way so that the name is in the Primary Column of the Final Sheet. I used this formula in all 5 of the rows:
=IF(Option@row <> "", INDEX([Form Name]:[Form Name], 1))
Next is a text/number column called [Submission Number]. I used this formula on all 5 rows:
=IF(Option@row <> "", MAX([Submission #]:[Submission #]))
Now we should have a section in the Form Sheet that looks like this:
And the whole Form Sheet (after a few test forms) looks like this:
STEP 3 - Set Up the Final Sheet
Now we can create our Final Sheet. To do this, I just created a new sheet, renamed the Primary Column to [Name], then copied a row from the Form Sheet to the Final Sheet to get the rest of the columns pushed through. I also deleted the standard columns that are automatically put in when creating a new sheet
STEP 4 - Copy Row Automation in Form Sheet
Then we hop back over to our Form Sheet and set up a Copy Row automation that looks like this:
Make a few test submissions to make sure everything is in fact linking up, and we should be up and running.
NOTE: We can also modify this to pull from submissions made using a multi-select dropdown, but this example is kept simple to provide the basics on getting this set up.
Re: Formula for last day in the month
There is not a function to find the last day in the month but you can write a formula using the DATE function, to calculate it. Because months have different lengths (28, 29, 30, 31 days), we need to find the start date of the subsequent month (which is always 1) and subtract on day to find the end date.
For example, if you want to know the last day in the month based on a date in a cell called "Base Date" (formated as Date Type) your formula would be
= DATE(YEAR([Base Date]@row), MONTH([Base Date]@row) + 1, 1) - 1)
If this formula is placed in another Date formatted column on the same row, it will return the last date of the month that Base Date is in.
It does it by creating a date:
- The year of which it takes from the Base Date cell. Let's say this was Jan 17th 2024. The year would be 2024.
- The month it also takes from the Base Date, and it adds 1 to it. So for Jan 17th the month in the new date is February.
- The day is always 1, i.e. Feb 1st.
It then subtracts one from this date, and that gives us the last day in January.
There is a slight complication in that you can't subtract 1 from the month of January to find December. 1-1 is not 12. So we add another little IF to return December 31st of the year in the Base Date cell, if the month is December.
= IF(MONTH([Base Date]@row) = 12, DATE(YEAR([Base Date]@row), 12, 31), DATE(YEAR([Base Date]@row), MONTH([Base Date]@row) + 1, 1) - 1))
You don't need to output these dates into columns, you can use them within formula. You also don't need to have a start date cell, you could use TODAY() to find the end date of the current month.
I hope this helps.
I noticed you had a couple of questions here that were not answered - I think they are being missed as they will not appear in the "unanswered questions" list. When asking questions in the community, please mark helpful answers as accepted and start new threads for new questions. This will prevent your subsequent questions from being missed (they look like follow-ups rather than new questions) and help other users with similar questions to find answers.
How I calculate HH:mm
Here's how I figured out HH:mm. I welcome all simplification suggestions.
The combined formula in A38 is this monstrosity (but it works):
=IFERROR(IF(INT(SUMIFS({Duration}, {CURWK}, 1, {Event Type}, A$37) / 60) < 10, "0" + INT(SUMIFS({Duration}, {CURWK}, 1, {Event Type}, A$37) / 60), INT(SUMIFS({Duration}, {CURWK}, 1, {Event Type}, A$37) / 60)) + ":" + IF(MOD(SUMIFS({Duration}, {CURWK}, 1, {Event Type}, A$37), 60) < 10, "0" + MOD(SUMIFS({Duration}, {CURWK}, 1, {Event Type}, A$37), 60), MOD(SUMIFS({Duration}, {CURWK}, 1, {Event Type}, A$37), 60)), "00:00")
----------------------------------------------------
{CURWK} - checkbox in data source indicating whether the event is "this" week
{Event Type} - single-select dropdown column in data source indicating the type of event
{Duration} - text/number column in data source with #minutes for each event
Using OR with the CONTAINS function (-or- How to Hack the CONTAINS Function)
This one comes up a lot, so I thought I would provide a few ways to solve it. The question is this: can I use the OR function in the CONTAINS function? For instances, you want to see if a cell contains "apple", "banana", or "orange".
In short, you can't use OR in the CONTAINS function (TLDR: because OR provides binary true/false outputs, so it doesn't make sense to put variables inside it).
But let me provide two solutions:
1.) Wrapping multiple CONTAINS functions within the OR functions. Yes, this is what many people are trying to avoid, but it does the job. This is formatted like this:
=IF(OR(CONTAINS("apple", column@row), CONTAINS("banana", column@row), CONTAINS("orange", column@row)), "Fruit!", "No Fruit!")
Now the OR function is searching for instances where any of the CONTAINS statements are true, meaning if any of the fruit names are inside the referenced cell.
2.) Hack! Reverse the polarity (this is my favorite) -- you can sometimes flip the "search for" and "search within" portions of the CONTAINS function like this:
=IF(CONTAINS(column@row, "apple banana orange"), "Fruit!", "No Fruit!")
Now your IF statement is looking for IF the entry in column@row is contained in the string "apple banana orange". Is the value in column@row "apple"? Great! "Fruit!"
This only works if column@row contains the actual fruit names. It wouldn't work if it contained a statement like "I like to eat apples", because that statement doesn't exist in the string "apple banana orange". But there are a ton of uses for this flipped version of the CONTAINS function, and when it works, it's a lot tidier. I use it often to exclude certain items from lists that are thousands of lines long. For instance, if I have a list of lot numbers I need to reference, but I know that 5 of 10,000 are bad, I can exclude them with a formula like this:
=IF(CONTAINS(lotnumber@row, "AX3432 AC3924 AF4030 AQ2020"), "NA", lotnumber@row)
This format makes it really easy for me to add to the exclusion list over time -- I just stick them in the list.
If you have fancy shifting variables you want to look for, you can replace the string with a JOIN COLLECT combination function. For instance:
=IF(CONTAINS(lotnumber@row, JOIN(COLLECT({bad lots}, {lot signifier}, "bad"), " ")), "NA", lotnumber@row)
The above example could be accomplished via other means, but this is just to show that the contains function is pretty flexible.
I hope this is helpful!
Using DataMesh to Split One Line Onto Multiple Lines (for Forms Entries and Other Uses)
This is a problem I've heard a few times so I'm answering it in a separate post for reference in long form. I'm using the example from @WtaylorW's question over here. The basic need is to take one line and split it onto multiple lines. In this example you have a form that's inputting multiple names in different columns, and you want a single line entry for each name.
Here's how to do it with DataMesh:
You'll need two sheets, called "Form Entry" and "Final Entries" for this example. The form responses, as expected, will load directly into the Form Entry sheet, and a single DataMesh configuration will port the entries into the Final Entries sheet. You can do this with a column formula that rotates a unique ID and name field. Read on!
Final Entries - Sheet Setup
The Final Entries sheet will contain the first seven columns from the above example, up to the "Name" column. It will contain one additional column called "UniqueEmpID".
Form Entry - Sheet Setup
The Form Entries sheet will look the same as the above example, except for the addition of these two columns:
- RowID: a column with the type "Row ID" to create a unique ID.
- UniqueEmpID: this is the rotating unique ID column, created with the below column formula (see immediately below the formula for an explanation). Note I've created this column with the same name on both sheets, but only the Form Entry sheet has a formula.
=IF(AND(NOT(ISBLANK([Employee Name 1]@row)), COUNTIFS({Final Sheet UniqueEmpID}, RowID@row + "A")=0), RowID@row+"A", IF(AND(NOT(ISBLANK([Employee Name 2]@row)), COUNTIFS({Final Sheet UniqueEmpID}, RowID@row + "B")=0), RowID@row+"B", IF(AND(NOT(ISBLANK([Employee Name 3]@row)), COUNTIFS({Final Sheet UniqueEmpID}, RowID@row + "C")=0), RowID@row+"C", IF(AND(NOT(ISBLANK([Employee Name 4]@row)), COUNTIFS({Final Sheet UniqueEmpID}, RowID@row + "D")=0), RowID@row+"D", ""))))
Let me explain the first line of the formula first. The IF statement is looking for two things:
- is there a name in the Employee 1 column?
- in the Final sheet, is there an entry in the UniqueEmpID column equal to the RowID with the letter A appended to it? For instance, if it's row 12, the formula is looking for the unique ID "12A". The COUNTIF counts instances of the ID, therefore a count of "0" would mean it's not on the target page.
If there is an name present on the form entry and the unique ID is not yet on the Final sheet, then the formula will create the unique employee ID (the "12A" in the above example).
However, if the employee ID is on the Final sheet, then it will go to the next line, which repeats the process for Employee 2, except that it appends a "B" instead of an "A". This continues down the list of employees. This is all structured for the DataMesh config and explained at the bottom of this post.
Your name column is going to have the same formula as the UniqueEmpID column, except instead of the output being RowID@row+"A", it will be [Employee Name 1]@row. That formula is:
=IF(AND(NOT(ISBLANK([Employee Name 1]@row)), COUNTIFS({Final Sheet UniqueEmpID}, RowID@row + "A")=0), [Employee Name 1]@row, IF(AND(NOT(ISBLANK([Employee Name 2]@row)), COUNTIFS({Final Sheet UniqueEmpID}, RowID@row + "B")=0), [Employee Name 2]@row, IF(AND(NOT(ISBLANK([Employee Name 3]@row)), COUNTIFS({Final Sheet UniqueEmpID}, RowID@row + "C")=0), [Employee Name 3]@row, IF(AND(NOT(ISBLANK([Employee Name 4]@row)), COUNTIFS({Final Sheet UniqueEmpID}, RowID@row + "D")=0), [Employee Name 4]@row, ""))))
DataMesh Configuration Setup
Setup your DataMesh configuration as follows:
- source sheet = Form Entry sheet, with Lookup Value "UniqueEmpID"
- target sheet = Final Entries sheet, with the Lookup Value "UniqueEmpID"
- for Data Fields, each column will copy its corresponding column (it doesn't matter if you include UniqueEmpID or not in the Data Field). Make sure to include the "Name" column, but DO NOT reference the Employee Name 1, 2, 3, etc columns from the Form Entries sheet.
- set your options for the config as noted in the below screenshot
What Happens
When a form submission lands on the Form Entry sheet, the UniqueEmpID formula will first look for the unique ID for Employee 1 (example, "12A") on the Final Entries sheet (in the corresponding UniqueEmpID column). If it doesn't see it, that cell will display the unique ID "12A". Similarly, the Name cell will do the same, except it will display the name of Employee 1.
The DataMesh config is set to "Copy and Add Data" -- that means if the unique ID 12A doesn't exist in the final sheet (which we know it doesn't because the formula checked), it will add that unique ID and the rest of the information in the corresponding columns.
At this point, the unique ID now exists in the Final Entries sheet, so the UniqueEmpID formula will now execute the entry for employee 2, triggering the DataMesh again, etc.
When I've setup similar processes, it works surprisingly quickly, spinning through the different options in moments and copying the data for all entries in a few seconds, but it's DataMesh, so results will vary.
You'll have to modify this slightly for your own purposes, of course. I hope this is helpful to some people. Let me know if you have questions!
Converting a Text Timestamp into a Numeric Timestamp Value
Problem: When timestamps are imported into smartsheet, the timestamp must be imported as a text field to retain its time aspect. Although the timestamp can be separated into a Date field and a Time field, this separation of Date and Time makes arranging the sheet into timestamp chronological order difficult.
Solution: Converting the data into a numeric value would allow chronological sorting. The formula below in the ‘Julian Timestamp’ column converts Date and Time into a numeric value that can be used for chronological ranking, or finding the MIN, MAX, etc. Note that these numeric values cannot be used to directly determine durations between times since time is based on a 1/60th scale, not based in tenths or hundredths of the decimal scale.
Below is a screenshot of my sheet. Data is imported into this sheet every 15min from an external data source. That data source generates a timestamp. In my process, I need to be able to always chart the 10 most recent data points in any rolling 24hr period.
These are my formulas
Timestamp Date: (Note my dates are US formatted (MM,DD,YYYY)
=DATE(VALUE(LEFT(timestamp@row, 4)), VALUE(MID(timestamp@row, 6, 2)), VALUE(RIGHT(timestamp@row, 2)))
Timestamp Time:
=TIME(MID(id@row, 13, 5))
Information on the TIME function can be found here
Julian Timestamp:
=VALUE(RIGHT([Timestamp Date]@row, 2) + YEARDAY([Timestamp Date]@row) + "." + LEFT([Timestamp Time]@row, 2) + RIGHT([Timestamp Time]@row, 2))
The Right function is parsing the 2 digit Year number from the timestamp field. The YEARDAY function returns a number representing the day in the year, 1 through 365, where 1 is the first day of the year. In the Julian timestamp formula this represents the digits to the left of the decimal place. In the screenshot the formula output yields year 24, day number 52, or 2452. The formula adds the decimal, then enters the time value as a 4 digit decimal value, as shown in the green row time 17:12 is converted to decimal 1712. The VALUE function that envelopes the entire formula converts the textstring that visually looks like a number into an actual numeric value. Note: The column header is only named ‘Julian Timestamp’ and is not a true Julian date.
Finally, my use case needs to rank the timestamps so that the 10 most recent timestamps are always identifiable.
Order:
=RANKAVG([Julian Timestamp]@row, [Julian Timestamp]:[Julian Timestamp], 0)
Community で人気のコメント(2) 親行・子行セットの自動追加
Smartsheet Community (英語版)で人気のコメントのうち、「いいね!」と思ったものをご紹介します。
第2回目は、Smartsheetの コミュニティでの数式の達人、ポール・ニューカム( @Paul Newcome )さんがベストプラクティスとして提案した、「子行をAPIやブリッジを使わずに自動で作る」についての記事です。
https://community.smartsheet.com/discussion/comment/420406#Comment_420406
はじめに
プロジェクト管理などのシートに、メインタスクとそれを構成するサブタスク(子タスク)をフォームなどで自動追加したい場合、 Smartsheetの数式には自動でインデントを作る機能がないので、インデント付きの行の追加の機能のあるSmartsheet APIやブリッジ * を使う必要がありました。
ポールさんの提案した方法を使えば、フォームに親行を構成する列の情報(タスク名、説明、連絡先、ドロップダウンリストなど)を入力すると、その親行とそれに付属するインデントされた子行(子タスク・サブタスク)のセットを自動的に作成することができます。
*ブリッジとはSmartsheetでプログラム的な操作を行うことができるプレミアムアプリです。
階層構造の親タスク・サブタスクのセットが自動追加されたシート(選択されているエリア)のイメージ
https://app.smartsheet.com/b/publish?EQBCT=ed3f653f80b043758a23e54fb59e8168
入力フォームのイメージ
https://app.smartsheet.com/b/form/eeedf60c1f164e06a36e5507ba66275d
具体的方法
フォームシートを用意
まず、親タスク・サブタスクのセットを自動追加するシート以外に、上記のフォームのデータが入力される別のシート(フォームシート、下のイメージ)を用意します。
https://app.smartsheet.com/b/publish?EQBCT=9a4853f69e2240398a3bd726a76e8b34
フォームシートの構造
フォームシートには親行として自動追加する列と同じ構造のフォーム入力用の列を追加します。例えば、上のイメージで言えば、親行として用いるタスク名、説明、日付などの各列に対応して、 F_タスク名、F_説明、F_日付などの列を追加します。 (F_はフォームからくるという意味ですがポールさんの例のようにForm Field A, Form Field Bなど任意の名前で大丈夫です。)
自動追加の仕組み
ポールさんの方法は、Smartsheetのフォーム、数式、自動化などの機能を組み合わせて実現しています。
フォームの新しいエントリーがデフォルトでシートの下部に追加されることを利用
まず、フォームがデフォルトでは最後の行に追加されることを利用しています。このことを利用して、直近に追加されたデータが最下行にあるので、以下の数式を第1行目のタスク名、説明、日付などの各列に置くことで、第1行目に新しいデータがフォームから入力されたときに、そのデータでタスク名、説明、日付などの値を更新することできます。
タスク名 =INDEX([F_タスク名]:[F_タスク名], MATCH(MAX([行 ID]:[行 ID]), [行 ID]:[行 ID], 0))
説明 =INDEX([F_説明]:[F_説明], MATCH(MAX([行 ID]:[行 ID]), [行 ID]:[行 ID], 0))
日付 =INDEX([F_日付]:[F_日付], MATCH(MAX([行 ID]:[行 ID]), [行 ID]:[行 ID], 0))
式を少し説明すると、行 IDは自動番号で、MATCH(MAX([行 ID]:[行 ID]), [行 ID]:[行 ID], 0)で一番最後の行の行 ID(上のイメージでは7)を取得します。(ここで使われているMAX([行 ID]:[行 ID])は、最下行などを取得するときによく使われるテクニックです。)
次に、INDEX(INDEX([F_タスク名]:[F_タスク名], 7) により7行目のF_タスク名にある列名の変更の値を取得します。
自動化の行のコピーでインデントされた子行もコピーされることを利用
以上により、フォームから新しいエントリーがあると、第1行目のタスク名、説明、日付などの値が更新されます。この値の更新をトリガーとして、その行を親行、子行のセットを追加したいシート(最上部のワーキングシート)にコピーする自動化を設定します。
自動化で行がコピーされるとき、インデントされた子行も一緒にコピーされるので、結果として、親行、子行が目的のシートに自動追加されます。
まとめ
プロジェクト管理などのシートに、メインタスクとそれを構成するサブタスク(子タスク)をフォームなどで自動追加したい、といった場合に、もちろんAPIやブリッジなどの高度な機能を用いて実現することもできますが、今回のポールさんの提案の優れているところは、既存のSmartsheetの機能をうまく組み合わせて、実用的な代替手段を提供しているところです。
Smartsheetの コミュニティではポールさんのようなグル(guru)が様々なクリエイティブな利用方法を発表しており、Smartsheetユーザにとっての知識の宝庫です。
Communityで人気のコメント
Smartsheet Community (英語版)で人気のコメントのうち、「いいね!」と思ったものをご紹介します。
第1回目は、Smartsheetの コミュニティチームのジュヌヴィエーヴ(Genevieve P.)さんが回答した、「同じプロジェクトシート内の異なる設定」についての回答です。
https://community.smartsheet.com/discussion/comment/418646#Comment_418646
はじめに
Smartsheetで同じプロジェクトシート内に、異なる勤務日と時間を持つタスクを作成する方法について質問がありました。
具体的には、週7日勤務(土日祝日なし)と、週5日勤務(祝日あり)のタスクを同じシートで管理したいというご要望でした。
質問の要約
異なる勤務日と時間を持つタスクを同じプロジェクトシートで作成することは可能ですか? 週7日勤務と週5日勤務のタスクをどのように管理すればよいですか?ダッシュボードは使用しません。
答えの要約
はい!プロジェクトシートで特定の勤務日と時間(例えば週5日勤務と休日)を有効にしている場合、週7日勤務にしたい特定の行では、期間の前にeを追加することで経過時間を使うこと
下のデモシートはジュヌヴィエーヴさんのデモシートを日本語化したものです。
https://app.smartsheet.com/b/publish?EQBCT=a343fb0967ab4c43aa190f2772ee979c
方法
プロジェクトシートで特定の勤務日と時間(例:週5日勤務と休日)を有効にします。
週7日勤務にしたい特定の行では、期間の前にeを追加することで経過時間を使用します。
詳細
期間と先行タスクを使う:
期間の列で継続期間を使用すると、非稼働日が考慮されません。 継続3日、継続5時間、継続3.5日のように表示されますが、e3d、e5h、e3.5d と入力してもかまいません。また、「継続」の代わりに「継続期間」や「継続時間」と入力することもできます。
ポイント
週7日勤務と週5日勤務のタスクを区別するために、e記号を使用する。
Turn Numbers Into Letters
Here's a handy formula to turn the numbers 1-26 into letters. Assume that the number you want to convert is in a column called "Number". In another column, create the following formula:
=RIGHT(LEFT("ABCDEFGHIJKLMNOPQRSTUVWXYZ", Number@row), 1)
If you need to increment these beyond Z, it gets a little more complicated, but here's how you can do it using the pattern, "...X, Y, Z, AA, AB, AC..." (going up to "ZZ", which is 702 character combinations):
=RIGHT(LEFT("ABCDEFGHIJKLMNOPQRSTUVWXYZ", ((Number@row - IF(MOD(Number@row, 26) = 0, 26, MOD(Number@row, 26))) / 26)), 1) + RIGHT(LEFT("ABCDEFGHIJKLMNOPQRSTUVWXYZ", IF(MOD(Number@row, 26) = 0, 26, MOD(Number@row, 26))), 1)