Skip to content

FILTER around QUERY treats the header row as data and the heights stop matching

Updated

QUERY with a headers argument of 1 puts a label row on the result. That row is part of the array FILTER receives. FILTER does not know it is a label. It tests it like a record, or it refuses the call because your condition range is still the height of the original sheet. The East rows you can see in the grid are not the rows FILTER is counting.

How 0 and 1 treat the first row of a plain QUERY, including on IMPORTRANGE, is QUERY headers 0/1. This page is the wrap: FILTER around that result. Keep the Google Sheets UI in English. Sheet Error is an independent formula-error library, not a Google product.

  1. Open a blank spreadsheet. In A1 type region, B1 qty. A2 East, B2 10. A3 West, B3 4. A4 East, B4 20. Two East rows, quantities 10 and 20. West is 4.

QUERY alone, headers 1. Leave D2:E4 empty. In D1 type q. In D2 enter =QUERY(A1:B4,"select A, B where A = 'East'",1). The spill is three rows: the labels region and qty, then East 10, then East 20. West is gone. The label row was not filtered. It is not a third East. That block is the control for what QUERY actually returned.

FILTER with a condition taken from the sheet. In D6 type hybrid. In D7 enter =FILTER(QUERY(A1:B4,"select A, B where A = 'East'",1),A1:A4="East"). The cell is #N/A. The tooltip says FILTER has mismatched range sizes. The QUERY result is 3 rows. A1:A4 is 4 rows. FILTER will not pad, and it will not drop the label to make the heights agree. Leave D7 broken.

D7 selected. Formula bar shows FILTER of a QUERY where region is East, with condition A1:A4 equal to East. D7 is #N/A. Tooltip: FILTER has mismatched range sizes. D2 still shows region/qty, East 10, East 20.

The label is inside the test. In G1 type body. In G2 enter =QUERY(A1:B4,"select A, B where A = 'East'",1). Same spill as D2. In I2 enter =FILTER(G2:H4,H2:H4>15). H2 is the text qty. qty>15 is #VALUE!, so the FILTER errors. The number 20 is on the sheet, in H4. The condition never got a clean column of quantities, because row 2 of the spill is the label. Leave I2 broken.

headers 1 on a range that already starts at the first record. In G6 enter =QUERY(A2:B4,"select A, B where A = 'East'",1). A2:B4 has no title row, but 1 still takes the first row as labels. Those labels are East and 10, and they are not tested by where. The data rows are West 4 and East 20. The spill shows East 10 on top and East 20 under it. The 10 looks like a row that passed the filter. It is the label, copied from A2. Leave G6 as that misleading pair.

Leave D7 and I2 broken. Leave D2 as the honest three-row QUERY.

  • FILTER measures the array it was given. A QUERY with headers 1 is one row taller than the matching records. A condition built from A1:A4 is the sheet’s height, including the title and including West. Those two heights are not the same number. D7 is FILTER range size caused by the label row.
  • Once the spill is on the sheet, H2:H4 includes the word qty. A numeric comparison against text is #VALUE!, and FILTER fails the whole call. It does not skip the label and keep East 20.
  • headers 1 on A2:B4 promotes the first East row into the label. where never sees it. The output still prints it. A later FILTER that assumes “every row under the formula is a hit” will treat 10 as a match. The headers primer is QUERY headers 0/1.
  • Putting both tests in QUERY avoids the second pass. and in the query string is one array, with one header policy. Splitting the work across FILTER and QUERY is what mis-counts the rows.

This is not QUERY returning no rows. See QUERY no rows only when the query language itself reports an empty result. D2 returned East.

Leave D7 and I2 broken.

Keep the test inside QUERY. In D10 enter =QUERY(A1:B4,"select A, B where A = 'East' and B > 15",1). The spill is the labels, then East 20. One array. The label is only the label. West and East 10 are both absent for reasons you can read in the query string.

D10 selected. Formula bar shows QUERY select A, B where A equals East and B greater than 15, headers 1. The spill is region/qty and East 20. D7 is still the mismatched FILTER. I2 is still the broken comparison on qty.

If you do FILTER, test the body under the label, not the sheet. In G10 enter =QUERY(A1:B4,"select A, B where A = 'East'",1). That is the same spill as D2: label on row 10, East 10 on row 11, East 20 on row 12. In I10 enter =FILTER(G11:H12,H11:H12>15). The condition is two cells, the body only. I10 spills East 20. H10 is the word qty, and it is not in the condition. The range you test is the spill’s records, not A1:A4.

Do not wrap D7 in IFERROR. The mismatch is the diagnosis. See IFERROR vs IFNA.

If FILTER(QUERY(...)) says the ranges are mismatched, the header row is inside one side and not the other. If the first “match” is actually the next row’s values printed as labels, headers is 1 on a range that already starts at the data. Move the predicate into where, or drop the label before FILTER sees it.