甲骨文 SQL 开发 | Select 只有一个重复行具有最高值

ORACLE SQL DEV | Select only one duplicate row having the highest value

关于我找不到答案的问题的快速提问。

我的SQL请求的objective是通过安置从墓地安置中找到最后一个持有人。

例如:

ID_CARTO_EMPL ID_EXT LAST_HOLDER
N¿A1¿10¿¿¿¿1¿ 55706 VIK TOR
N¿A1¿10¿¿¿¿11¿ 52536 MARC MINI
N¿A1¿10¿¿¿¿11¿ 52458 DAVID MARCEL
(41 000 rows left) (41 000 rows left) (41 000 rows left)

如您所见,“ID_CARTO_EMPL”列有重复的行。 (N¿A1¦10¿¿¿11¿) 所以在这种情况下,我想 select 在“ID_EXT”列中具有最高值的那个 (52536)

从这里开始:

ID_CARTO_EMPL ID_EXT LAST_HOLDER
N¿A1¿10¿¿¿¿1¿ 55706 VIK TOR
N¿A1¿10¿¿¿¿11¿ 52536 MARC MINI
N¿A1¿10¿¿¿¿11¿ 52458 DAVID MARCEL
(41 000 rows left) (41 000 rows left) (41 000 rows left)

为此:

ID_CARTO_EMPL ID_EXT LAST_HOLDER
N¿A1¿10¿¿¿¿1¿ 55706 VIK TOR
N¿A1¿10¿¿¿¿11¿ 52536 MARC MINI
(41 000 rows left) (41 000 rows left) (41 000 rows left)

我想对超过 41 000 行查找重复项执行此操作,如果我们得到一个 select 只有在“ID_EXT”列中具有较高值的​​行。

暂时有我的代码:


--Objective, to obtain the last holder of the concession in order to
-- to conduct research
--------------------------------------------------------------------------------
--Start of the script

SELECT

-- Concatenation in order to get the cleanest ID_CARTO_EMPL possible
(et_empl.cd_cim_empl ||'¤'|| et_empl.cle1_empl ||'¤'|| et_empl.cle2_empl||'¤'||
et_empl.cle3_empl||'¤'||et_empl.cle4_empl||'¤'||et_empl.cle5_empl||'¤'||
et_empl.tombe_empl||'¤'||et_empl.compl_empl) AS ID_CARTO_EMPL,

-------------------------------------------------------------
et_co.cd_c,

et_conc_pers.cd_e,

et_conc_pers.cd_status

et_conc_pers.id_ext,
--------------------------------------------------------------------------------
-- Get the dealer of the concession (concatenation N/P/NJF)
(et_perssup.name_e || ' ' || et_perssup.pren_e || ' ' || et_perssup.name_jf_e)
AS LAST_HOLDER
--------------------------------------------------------------------------------
-- From the location table (base table)
FROM and_empl
--------------------------------------------------------------------------------
-- Join
INNER JOIN et_co ON et_empl.cd_c = et_co.cd_c
INNER JOIN et_conc_pers ON et_empl.cd_c = et_conc_pers.cd_c
INNER JOIN et_perssup ON et_conc_pers.cd_e = et_perssup.cd_e
--------------------------------------------------------------------------------
WHERE
et_conc_pers.cd_status_pers_conc = 2
AND et_empl.histo_empl = 0
AND et_empl.cd_cim_empl = 'N'

ORDER BY ID_CARTO_EMPL ASC


关于请求的多个条件,我想出了 sql 查询,但我一开始想做的那个似乎比那个更复杂。 总的来说,我不得不将我的请求分成 3 个:

-1:位置所有者 -2:最后持有人 -3:最后一位死者

所以在一行中我想要:“ID_CARTO_EMPL” | “位置所有者” | “最后的持有者” | “最后一个死者”

目标示例:

ID_CARTO_EMPL ID_EXT LOCATION_OWNER LAST_HOLDER LAST_DECEASED
N¿A1¿10¿¿¿¿1¿ 55706 VIK TOR HUGO TOR
N¿A1¿10¿¿¿¿11¿ 52536 MARC MINI DAVID MINI BERNADETTE MINI
(41 000 rows left) (41 000 rows left) (41 000 rows left) (41 000 rows left) (41 000 rows left)

所以对于每一行我都需要找到这个:

LOCATION_OWNER : "STATUT" = 1
LAST_HOLDER : "STATUT" = 2 AND HIGHEST "ID_EXT"
LAST_DECEASED : "STATUT" = 13 AND HIGHEST "ID_EXT"

我成功地完成了三个查询,但不止一个:

LOCATION_OWNER :

--Objective, to obtain most of the information present in the table
-- ET_CARTO_EMPL with only the dealer as person.
-------------------------------------------------- ------------------------------
--Start of script

SELECT DISTINCT

-- Obtain CLE_EMPL
et_empl.key_empl,

-- Concatenation in order to obtain the cleanest possible ID_CARTO_EMPL
-- Join field
(et_empl.cd_cim_empl ||'¤'|| et_empl.cle1_empl ||'¤'|| et_empl.cle2_empl||'¤'||
et_empl.cle3_empl||'¤'||et_empl.cle4_empl||'¤'||et_empl.cle5_empl||'¤'||
et_empl.tombe_empl||'¤'||et_empl.compl_empl) AS ID_CARTO_EMPL,

-- Obtain the Title number of the concession
et_co.numtit_c AS NUM_TITRE,

-- Obtain the Concession number of the concession
et_co.num_conc_c AS NUM_CONCESSION,

-- Obtain the expiration date of the concession
et_co.dt_exp_c AS DATE_DEADLINE,

-- Get dealership location type
et_empl.type_c,

-- Get dealership from dealership (concatenation N/P/NJF)
(et_perssup.nom_e || ' ' || et_perssup.pren_e || ' ' || et_perssup.nom_jf_e)
AS DEALER
-------------------------------------------------- ------------------------------
-- From the locations table (base table)
FROM and_empl
-------------------------------------------------- ------------------------------
-- Join
INNER JOIN et_co ON et_empl.cd_c = et_co.cd_c
INNER JOIN et_conc_pers ON et_empl.cd_c = et_conc_pers.cd_c
INNER JOIN et_perssup ON et_conc_pers.cd_e = et_perssup.cd_e
-------------------------------------------------- ------------------------------
--Terms
WHERE
et_conc_pers.cd_statut_pers_conc = 1 AND et_empl.histo_empl = 0

LAST_HOLDER :

-- Objective, obtain the last holder of the concession
-------------------------------------------------- ------------------------------
-- Start of script
WITH
   your_query
   AS
      (SELECT -- Concatenation to obtain the cleanest possible ID_CARTO_EMPL
              ( et_empl.cd_cim_empl
               || '¤'
               || et_empl.key1_empl
               || '¤'
               || et_empl.key2_empl
               || '¤'
               || et_empl.key3_empl
               || '¤'
               || et_empl.key4_empl
               || '¤'
               || et_empl.key5_empl
               || '¤'
               || et_empl.grave_empl
               || '¤'
               || et_empl.compl_empl) AS ID_CARTO_EMPL,
              -------------------------------------------------- -----------
              et_conc_pers.id_ext, -- Mandatory otherwise the query crashes
              -------------------------------------------------- ------------------------------
              -- Obtain the last concession holder (N/P/NJF concatenation)
              ( et_perssup.nom_e
               || ' '
               || et_perssup.pren_e
               || ' '
               || et_perssup.nom_jf_e) AS LAST_HOLDER
         -------------------------------------------------- ------------------------------
         -- From the location table (base table)
         FROM and_empl
              -------------------------------------------------- ------------------------------
              -- Join
              INNER JOIN et_co ON et_empl.cd_c = et_co.cd_c
              INNER JOIN et_conc_pers ON et_empl.cd_c = et_conc_pers.cd_c
              INNER JOIN et_perssup ON et_conc_pers.cd_e = et_perssup.cd_e
        -------------------------------------------------- ------------------------------
        -- Terms
        WHERE et_conc_pers.cd_statut_pers_conc = 2
              AND et_empl.histo_empl = 0),
   time
   AS
      (SELECT ID_CARTO_EMPL,
              id_ext,
              LAST_HOLDER,
              ROW_NUMBER()
                 OVER (PARTITION BY ID_CARTO_EMPL ORDER BY id_ext DESC) rn
         FROM your_query)
  SELECT ID_CARTO_EMPL, id_ext, LAST_HOLDER
    FROM temp
   WHERE rn = 1
ORDER BY ID_CARTO_EMPL ASC

LAST_DECEASED:

-- Objective, obtain the last buried of the concession
-------------------------------------------------- ------------------------------
-- Start of script
 
WITH
   your_query
   AS
      (SELECT -- Concatenation to obtain the cleanest possible ID_CARTO_EMPL
              ( et_empl.cd_cim_empl
               || '¤'
               || et_empl.key1_empl
               || '¤'
               || et_empl.key2_empl
               || '¤'
               || et_empl.key3_empl
               || '¤'
               || et_empl.key4_empl
               || '¤'
               || et_empl.key5_empl
               || '¤'
               || et_empl.grave_empl
               || '¤'
               || et_empl.compl_empl) AS ID_CARTO_EMPL,
              -------------------------------------------------- -----------
              et_conc_pers.id_ext, -- Mandatory otherwise the query crashes
              -------------------------------------------------- ------------------------------
              -- Obtain the last buried of the concession (concatenation N/P/NJF)
              ( et_perssup.nom_e
               || ' '
               || et_perssup.pren_e
               || ' '
               || et_perssup.nom_jf_e) AS LAST_BURIED
         -------------------------------------------------- ------------------------------
         -- From the location table (base table)
         FROM and_empl
         -------------------------------------------------- -----------------------------------
              -- Joints
              INNER JOIN et_co ON et_empl.cd_c = et_co.cd_c
              INNER JOIN et_conc_pers ON et_empl.cd_c = et_conc_pers.cd_c
              INNER JOIN et_perssup ON et_conc_pers.cd_e = et_perssup.cd_e
        -------------------------------------------------- ------------------------------
        -- Terms
        WHERE et_conc_pers.cd_statut_pers_conc = 13
              AND et_empl.histo_empl = 0),
   time
   AS
      (SELECT ID_CARTO_EMPL,
              id_ext,
              LAST_BURIED,
              ROW_NUMBER()
                 OVER (PARTITION BY ID_CARTO_EMPL ORDER BY id_ext DESC) rn
         FROM your_query)
  SELECT ID_CARTO_EMPL, id_ext, LAST_INHUME
    FROM temp
   WHERE rn = 1
ORDER BY ID_CARTO_EMPL ASC




如果可以将这 3 个请求结合起来,那可能非常好,但不是主要的。与此同时,我继续我的研究。

一般来说,一种选择是按 something 对行进行分区(在你的情况下似乎是 id_carto_empl)并将它们排序为 some order(在你的例子中,id_ext 降序排列)。

然后,作为最终结果,return 行排名为“最高”(即有 rn = 1)。

像这样:

with temp as
  (select id_carto_empl, id_ext, last_holder,
     row_number() over (partition by id_carto_empl order by id_ext desc) rn
   from your_table
  )
select id_carto_empl, id_ext, last_holder
from temp
where rn = 1

应用于您的查询:

WITH
   your_query
   AS
      (SELECT -- Concatenation in order to get the cleanest ID_CARTO_EMPL possible
              (   et_empl.cd_cim_empl
               || '¤'
               || et_empl.cle1_empl
               || '¤'
               || et_empl.cle2_empl
               || '¤'
               || et_empl.cle3_empl
               || '¤'
               || et_empl.cle4_empl
               || '¤'
               || et_empl.cle5_empl
               || '¤'
               || et_empl.tombe_empl
               || '¤'
               || et_empl.compl_empl) AS id_carto_empl,
              -------------------------------------------------------------
              et_co.cd_c,
              et_conc_pers.cd_e,
              et_conc_pers.cd_status,
              et_conc_pers.id_ext,
              --------------------------------------------------------------------------------
              -- Get the dealer of the concession (concatenation N/P/NJF)
              (   et_perssup.name_e
               || ' '
               || et_perssup.pren_e
               || ' '
               || et_perssup.name_jf_e) AS last_holder
         --------------------------------------------------------------------------------
         -- From the location table (base table)
         FROM and_empl
              --------------------------------------------------------------------------------
              -- Join
              INNER JOIN et_co ON et_empl.cd_c = et_co.cd_c
              INNER JOIN et_conc_pers ON et_empl.cd_c = et_conc_pers.cd_c
              INNER JOIN et_perssup ON et_conc_pers.cd_e = et_perssup.cd_e
        --------------------------------------------------------------------------------
        WHERE     et_conc_pers.cd_status_pers_conc = 2
              AND et_empl.histo_empl = 0
              AND et_empl.cd_cim_empl = 'N'),
   temp
   AS
      (SELECT id_carto_empl,
              id_ext,
              last_holder,
              ROW_NUMBER ()
                 OVER (PARTITION BY id_carto_empl ORDER BY id_ext DESC) rn
         FROM your_table)
  SELECT id_carto_empl, id_ext, last_holder
    FROM temp
   WHERE rn = 1
ORDER BY id_carto_empl ASC

关于您对同一查询中的“多个”条件的评论:您可以这样做,使用您感兴趣的 return 结果的任意数量的分析函数。

这是一个基于 Scott 的示例架构及其 EMP table 的示例。假设您要获取每个部门收入最高的员工和按字母顺序排在第一位的员工。

SQL> break on deptno
SQL> select deptno, empno, ename, job, sal
  2  from emp
  3  order by deptno, sal desc, ename;

    DEPTNO      EMPNO ENAME      JOB              SAL
---------- ---------- ---------- --------- ----------
        10       7839 KING       PRESIDENT       5000  --> earns the most in dept. 10
                 7782 CLARK      MANAGER         2450  --> alphabetically first in dept. 10
                 7934 MILLER     CLERK           1300
        20       7902 FORD       ANALYST         3000  --> Ford and Scott earn
                 7788 SCOTT      ANALYST         3000  --> the most in dept. 20
                 7566 JONES      MANAGER         2975
                 7876 ADAMS      CLERK           1100  --> alphabetically first in dept. 20
                 7369 SMITH      CLERK            800
        30       7698 BLAKE      MANAGER         2850
                 7499 ALLEN      SALESMAN        1600
                 7844 TURNER     SALESMAN        1500
                 7654 MARTIN     SALESMAN        1250
                 7521 WARD       SALESMAN        1250
                 7900 JAMES      CLERK            950

14 rows selected.

您随后使用的查询可能是这样的:

SQL> with temp as
  2    (select deptno, empno, ename, job, sal,
  3            rank() over (partition by deptno order by sal desc) rnk_sal_desc,
  4            row_number() over (partition by deptno order by ename asc) rn_ename_asc
  5     from emp
  6    )
  7  select deptno, empno, ename, job, sal
  8  from temp
  9  where 1 in (rnk_sal_desc, rn_ename_asc)
 10  order by deptno, sal desc, empno asc;

    DEPTNO      EMPNO ENAME      JOB              SAL
---------- ---------- ---------- --------- ----------
        10       7839 KING       PRESIDENT       5000
                 7782 CLARK      MANAGER         2450
        20       7788 SCOTT      ANALYST         3000
                 7902 FORD       ANALYST         3000
                 7876 ADAMS      CLERK           1100
        30       7698 BLAKE      MANAGER         2850
                 7499 ALLEN      SALESMAN        1600

7 rows selected.

SQL>

你要的是MAX函数

将其分解为基本框架,并避免所有的串联和组合,您会看到类似

的东西
SELECT id_carto_empl, MAX(id_ext) FROM my_theoretical_emplacement_table;

如果您在其中重建一些联接和串联(用您的表达式替换 id_carto_empl 并为“my_theoretical_emplacement_table”构建必要的联接),这将为您提供一个安置列表具有最高相关 ID 的 ID。

然后您可以使用另一个 select 或连接来获取与 id_ext 关联的名称并构建 id_carto_empl、id_ext、[=24 的单个输出=]