【问题标题】:How to remove redundant data from SQL query如何从 SQL 查询中删除冗余数据
【发布时间】:2017-06-13 14:05:33
【问题描述】:

嗨:我正在从一个表中提取数据,该表的主 ID 代码与用户相关联,但每次用户更改他/她的姓名时,都会添加一条额外的记录。我正在尝试提取当前用户的列表以及他们过去可能使用过的任何旧名称。我正在使用外部连接来获取至少一个以前的名字和一个额外的以前的名字。

这是查询:

select
PrimaryName.PM_PDM,
PrimaryName.PM_ID,
PrimaryName.PM_AltID,
PrimaryName.PM_Change,
PrimaryName.PM_FName,
PrimaryName.PM_LName,
OldNames1.ON_PDM,
OldNames1.ON_Change,
OldNames1.ON_ID,
OldNames1.ON_AltID,
OldNames1.ON_FName,
OldNames1.ON_LName,
OldNames2.O2_PDM,
OldNames2.O2_Change,
OldNames2.O2_ID,
OldNames2.O2_AltID,
OldNames2.O2_FName,
OldNames2.O2_LName

from
(select
S_PDM as PM_PDM,
S_ID as PM_ID,
S_FIRST_NAME as PM_FName,
S_LAST_NAME as PM_LName,
S_CHANGE_IND as PM_Change,
S_SURROGATE_ID as PM_AltID
from S
WHERE S_CHANGE_IND is null) PrimaryName,

(select
S_PDM as ON_PDM,
S_ID  as ON_ID,
S_FIRST_NAME as ON_FName,
S_LAST_NAME as ON_LName,
S_CHANGE_IND as ON_Change,
S_SURROGATE_ID as ON_AltID
from S
where S_CHANGE_IND = 'N') OldNames1,

(select
S_PDM as O2_PDM,
S_ID  as O2_ID,
S_FIRST_NAME as O2_FName,
S_LAST_NAME as O2_LName,
S_CHANGE_IND as O2_Change,
S_SURROGATE_ID as O2_AltID
from S
where S_CHANGE_IND = 'N') OldNames2


where (OldNames1.ON_PDM = PrimaryName.pm_pdm)
and
  (OldNames1.ON_PDM = OldNames2.O2_PDM (+)
   and
   OldNames1.ON_AltID <> OldNames2.O2_AltID (+))

order by 2

这是我的结果示例:

PM_PDM  |PM_ID  |PM_ID2 |PM_CHANGE  |PM_FNAME   |PM_LNAME   |ON_PDM |ON_CHANGE  |ON_ID  |ON_ID2 |ON_FNAME   |ON_LNAME   |O2_PDM     |O2_CHANGE  |O2_ID2 |O2_ID  |O2_FNAME   |O2_LNAME
1111    |2222   |3333   |           |Betty      |Boop       |1111   |N          |2222   |4444   |Betty      |Smith      |1111       |N          |5555   |2222   |Betty      |Jones
1111    |2222   |3333   |           |Betty      |Boop       |1111   |N          |2222   |5555   |Betty      |Jones      |1111       |N          |4444   |2222   |Betty      |Smith

我只为三个名字返回了一行:

  1. Betty Boop 2.Betty Smith 3. Betty Jones

现在,它正在回归

  1. Betty Boop 2.Betty Smith 3.Betty Jones
  2. Betty Boop 2.Betty Jones 3.Betty Smith

我知道这是最后一次加入,但我不确定如何将其限制为仅一行。查询按预期方式工作,但我需要对其进行编辑以仅返回一行。

【问题讨论】:

  • 修复您的联接以使用现代 JOIN 语法,而不是古老的过时 A、B 联接语法。这应该使错误更清晰,更容易发现。
  • 你能解释一下这个问题吗?我看到您已经解释了您所做的事情并显示了结果数据,但我看不出结果有任何问题。
  • 我试图将结果限制为每个用户一行:当前用户名、第一个以前的用户名、第二个以前的用户名。现在,连接正在获取用户名、第一个用户名和第二个用户名。它还返回用户名、第二个用户名和第一个用户名的第二行。这有意义吗?
  • @Lyndey 您期望结果是什么样的?请更新您的问题以包含您想看到的内容。
  • 欢迎在原始查询及其输出中保持同样的简洁性 :)

标签: sql oracle


【解决方案1】:

使用row_number() 为每个更改分配数字,并仅使用RN = 1RN = 2 所在的行将这些数据连接两次:

with c as (select s.*, row_number() over (partition by pdm order by id desc) rn
             from s where chg = 'N')
select s.pdm, s.id, s.name, c1.id id1, c1.name name1, c2.id id2, c2.name name2
  from (select * from s where chg is null) s
  left join c c1 on c1.pdm = s.pdm and c1.rn = 1
  left join c c2 on c2.pdm = s.pdm and c2.rn = 2

测试:

with s(pdm, id, chg, name) as (select 1, 1, 'N',  'Smith' from dual union all
                               select 1, 2, 'N',  'Jones' from dual union all
                               select 1, 3, null, 'Brown' from dual),
     c as (select s.*, row_number() over (partition by pdm order by id desc) rn
             from s where chg = 'N')
select s.pdm, s.id, s.name, c1.id id1, c1.name name1, c2.id id2, c2.name name2
  from      (select * from s where chg is null) s
  left join c c1 on c1.pdm = s.pdm and c1.rn = 1
  left join c c2 on c2.pdm = s.pdm and c2.rn = 2


PDM  ID   NAME    ID1  NAME1   ID2  NAME2
---  ---  ------  ---  ------  ---  ------
  1    3  Brown     2  Jones     1  Smith

【讨论】:

  • 这个答案是一个好的开始。我仍然需要努力将东西放在一排,但它正在到达那里。
【解决方案2】:

将最后一个连接条件更改为:

 OldNames1.ON_AltID < OldNames2.O2_AltID (+)

解释:您有两个AltID444455554444 &lt;&gt; 5555 是真的,5555 &lt;&gt; 4444 也是如此。因此,您的现有状况....

 OldNames1.ON_AltID <> OldNames2.O2_AltID (+)

.... 产生一个交叉连接,所以你得到两条记录。因为5555 &lt; 4444 是假的,所以将条件更改为小于等于消除了交叉连接。

【讨论】:

  • 外连接,所以仍然会产生 2 行:1111-4444-5555 和 1111-5555-null。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-05
  • 2017-08-07
  • 1970-01-01
相关资源
最近更新 更多