Description
In an SQLite database I am using a prepared statement to look up a record in a table storing component data. Each component has two names, a schematicName
and a name
(which can be null), When I search the table I need to find records that match the name
or schematicName
. So far this could be easily done with something like this:
return sqlpp::select(
all_of(components)
.from(components)
.where(
(components.name.is_not_null() and (components.name == sqlpp::parameter(components.name))
or (components.schematicName == sqlpp::parameter(components.schematicName)))
);
But I also need to know what the match was made on, the name
or the schematicName
. To this I would ideally use a calculated column with an alias, e.g.:
auto matchCalc_exp =
case_when(components.name == sqlpp::parameter(components.name))
.then(0)
.else_(case_when(components.schematicName
== sqlpp::parameter(components.schematicName))
.then(1)
.else_(3))
.as(matchQualifier);
In an ideal world I could use this alias matchQualifier
in the where clause instead of doing the equality checks again. If it worked, it could translate into the following SQL:
SELECT tblComponents.*,
(CASE WHEN (tblComponents.name=?1) THEN 1
ELSE (CASE WHEN (tblComponents.schematicName=?2) THEN 0
ELSE 3
END)
END) AS matchQualifier
FROM tblComponents
WHERE (matchQualifier != 3)
But I just could not find any way to make this work.
- I could not find any way to use an aliased column in the where clause.
- Directly using the expression in the where clause makes duplicating the parameters which results in a compile error. (Even if it worked, the resulting query would not be too efficient either.)
- Ideally, I would like to use just one parameter, a
searchName
instead of needing to assign the same string value to bothmyQuery.params.name
andmyQuery.params.schematicName
, but this results in duplication as well, so does not compile. - Tried to use sqlpp::verbatim() in the where clause to add
matchQualifier != 3
but could not make it work. All it gave me was a static_assert: Invalid operand(s) - I tried to make a temporary table alias to the query with the extra matchQualifier column which actually compiled, but then the parameters of the expression are not visible in the prepared statement and I am back to square one. Besides, with this approach I would run the select twice on the table (
SELECT * FROM (SELECT *, CASE WHEN ... AS matchQualifier) WHERE ...) WHERE matchQualifier != 3
) which is not too healthy.
Update
I found how I can use the expression in the WHERE clause. Removing the .as(matchQualifier)
part does the trick. Then the expression can be directly compared with another sqlpp value, e.g.: .where(matchCalc_exp != sqlpp::value(3))
.
However, I now realize that my initial query design is less than optimal, To be able to utilize indexes on the name fields I have to have the names in the where clause. In this case if I wanted to have my calculated matchQualifier
field I would need to use the same expression there, but it would then require me to use different parameter aliases.
So all my above questions really boil down to:
Can the same parameter be used in multiple places in the same prepared statement?