我有以下情况:
表员工:
First Name | Last Name | Department | Salary
-----------|-----------|------------|---------
John | Doe | Finance | 20
John | Doe | R&D | 20
John | null | Finance | 20
John | long | Finance | 20
我想要每个 1 行(名字,姓氏),除非我们的姓氏中有一个 null,然后我只需要 1 行 (名字,空)
对于上面的示例,结果为:
First Name | Last Name | Department | Salary
-----------|-----------|------------|---------
John | null | Finance | 20
但是如果我没有那个记录,那么结果应该是:
First Name | Last Name | Department | Salary
-----------|-----------|------------|---------
John | Doe | R&D | 20
John | long | Finance | 20
我想答案涉及一些分区,但我不确定在哪里。
现在我来到这个:
SELECT FirstName,LastName, DEPARTMENT,Salary,RK FROM
(
select * from
SELECT EXT.*,
ROW_NUMBER() OVER(PARTITION BY EXT.FirstName,EXT.LastName
ORDER BY rownum ASC) AS RK
FROM Employees EXT
)
WHERE RK = 1 ;
谢谢!
你的问题出在分区子句中。您希望每个名字都有姓氏,除非至少有一个具有该名字的姓氏为 NULL,在这种情况下,您只需要那些姓氏为 NULL 的名字。
这里的答案是使用 RANK() 而不是 ROW_NUMBER()。RANK() 不会创建连续列表;相反,具有相等值的行将获得相同的排名。
select firstname, lastname, department, salary, rk
from ( select a.*
, rank() over ( partition by firstname
order by case when lastname is null then 0
else 1
end
) as rnk
from employees a
)
where rnk = 1
这是通过使姓氏的存在相关而不是姓氏本身来起作用的。
还有两点:
- 您有一个不带括号的嵌套选择。这是行不通的。
- ROWNUM订购没有意义。根据定义,rownum 按语句返回的顺序返回行,这意味着行将始终按 ROWNUM 的顺序返回。
像
这样:
SQL> create table person
2 (
3 fname varchar2(10),
4 lname varchar2(10),
5 dept varchar2(10),
6 sal number
7 );
Table created.
SQL> insert into person values ('John', 'Doe', 'Finance', 20);
1 row created.
SQL> insert into person values ('John', 'Doe', 'R&D', 20);
1 row created.
SQL> insert into person values ('John', '', 'Finance', 20);
1 row created.
SQL> insert into person values ('John', 'Long', 'Finance', 20);
1 row created.
SQL> insert into person values ('Paul', 'Doe', 'R&D', 30);
1 row created.
SQL> insert into person values ('Paul', 'Doe', 'Finance', 30);
1 row created.
SQL> insert into person values ('Paul', 'Long', 'Finance', 30);
1 row created.
SQL> select fname, lname, dept, sal
2 from (select fname, lname, dept, sal,has_null,
3 row_number() over(partition by fname,
4 case when has_null = 'N' then lname else null end
5 order by lname desc nulls first) rn
6 from (select fname, lname,
7 nvl(max(case when lname is null then 'Y'
8 end) over(partition by fname), 'N') has_null, dept, sal
9 from person))
10 where rn = 1;
FNAME LNAME DEPT SAL
---------- ---------- ---------- ----------
John Finance 20
Paul Doe R&D 30
Paul Long Finance 30
该查询执行(相同的)技巧,但效果更好。
SELECT fname,
lname,
dept,
sal
FROM (SELECT fname,
lname,
dept,
sal,
First_value(lname)
OVER(
partition BY fname
ORDER BY lname nulls first) null_domain,
Row_number()
OVER (
partition BY fname, lname
ORDER BY fname) r
FROM person)
WHERE ( ( null_domain IS NULL
AND lname IS NULL )
OR null_domain IS NOT NULL )
AND r = 1;