patternsqlMinor
PostgreSQL WHERE clause with two OR'ed conditions, priority to first
Viewed 0 times
postgresqlprioritywithwheretwofirstconditionsclause
Problem
I'm storing user data (username, email, password hash) in PostgreSQL, and I can only enforce uniqueness on
For example, in the following contrived instance:
if both users enter their username, I want to guarantee that user 2 gets logged in.
If I use:
this matches both users but provide no guarantee on order.
Is there a way to have to conditions, and only check the second condition if the first isn't satisfied? Can this be done in a single query?
username. I'd like to let users provide either their username or their email when they login. However, when matching their input against usernames and email addresses I want to ensure that a username match gets priority over an email match.For example, in the following contrived instance:
id | username | email address | pw_hash
-------------------------------------------------
1 john_doe john@domain.com x1j34
2 john@domain.com john@domain.com x1j34if both users enter their username, I want to guarantee that user 2 gets logged in.
If I use:
SELECT * FROM member WHERE (username='john@domain.com' OR email='john@domain.com') AND pw_hash='x1j34';this matches both users but provide no guarantee on order.
Is there a way to have to conditions, and only check the second condition if the first isn't satisfied? Can this be done in a single query?
Solution
You have two conditions to check during the authentication:
-
There is a user with matching username; do not need to match by email.
-
There are no users with matching usernames; need to match by email.
So the query is:
On the other hand, there is a problem with your design of the table.
What if two users have have the same email, but neither of them have email as their username? If one of them tries to authenticate with an email, you will not be able to tell, which user record to authenticate against.
-
There is a user with matching username; do not need to match by email.
-
There are no users with matching usernames; need to match by email.
So the query is:
WITH matching_username AS (SELECT * FROM member WHERE username = 'john@domain.com')
SELECT * FROM matching_username WHERE (SELECT COUNT(*) FROM matching_username) = 1
AND pw_hash = 'x1j34'
UNION
SELECT * FROM member WHERE (SELECT COUNT(*) FROM matching_username) = 0
AND email = 'john@domain.com'
AND pw_hash='x1j34';On the other hand, there is a problem with your design of the table.
What if two users have have the same email, but neither of them have email as their username? If one of them tries to authenticate with an email, you will not be able to tell, which user record to authenticate against.
Code Snippets
WITH matching_username AS (SELECT * FROM member WHERE username = 'john@domain.com')
SELECT * FROM matching_username WHERE (SELECT COUNT(*) FROM matching_username) = 1
AND pw_hash = 'x1j34'
UNION
SELECT * FROM member WHERE (SELECT COUNT(*) FROM matching_username) = 0
AND email = 'john@domain.com'
AND pw_hash='x1j34';Context
StackExchange Database Administrators Q#67840, answer score: 2
Revisions (0)
No revisions yet.