Reputation: 2148
I have a table with data similar to the following.
I've been using a large table with numerous rows with varying flags, and keys. I've managed to group them down so that I have the lowest where the flag is true, and the lowest where the flag is false.
╔══════════════════╦══════╦═══════╗
║ Email ║ Flag ║ Key ║
╠══════════════════╬══════╬═══════╣
║ [email protected] ║ 1 ║ 77731 ║
║ [email protected] ║ 0 ║ 67980 ║
║ [email protected] ║ 1 ║ 64417 ║
║ [email protected] ║ 0 ║ 71733 ║
║ [email protected] ║ 1 ║ 95655 ║
║ [email protected] ║ 0 ║ 91016 ║
╚══════════════════╩══════╩═══════╝
Now, for each distinct email, if there is a true AND false flag, I want to return the true Key value. Otherwise, I want to return the lowest value.
So the output would ideally look like this:
╔══════════════════╦══════╦═══════╗
║ Email ║ Flag ║ Key ║
╠══════════════════╬══════╬═══════╣
║ [email protected] ║ 1 ║ 77731 ║
║ [email protected] ║ 1 ║ 64417 ║
║ [email protected] ║ 1 ║ 95655 ║
║ [email protected] ║ 0 ║ 91016 ║
╚══════════════════╩══════╩═══════╝
I've been trying all kinds of grouping, having clauses, using case statements in the previous two, but can't see how to do so.
I only really need the email and the Key, if that helps.
Upvotes: 1
Views: 728
Reputation: 12485
You could also accomplish this through a window function:
SELECT email, flag, key FROM (
SELECT email, flag, key, ROW_NUMBER() OVER ( PARTITION BY email ORDER BY flag DESC ) AS rn
FROM mytable
) x1
WHERE rn = 1;
Upvotes: 0
Reputation: 117
SELECT
A.Email
,CASE WHEN A.Cf > A.Sf THEN Mk ELSE Key END AS ChosenKey
FROM
(
SELECT
Email
,Key
,COUNT(Flag) Cf
,MIN(Key) OVER(PARTITION BY Email ORDER BY Key ASC) AS Mk
,SUM(Flag) OVER(PARTITION BY Email) Sf
FROM
Table
) AS A
Maybe work from something like that? And then remove your duplicates etc.
Upvotes: 0
Reputation: 118947
There's lots of ways, here are two.
Method 1
You could do it with a CTE like this:
WITH data_cte AS (
SELECT Email, MAX(CAST(Flag AS INT)) AS Flag
FROM Data
GROUP BY Email)
SELECT Data.*
FROM data_cte
JOIN Data
ON Data.Email = data_cte.Email
AND Data.Flag = data_cte.Flag
To de-construct it, the CTE part just gets the MAX
value of flag for each email (need to CAST
to INT
as you can't MAX
on a BIT
column) and the rest of the query joins the CTE back to the table to get the relevant data rows.
Method 2
Using a UNION
:
SELECT *
FROM Data
WHERE Flag = 1
UNION
SELECT *
FROM Data
WHERE Flag = 0
AND NOT EXISTS(SELECT *
FROM Data AS InnerData
WHERE InnerData.Flag = 1
AND InnerData.Email = Data.Email)
Upvotes: 1