Je souhaite obtenir uniquement des lignes ayant une valeur NULL
et une autre valeur que NULL
pour une colonne de nom d'utilisateur particulière.
Si les deux lignes ont null pour ce nom d'utilisateur particulier ou si les deux ont des valeurs autres que null, cela ne devrait pas apparaître dans la sortie. S'il y a plus de deux lignes pour le même nom d'utilisateur avec null et une autre valeur, elles devraient apparaître.
Voici un exemple d'échantillon et de sortie. Comment cela peut-il être fait en utilisant la requête SQL?
+----------+-------+
| username | col2 |
+----------+-------+
| a | abc |
| a | ef |
| b | null |
| b | null |
| c | der |
| c | null |
+----------+-------+
production
+----------+------+
| username | col2 |
+----------+------+
| c | der |
| c | null |
+----------+------+
Vous devriez pouvoir utiliser l'agrégation conditionnelle pour obtenir le nom d'utilisateur avec à la fois une valeur dans col2
ainsi que null
.
Je suggère d'utiliser une clause HAVING avec les conditions. La requête serait similaire à:
select username
from yourtable
group by username
having sum(case when col2 is not null then 1 else 0 end) = 1
and sum(case when col2 is null then 1 else 0 end) = 1
Voir SQL Fiddle with Demo . Cette requête regroupe vos données par chaque nom d'utilisateur, puis utilise une logique conditionnelle pour vérifier si col2
remplit les deux conditions que vous souhaitez - où col2
n'est pas nul et col2
est nul.
Vous pouvez ensuite l'utiliser dans une sous-requête, etc. pour obtenir les username
et col2
valeurs:
select
t.username,
t.col2
from yourtable t
inner join
(
select username
from yourtable
group by username
having sum(case when col2 is not null then 1 else 0 end) = 1
and sum(case when col2 is null then 1 else 0 end) = 1
) d
on t.username = d.username
Voir SQL Fiddle with Demo .
Si vous en avez plusieurs col2
ligne avec à la fois null
et une autre valeur, il vous suffit alors de modifier légèrement la clause HAVING
:
select
t.username,
t.col2
from yourtable t
inner join
(
select username
from yourtable
group by username
having sum(case when col2 is not null then 1 else 0 end) >= 1
and sum(case when col2 is null then 1 else 0 end) >= 1
) d
on t.username = d.username;
Voir SQL Fiddle with Demo
Une autre solution:
SELECT Y1.*
FROM dbo.yourtable AS Y1
WHERE Y1.username = ANY
(
SELECT Y2.username
FROM dbo.yourtable AS Y2
WHERE Y2.col2 IS NULL
INTERSECT
SELECT Y3.username
FROM dbo.yourtable AS Y3
WHERE Y3.col2 IS NOT NULL
);
Dans la même veine logique:
SELECT Y.*
FROM dbo.yourtable AS Y
WHERE EXISTS
(
SELECT *
FROM dbo.yourtable AS Y2
WHERE Y2.username = Y.username
AND Y2.col2 IS NULL
)
AND EXISTS
(
SELECT *
FROM dbo.yourtable AS Y3
WHERE Y3.username = Y.username
AND Y3.col2 IS NOT NULL
);
Encore un autre:
SELECT
SQ1.username,
SQ1.col2
FROM
(
SELECT
Y.username,
Y.col2,
MinCol2 =
MIN(CASE WHEN Y.col2 IS NULL THEN -1 ELSE 1 END)
OVER (PARTITION BY Y.username),
MaxCol2 =
MAX(CASE WHEN Y.col2 IS NULL THEN -1 ELSE 1 END)
OVER (PARTITION BY Y.username)
FROM dbo.yourtable AS Y
) AS SQ1
WHERE
SQ1.MinCol2 = -SQ1.MaxCol2;
Juste une autre façon de le faire:
; WITH cte AS
( SELECT username, col2,
cnt_all = COUNT(*) OVER (PARTITION BY username),
not_null = COUNT(col2) OVER (PARTITION BY username)
FROM yourtable AS a
)
SELECT username, col2
FROM cte
WHERE cnt_all > not_null
AND not_null > 0 ;
Celui-ci fonctionne aussi. SQL Fiddle
J'obtiens C1 comme nombre total de lignes pour chaque nom d'utilisateur, C2 comme nombre total de lignes nulles pour chaque nom d'utilisateur et je compare ces valeurs plus tard.
SELECT username, col2 FROM
(
SELECT *,
(SELECT Count(*) FROM T Where username = T1.username) C1,
(SELECT Count(*) FROM T Where username = T1.username and col2 is null) C2
FROM T T1
) T2
WHERE C2 > 0 And C1 <> C2
J'utiliserais la sous-requête pour sélectionner ces noms d'utilisateur comme:
select username
from dbo.yourtable
group by username
having sum(distinct case when col2 is not null then 1 else 2 end) = 3;