I know this is an old thread but I have a technique that works fairly well for this:
Wrap your data range with curly braces { } so query will use the Col1, Col2 syntax rather than A, B column names.
Use match to query your header row and find the column number you want to query.
Dynamically insert that row into your query string. It makes for a more complex query, but it's relatively maintainable as the primary value you modify over time is a plain text column name.
I'm using index to return the header row of a table:
index(Customer_Matrix[#ALL],1,0)
And then using match to search the header row for the column I need:
match("Horizontal Use Cases",index(Customer_Matrix[#ALL],1,0),0)
And that allows me to construct a query which can dynamically refer to table rows by name. Deleting or re-ordering table rows no longer breaks your query.
query({Customer_Matrix},"select Col1 where Col" & match("Horizontal Use Cases",index(Customer_Matrix[#ALL],1,0),0) & " contains '" & A30 & "'")