选择具有相同ID但为null的行,并在该ID的另一列中选择其他值


9

我只想获得具有值NULL和某些值的行,而不是NULL特定的用户名列。

如果该特定用户名的两行均为null或均具有null以外的其他值,则该行不应出现在输出中。如果同一个用户名存在多于两行的null和其他值,则应显示它们。

以下是示例示例和输出。如何使用sql查询来完成?

+----------+-------+
| username | col2  |
+----------+-------+
| a        | abc   |
| a        | ef    |
| b        | null  |
| b        | null  |
| c        | der   |
| c        | null  |
+----------+-------+

输出

+----------+------+
| username | col2 |
+----------+------+
| c        | der  |
| c        | null |
+----------+------+

1
如果有2行d, der和有2行d, null呢?
ypercubeᵀᴹ

1
@ypercube然后应显示d的所有4行
IT研究人员

1
如果存在带有的行e, onee, two以及具有2个或更多的行e, null
ypercubeᵀᴹ

1
@ypercube然后所有行都应该出现。
IT研究人员

Answers:


12

您应该能够使用条件聚集在这两个数值来获取用户名col2null

我建议在条件中使用HAVING子句。该查询将类似于:

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

请参阅带有演示的SQL Fiddle。此查询按每个用户名对数据进行分组,然后使用条件逻辑检查是否同时col2满足您想要的两个条件-其中col2不为null col2为null。

然后,您可以在子查询等中使用它来获取usernamecol2值:

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

请参阅带有演示的SQL Fiddle

如果您同时拥有多于col2一行null和另一个值,则只需要对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;

参见带有演示的SQL Fiddle


您的查询遗漏了一点(实际上我也没有明确提到问题)。如果同一个用户名有多于两行的null和其他值,则应显示它们。在您的查询中,它们就不会出现(例如,如果还有另一行的用户名是“ c”,并且为空或某个值,则不会出现。)
IT研究人员

1
@ITresearcher这是一个简单的解决方法-你需要更改HAVING条款是>=1- sqlfiddle.com/#!3/8af72/2
泰伦

好的,那是正确的。JGA的回答也有效。
IT研究人员

8

另一个解决方案:

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
);

执行计划

按照类似的逻辑:

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
    );

执行计划

完后还有:

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;

执行计划


好答案。即使它有更好的性能,因为我的桌子很大。
IT研究人员

5

只是另一种方式:

; 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 ;

4

这个也可以。 SQL Fiddle演示

我将C1作为每个用户名的总行,将C2作为每个用户名的总空行,然后在以后比较这些值。

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

3

我将使用子查询来选择以下用户名:

select username
from   dbo.yourtable
group by username
having sum(distinct case when col2 is not null then 1 else 2 end) = 3;

-1

我尝试过这个...

select a.username from  
(select username ,col2 
   from yourtable
where col2 is null) a,(select username ,col2 
                       from yourtable
                        where col2 is not null) b
where a.username=b.username;

2
这将导致交叉连接。如果对于用户名,有3行col2为空,而2行非col2为空,则最终结果将为6行,而不是5行,并且col2将不在输出中。
ypercubeᵀᴹ
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.