【问题标题】:Oracle Sequential assignment of alphabets based on date columnOracle 基于日期列的字母顺序分配
【发布时间】:2022-01-19 11:04:03
【问题描述】:

表 1:

|Trans|Inc|Date|Status|
-----------------------
|1|1|01/01/2022|null
|5|1|20/01/2022|null
|3|1|03/01/2022|null
|11|2|01/01/2022|null
|3|2|13/12/2021|null

结果应该是

|Trans|Inc|Date|Status|
-----------------------
|1|1|01/01/2022|A
|5|1|20/01/2022|C
|3|1|03/01/2022|B
|11|2|01/01/2022|B
|3|2|13/12/2021|A

逻辑: 表 1 有 4 列,状态列应按以下条款更新: 1 Inc 可以附加多个反式。所以状态应该根据日期列更新。前任。对于 Inc 1,我们有 4 个 trans(所以会有状态 A、B、C、D)和 Tran 1 日期 01/01/2022 所以状态是“A”,第二条记录是 inc 1 tran 3,日期是 03 /01/2022,所以状态是 B。基本上我们需要根据日期列按字母顺序分配状态。

需要帮助。

【问题讨论】:

  • 如果 INC 值的值超过 26 个会怎样?
  • 那么我们应该明智地移动到'AA','AB','AC'。

标签: sql oracle join plsql


【解决方案1】:

你可以在这里使用ROW_NUMBER

SELECT Trans, Inc, Date,
       SUBSTR('ABCDEFGHIJKLMNOPQRSTUVWXYZ',
              ROW_NUMBER() OVER (PARTITION BY Inc ORDER BY Date), 1) AS Status
FROM yourTable;

这里的技巧是在每组公司记录中根据每条记录的行号位置取一个字母的 1 子字符串。

【讨论】:

  • 感谢蒂姆,但在更新现有表时遇到错误,因为我在其他评论中提到了错误。 ORA-01427 单个查询....同时更新现有表。
【解决方案2】:

你可以使用:

SELECT Trans,
       Inc,
       "DATE",
       CASE
       WHEN rn < 26      THEN    CHR(65 + rn)
       WHEN rn < 27 * 26 THEN    CHR(65 + MOD(FLOOR((rn-26)/POWER(26,1)),26))
                              || CHR(65 + MOD(FLOOR((rn-26)/POWER(26,0)),26))
                         ELSE    CHR(65 + MOD(FLOOR((rn-27*26)/POWER(26,2)),26))
                              || CHR(65 + MOD(FLOOR((rn-27*26)/POWER(26,1)),26))
                              || CHR(65 + MOD(FLOOR((rn-27*26)/POWER(26,0)),26))
       END AS status
FROM   (
  SELECT Trans,
         Inc,
         "DATE",
         ROW_NUMBER() OVER (PARTITION BY Inc ORDER BY "DATE") - 1 AS rn
  FROM   table_name t
);

其中,对于样本数据:

CREATE TABLE table_name (Trans, Inc, "DATE", Status) AS
SELECT  1, 1, DATE '2022-01-01', CAST(NULL AS VARCHAR2(3)) FROM DUAL UNION ALL
SELECT  5, 1, DATE '2022-01-20', CAST(NULL AS VARCHAR2(3)) FROM DUAL UNION ALL
SELECT  3, 1, DATE '2022-01-03', CAST(NULL AS VARCHAR2(3)) FROM DUAL UNION ALL
SELECT 11, 2, DATE '2022-01-01', CAST(NULL AS VARCHAR2(3)) FROM DUAL UNION ALL
SELECT  3, 2, DATE '2021-12-13', CAST(NULL AS VARCHAR2(3)) FROM DUAL;

这将为每个INC 值输出从AZ 然后AAZZ 然后AAAZZZ 的状态。

输出:

TRANS INC DATE STATUS
1 1 2022-01-01 00:00:00 A
3 1 2022-01-03 00:00:00 B
5 1 2022-01-20 00:00:00 C
3 2 2021-12-13 00:00:00 A
11 2 2022-01-01 00:00:00 B

如果您想更新状态值,那么您可以MERGE 使用ROWID 伪列进行关联:

MERGE INTO table_name dst
USING (
  SELECT ROWID AS rid,
         CASE
         WHEN rn < 26      THEN    CHR(65 + rn)
         WHEN rn < 27 * 26 THEN    CHR(65 + MOD(FLOOR((rn-26)/POWER(26,1)),26))
                                || CHR(65 + MOD(FLOOR((rn-26)/POWER(26,0)),26))
                           ELSE    CHR(65 + MOD(FLOOR((rn-27*26)/POWER(26,2)),26))
                                || CHR(65 + MOD(FLOOR((rn-27*26)/POWER(26,1)),26))
                                || CHR(65 + MOD(FLOOR((rn-27*26)/POWER(26,0)),26))
         END AS status
  FROM   (
    SELECT ROW_NUMBER() OVER (PARTITION BY Inc ORDER BY "DATE") - 1 AS rn
    FROM   table_name t
  )
) src
ON (src.rid = dst.ROWID)
WHEN MATCHED THEN
  UPDATE
  SET status = src.status;

db小提琴here

【讨论】:

  • update table_name n set status = ;抛出错误单行子查询返回多行。 ora-01427
  • @OracleForLife 如果要更新,请使用MERGE 语句。我添加了一个示例。
猜你喜欢
  • 2013-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-27
  • 2018-04-22
  • 1970-01-01
  • 2012-12-28
  • 1970-01-01
相关资源
最近更新 更多