Chọn các hàng có cùng id nhưng null và một số giá trị khác trong cột khác cho id đó


9

Tôi muốn chỉ nhận các hàng có một giá trị NULLvà một số giá trị khác ngoài NULLmột cột tên người dùng cụ thể.

Nếu cả hai hàng đều có null cho tên người dùng cụ thể đó hoặc cả hai có một số giá trị khác với null thì nó sẽ không xuất hiện trong đầu ra. Nếu có nhiều hơn hai hàng cho cùng một tên người dùng với null và một số giá trị khác thì chúng sẽ xuất hiện.

Dưới đây là ví dụ mẫu và đầu ra. Làm thế nào nó có thể được thực hiện bằng cách sử dụng truy vấn sql?

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

đầu ra

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

1
Nếu có 2 hàng với d, dervà 2 với d, nullthì sao?
ypercubeᵀᴹ

1
@ypercube Sau đó, tất cả 4 hàng của d sẽ xuất hiện
nghiên cứu CNTT

1
Nếu có hàng với e, one, e, twovà 2 hoặc nhiều hơn với e, null?
ypercubeᵀᴹ

1
@ypercube thì tất cả các hàng sẽ xuất hiện.
nghiên cứu CNTT

Câu trả lời:


12

Bạn sẽ có thể sử dụng kết hợp có điều kiện để có được tên người dùng với cả một giá trị trong col2cũng như null.

Tôi đề nghị sử dụng mệnh đề HAVING với các điều kiện. Truy vấn sẽ tương tự như:

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

Xem SQL Fiddle với Demo . Truy vấn này nhóm dữ liệu của bạn theo từng tên người dùng và sau đó sử dụng logic có điều kiện để kiểm tra xem có col2đáp ứng cả hai điều kiện bạn muốn không - col2không phải là null col2 là null.

Sau đó, bạn có thể sử dụng điều này trong truy vấn con, v.v. để lấy usernamecol2các giá trị:

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

Xem SQL Fiddle với Demo .

Nếu bạn có nhiều hơn một col2hàng với cả hai nullvà một giá trị khác, thì bạn chỉ cần thay đổi HAVINGmệnh đề một chút:

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;

Xem SQL Fiddle với bản demo


Truy vấn của bạn đã bỏ lỡ một điểm (thực ra tôi cũng không đề cập rõ ràng trong câu hỏi). Nếu có nhiều hơn hai hàng cho cùng một tên người dùng với null và một số giá trị khác thì chúng sẽ xuất hiện. trong truy vấn của bạn, họ sẽ không đến (ví dụ trong câu đố đó nếu có một hàng khác có tên người dùng 'c' và null hoặc một số giá trị.
nghiên cứu CNTT

1
@ITresearcher Đó là một sửa chữa đơn giản - bạn cần thay đổi HAVINGmệnh đề thành >=1- sqlfiddle.com/#!3/8af72/2
Taryn

Ok. Đúng vậy. Trả lời bởi JGA cũng hoạt động.
nghiên cứu CNTT

8

Giải pháp khác:

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

Kế hoạch thực hiện

Trong một tĩnh mạch logic tương tự:

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

Kế hoạch thực hiện

Còn nữa:

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;

Kế hoạch thực hiện


Câu trả lời tốt đẹp. Thậm chí nó có hiệu suất tốt hơn bcoz bàn của tôi là rất lớn.
nghiên cứu CNTT

5

Chỉ là một cách khác để làm điều đó:

; 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

Cái này hoạt động quá. Bản thử nghiệm SQL Fiddle

Tôi nhận được C1 là tổng số hàng cho mỗi tên người dùng, C2 là tổng số hàng null cho mỗi tên người dùng và tôi so sánh các giá trị này sau.

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

Tôi sẽ sử dụng truy vấn phụ để chọn những tên người dùng như:

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

-1

Tôi đã thử với cái này ...

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
Điều này sẽ gây ra một tham gia chéo. Nếu đối với tên người dùng, có 3 hàng có null col2 và 2 hàng có col2 không null, kết quả cuối cùng sẽ có 6 hàng, không phải 5. Và col2sẽ không có trong đầu ra.
ypercubeᵀᴹ
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.