Pilih baris dengan id yang sama tetapi nol dan beberapa nilai lainnya di kolom lain untuk id itu

9

Saya hanya ingin mendapatkan baris yang memiliki nilai NULLdan beberapa nilai lain selain NULLuntuk kolom nama pengguna tertentu.

Jika kedua baris memiliki null untuk nama pengguna tertentu atau keduanya memiliki beberapa nilai selain nol maka seharusnya tidak muncul dalam output. Jika ada lebih dari dua baris untuk nama pengguna yang sama dengan nol dan beberapa nilai lainnya maka mereka akan muncul.

Di bawah ini adalah contoh sampel dan output. Bagaimana itu bisa dilakukan menggunakan kueri sql?

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

keluaran

+----------+------+
| username | col2 |
+----------+------+
| c        | der  |
| c        | null |
+----------+------+
Peneliti IT
sumber
1
Bagaimana jika ada 2 baris dengan d, derdan 2 dengan d, null?
ypercubeᵀᴹ
1
@ ypercube Maka semua 4 baris d akan muncul
IT peneliti
1
Jika ada baris dengan e, one, e, twodan 2 atau lebih dengan e, null?
ypercubeᵀᴹ
1
@ ypercube maka semua baris akan muncul.
Peneliti IT

Jawaban:

12

Anda harus dapat menggunakan agregasi bersyarat untuk mendapatkan nama pengguna dengan nilai col2sekaligus null.

Saya sarankan menggunakan klausa HAVING dengan kondisi. Kueri akan serupa dengan:

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

Lihat SQL Fiddle dengan Demo . Kueri ini mengelompokkan data Anda dengan setiap nama pengguna dan kemudian menggunakan logika kondisional untuk memeriksa apakah col2memenuhi kedua kondisi yang Anda inginkan - di mana col2tidak nol dan col2 nol.

Anda kemudian dapat menggunakan ini dalam subquery, dll untuk mendapatkan usernamedan col2nilai:

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

Lihat SQL Fiddle dengan Demo .

Jika Anda memiliki lebih dari satu col2baris dengan nilai keduanya nulldan lainnya, maka Anda hanya perlu mengubah HAVINGsedikit klausa:

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;

Lihat SQL Fiddle dengan Demo

Taryn
sumber
Permintaan Anda melewatkan satu poin (sebenarnya saya juga tidak disebutkan dengan jelas dalam pertanyaan). Jika ada lebih dari dua baris untuk nama pengguna yang sama dengan nol dan beberapa nilai lainnya maka mereka akan muncul. dalam kueri Anda, mereka tidak akan datang (misalnya dalam biola jika ada baris lain dengan nama pengguna 'c' dan nilai nol atau lebih.
Peneliti TI
1
@ITresearcher Itu adalah perbaikan sederhana - Anda perlu mengubah HAVINGklausa menjadi >=1- sqlfiddle.com/#!3
Taryn
Oke. Itu benar. Jawaban oleh JGA juga berfungsi.
Peneliti IT
8

Solusi lain:

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

Rencana eksekusi

Dalam nada logis yang serupa:

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

Rencana eksekusi

Lagi:

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;

Rencana eksekusi

Paul White 9
sumber
Jawaban bagus. Bahkan memiliki kinerja yang lebih baik karena meja saya sangat besar.
Peneliti TI
5

Hanya cara lain untuk melakukannya:

; 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 ;
ypercubeᵀᴹ
sumber
4

Ini juga berfungsi. Demo SQL Fiddle

Saya mendapatkan C1 sebagai baris total untuk setiap nama pengguna, C2 sebagai baris null total untuk setiap nama pengguna dan saya membandingkan nilai-nilai ini nanti.

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
JGA
sumber
3

Saya akan menggunakan sub-kueri untuk memilih nama pengguna tersebut seperti:

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

Saya mencoba dengan yang ini ...

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;
ammu
sumber
2
Ini akan menginduksi gabungan silang. Jika untuk nama pengguna, ada 3 baris dengan nol col2 dan 2 baris dengan non-nol col2, hasil akhirnya akan memiliki 6 baris, bukan 5. Dan col2tidak akan di output.
ypercubeᵀᴹ