Reputation: 312
I have an SQL table:
country | state | county | city |
---|---|---|---|
'us' | 'ny' | 'steuben' | NULL |
'us' | 'ny' | 'steuben' | 'city a' |
'us' | 'ny' | 'steuben' | 'city b' |
'us' | 'ny' | NULL | NULL |
'us' | NULL | NULL | NULL |
NULL | NULL | NULL | NULL |
The goal is to have some sort of query where "country, state, county, and city" are always supplied, but what is provided may not exist in the table. If a supplied attribute isn't found, I would like the relevant 'NULL' value from the column.
Example: User provides "us, ny, steuben, city b" --> Row #3
Example: User provides "us, ny, steuben, city c" --> Row #1 because 'city c' is unknown
Example: User provides "us, ny, hamilton, city a" --> Row #4 because 'hamilton' is unknown
The original thought was:
SELECT *
FROM [location]
WHERE
(country = @country OR country IS NULL) AND
([state] = @state OR [state] IS NULL) AND
(county = @county OR county IS NULL) AND
(city = @city OR city IS NULL)
However, this will return the NULL rows indiscriminately. What I'm really looking for is some sort of logic like:
SELECT *
FROM [location]
WHERE
(country = @country IF EXISTS OR country IS NULL) AND
([state] = @state IF EXISTS OR [state] IS NULL) AND
(county = @county IF EXISTS OR county IS NULL) AND
(city = @city IF EXISTS OR city IS NULL)
Does anyone have a potential solution?
Note: If the answer varies with databases, I'm interested in MS-SQL.
Upvotes: 1
Views: 2643
Reputation: 1269953
You can use filtering and order by
:
select top (1) t.*
from t
where (t.country = @country or t.country is null) and
(t.state = @state or t.state is null) and
(t.county = @county or t.county is null) and
(t.city = @city or t.city is city)
order by ( (case when t.country = @country then 1 else 0 end) +
(case when t.state = @state then 1 else 0 end) +
(case when t.county = @county then 1 else 0 end) +
(case when t.city = @city then 1 else 0 end)
) desc;
The key is to order by the number of full matches descending.
Upvotes: 2