Fix Google Sheets QUERY Failures with Transposed Arrays
A user on a Google Sheets help forum recently posted: “I am trying to combine several vertical columns into a single horizontal dataset using TRANSPOSE and ARRAYFORMULA, then run a QUERY on that result. However, the QUERY keeps returning #VALUE! or incorrectly merging my first row of data into the header. No matter what I put in the headers argument, it fails to parse properly.”
This is a common frustration. When you use curly braces {} to create an “array literal” (e.g., {Range1; Range2}), Google Sheets loses the metadata that tells it where the headers are. If you then nest TRANSPOSE or ARRAYFORMULA inside that array, the QUERY function becomes blind to your data structure.
The Minimal Working Example
Section titled “The Minimal Working Example”The most reliable way to fix this is to force QUERY to treat the entire input as data (0 headers) and manually define your headers outside the query if necessary.
The Setup:
Suppose you have vertical data in A2:A10 and B2:B10 that you want to flip horizontally and stack.
The Fix Formula:
=QUERY({TRANSPOSE(A2:A10); TRANSPOSE(B2:B10)}, "SELECT *", 0)Tested on Google Sheets as of 2024.
Why This Works
Section titled “Why This Works”The QUERY function has three arguments: =QUERY(data, query, [headers]).
When you use “natural” ranges like A1:C10, Google Sheets can often guess the headers. But once you use a “constructed” range (using {} or TRANSPOSE), the function gets confused. By explicitly setting the third argument to 0, you tell Google Sheets: “Do not try to guess. Just treat every row as data.”
| Argument | Value | Why it matters in nested formulas |
|---|---|---|
data |
{TRANSPOSE(A2:A10); ...} |
The curly braces create a new virtual table. |
query |
"SELECT * WHERE..." |
Keep your SQL-like syntax here. |
[headers] |
0 |
Crucial. Prevents QUERY from “guessing” and failing to parse the transposed array. |
Step-by-Step: Adapting to Your Own Data
Section titled “Step-by-Step: Adapting to Your Own Data”If you need to combine multiple transposed ranges and still want a header row at the top, follow these steps:
1. Construct the Header Manually
Section titled “1. Construct the Header Manually”Since QUERY is set to 0 headers, it won’t pull your top row automatically. You should include your headers inside the array literal using a semi-colon ; for a new row.
={ "Header 1", "Header 2", "Header 3"; QUERY({TRANSPOSE(A2:A10); TRANSPOSE(B2:B10)}, "SELECT *", 0) }2. Wrap in ARRAYFORMULA if needed
Section titled “2. Wrap in ARRAYFORMULA if needed”If your transposed ranges rely on logic (like IF statements), wrap the inner part of your query data in ARRAYFORMULA.
=QUERY(ARRAYFORMULA({TRANSPOSE(IF(A2:A10="", "N/A", A2:A10))}), "SELECT *", 0)3. Standardize Data Types
Section titled “3. Standardize Data Types”QUERY will fail if a single column contains mixed data types (e.g., numbers and text). Because TRANSPOSE can move different types into the same vertical column, ensure your source data is uniform before running the query.
Frequently Asked Questions
Section titled “Frequently Asked Questions”What if I need to apply this to filtered rows?
If you only want to transpose and query rows that meet a certain criteria, use the FILTER function inside your TRANSPOSE. For example: TRANSPOSE(FILTER(A2:A10, A2:A10<>"")). This ensures your QUERY isn’t processing hundreds of empty transposed cells, which can hit the column limit of Google Sheets (currently 18,278 columns).
Can I automate this with Apps Script?
While you can write a script to move and transpose data, it is rarely necessary. The QUERY function is more performant for live updates. If your dataset is so large that QUERY and TRANSPOSE are lagging, consider using getValues() and setValues() in Apps Script to perform the transformation in the background and paste the result as static values.
Why does it still say “Unable to parse query string”?
This usually happens if you reference a column letter (like SELECT A) inside the query string while using a constructed array {}. When using curly braces, you must use column numbers (e.g., SELECT Col1, Col2) instead of letters.
Updated Formula for Array Literals:
=QUERY({TRANSPOSE(A2:A10); TRANSPOSE(B2:B10)}, "SELECT Col1, Col2 WHERE Col1 IS NOT NULL", 0)