用于过滤重复项的多行功能
Multi-Row function to filter out Duplicates
我对使用 SQL 比较陌生,所以我想请您帮忙处理一个案例。
我有以下 Table(只是一个示例):
| id | FName_LVL1 | LName_LVL1 | FName_LVL2 | LName_LVL2 |
|----|-------------|------------|------------|-------------|
| 1 | John | Kennedy | Marc | Guy |
| 2 | John | Kennedy | Olivier | Oslo |
| 3 | Mike | Lanes | Patrick | James |
我想隔离 FName_LVL1 和 LName_LVL1
中的重复项
所以 Table 看起来像这样 :
| id | FName_LVL1 | LName_LVL1 | FName_LVL2 | LName_LVL2 |
|----|-------------|------------|------------|-------------|
| 1 | John | Kennedy | Marc | Guy |
| 2 | John | Kennedy | Olivier | Oslo |
我的想法是创建一个标志列,条件是如果 FName_LVL1 列和 LName_LVL1 列中的上方或下方行相同,则输入“1”,否则输入“0”。 =13=]
栏目如下所示:
| id | FName_LVL1 | LName_LVL1 | FName_LVL2 | LName_LVL2 | Flag
|----|-------------|------------|------------|-------------|
| 1 | John | Kennedy | Marc | Guy | 1
| 2 | John | Kennedy | Olivier | Oslo | 1
| 3 | Mike | Lanes | Patrick | James | 0
有了这样的 table 之后,我可以过滤并得到我想要的结果。
这是我在 Alteryx 中习惯的工作方式,但我不确定是否可以使用 SQL 语句,或者即使这是解决这种情况的最佳方式
no_of_records
列告诉您该组合在 table 中出现了多少次。 IE。在你的例子中它将是 2 table
select table1.*
from table as table1
inner join
(
Select FName_LVL1, LName_LVL1, count(*) as no_of_records
from Table
group by FName_LVL1, LName_LVL1
) table2
on table1.FName_LVL1 = table2.FName_LVL1
and table1.LName_LVL1 = table2.LName_LVL1
and no_of_records>1
您可以将 count()
与 window 函数一起使用。
查询 1:
SELECT t.*
,CASE
WHEN COUNT(*) OVER (
PARTITION BY fname_lvl1
,lname_lvl1
) > 1
THEN 1
ELSE 0
END AS Flag
FROM t
| ID | FNAME_LVL1 | LNAME_LVL1 | FNAME_LVL2 | LNAME_LVL2 | FLAG |
|----|------------|------------|------------|------------|------|
| 1 | John | Kennedy | Marc | Guy | 1 |
| 2 | John | Kennedy | Olivier | Oslo | 1 |
| 3 | Mike | Lanes | Patrick | James | 0 |
您可以使用 "semi join" 子查询来获得这样的结果:
SELECT * FROM Table1 t1
WHERE EXISTS (
SELECT 'Anything' FROM Table1 t2
WHERE t1.FName_LVL1 = t2.FName_LVL1
AND t1.LName_LVL1 = t2.LName_LVL1
AND t1.id <> t2.id
)
演示:http://sqlfiddle.com/#!4/f9c44/3
| ID | FNAME_LVL1 | LNAME_LVL1 | FNAME_LVL2 | LNAME_LVL2 |
|----|------------|------------|------------|------------|
| 2 | John | Kennedy | Olivier | Oslo |
| 1 | John | Kennedy | Marc | Guy |
您可能更喜欢使用 LAG
和 LEAD
分析函数以及 NVL2
的贡献:
select n.*,
nvl2(lag(FName_LVL1||' '||LName_LVL1,1,null) over
(partition by FName_LVL1||' '||LName_LVL1 order by FName_LVL1, LName_LVL1),1,0)+
nvl2(lead(FName_LVL1||' '||LName_LVL1,1,null) over
(partition by FName_LVL1||' '||LName_LVL1 order by FName_LVL1, LName_LVL1),1,0) flag
from names n;
ID FNAME_LVL1 LNAME_LVL1 FNAME_LVL2 LNAME_LVL2 FLAG
-- ---------- ---------- ---------- ---------- -----
1 John Kennedy Marc Guy 1
2 John Kennedy Olivier Oslo 1
3 Mike Lanes Patrick James 0
最有效的方法是使用 partition by 子句只进行一次 table 扫描。
我已将输出保存在 Livesql
drop table t1 purge;
create table t1 ( c1 varchar2(20), c2 varchar2(20), c3 varchar2(20), c4 varchar2(20));
insert into t1 values ('John','Kennedy','Marc','Guy');
insert into t1 values ('John','Kennedy','Olivier','Oslo');
insert into t1 values ('not','john','vijay','balebail');
commit;
select t1.*, count(c1||c2) over (partition by c1,c2 order by c1,c2 ) flag from t1;
select t1.*, decode (count(c1||c2) over (partition by c1,c2 order by c1,c2 ),1,0,1) flag from t1;
C1 C2 C3 C4 标志
约翰肯尼迪马克盖伊 2
约翰肯尼迪奥利维尔奥斯陆 2
不是 john vijay balebail 1
下载 CSV
3 行 selected。
报表 7
select t1.*, 解码 (count(c1||c2) over (partition by c1,c2 order by c1,c2 ),1,0,1) 来自 t1
的标志
C1 C2 C3 C4 FLAG
John Kennedy Marc Guy 1
John Kennedy Olivier Oslo 1
not john vijay balebail 0
谢谢大家!看来那个案子确实有很多解决办法!
我会继续深入研究,看看我最喜欢哪一个,但多亏了你,它让我对 SQL 逻辑有了很好的了解
抱歉,我的回复延迟了,因为工作不在
我对使用 SQL 比较陌生,所以我想请您帮忙处理一个案例。
我有以下 Table(只是一个示例):
| id | FName_LVL1 | LName_LVL1 | FName_LVL2 | LName_LVL2 |
|----|-------------|------------|------------|-------------|
| 1 | John | Kennedy | Marc | Guy |
| 2 | John | Kennedy | Olivier | Oslo |
| 3 | Mike | Lanes | Patrick | James |
我想隔离 FName_LVL1 和 LName_LVL1
中的重复项所以 Table 看起来像这样 :
| id | FName_LVL1 | LName_LVL1 | FName_LVL2 | LName_LVL2 |
|----|-------------|------------|------------|-------------|
| 1 | John | Kennedy | Marc | Guy |
| 2 | John | Kennedy | Olivier | Oslo |
我的想法是创建一个标志列,条件是如果 FName_LVL1 列和 LName_LVL1 列中的上方或下方行相同,则输入“1”,否则输入“0”。 =13=]
栏目如下所示:
| id | FName_LVL1 | LName_LVL1 | FName_LVL2 | LName_LVL2 | Flag
|----|-------------|------------|------------|-------------|
| 1 | John | Kennedy | Marc | Guy | 1
| 2 | John | Kennedy | Olivier | Oslo | 1
| 3 | Mike | Lanes | Patrick | James | 0
有了这样的 table 之后,我可以过滤并得到我想要的结果。
这是我在 Alteryx 中习惯的工作方式,但我不确定是否可以使用 SQL 语句,或者即使这是解决这种情况的最佳方式
no_of_records
列告诉您该组合在 table 中出现了多少次。 IE。在你的例子中它将是 2 table
select table1.*
from table as table1
inner join
(
Select FName_LVL1, LName_LVL1, count(*) as no_of_records
from Table
group by FName_LVL1, LName_LVL1
) table2
on table1.FName_LVL1 = table2.FName_LVL1
and table1.LName_LVL1 = table2.LName_LVL1
and no_of_records>1
您可以将 count()
与 window 函数一起使用。
查询 1:
SELECT t.*
,CASE
WHEN COUNT(*) OVER (
PARTITION BY fname_lvl1
,lname_lvl1
) > 1
THEN 1
ELSE 0
END AS Flag
FROM t
| ID | FNAME_LVL1 | LNAME_LVL1 | FNAME_LVL2 | LNAME_LVL2 | FLAG |
|----|------------|------------|------------|------------|------|
| 1 | John | Kennedy | Marc | Guy | 1 |
| 2 | John | Kennedy | Olivier | Oslo | 1 |
| 3 | Mike | Lanes | Patrick | James | 0 |
您可以使用 "semi join" 子查询来获得这样的结果:
SELECT * FROM Table1 t1
WHERE EXISTS (
SELECT 'Anything' FROM Table1 t2
WHERE t1.FName_LVL1 = t2.FName_LVL1
AND t1.LName_LVL1 = t2.LName_LVL1
AND t1.id <> t2.id
)
演示:http://sqlfiddle.com/#!4/f9c44/3
| ID | FNAME_LVL1 | LNAME_LVL1 | FNAME_LVL2 | LNAME_LVL2 |
|----|------------|------------|------------|------------|
| 2 | John | Kennedy | Olivier | Oslo |
| 1 | John | Kennedy | Marc | Guy |
您可能更喜欢使用 LAG
和 LEAD
分析函数以及 NVL2
的贡献:
select n.*,
nvl2(lag(FName_LVL1||' '||LName_LVL1,1,null) over
(partition by FName_LVL1||' '||LName_LVL1 order by FName_LVL1, LName_LVL1),1,0)+
nvl2(lead(FName_LVL1||' '||LName_LVL1,1,null) over
(partition by FName_LVL1||' '||LName_LVL1 order by FName_LVL1, LName_LVL1),1,0) flag
from names n;
ID FNAME_LVL1 LNAME_LVL1 FNAME_LVL2 LNAME_LVL2 FLAG
-- ---------- ---------- ---------- ---------- -----
1 John Kennedy Marc Guy 1
2 John Kennedy Olivier Oslo 1
3 Mike Lanes Patrick James 0
最有效的方法是使用 partition by 子句只进行一次 table 扫描。 我已将输出保存在 Livesql
drop table t1 purge;
create table t1 ( c1 varchar2(20), c2 varchar2(20), c3 varchar2(20), c4 varchar2(20));
insert into t1 values ('John','Kennedy','Marc','Guy');
insert into t1 values ('John','Kennedy','Olivier','Oslo');
insert into t1 values ('not','john','vijay','balebail');
commit;
select t1.*, count(c1||c2) over (partition by c1,c2 order by c1,c2 ) flag from t1;
select t1.*, decode (count(c1||c2) over (partition by c1,c2 order by c1,c2 ),1,0,1) flag from t1;
C1 C2 C3 C4 标志 约翰肯尼迪马克盖伊 2 约翰肯尼迪奥利维尔奥斯陆 2 不是 john vijay balebail 1 下载 CSV 3 行 selected。 报表 7 select t1.*, 解码 (count(c1||c2) over (partition by c1,c2 order by c1,c2 ),1,0,1) 来自 t1
的标志C1 C2 C3 C4 FLAG John Kennedy Marc Guy 1 John Kennedy Olivier Oslo 1 not john vijay balebail 0
谢谢大家!看来那个案子确实有很多解决办法!
我会继续深入研究,看看我最喜欢哪一个,但多亏了你,它让我对 SQL 逻辑有了很好的了解
抱歉,我的回复延迟了,因为工作不在