查询在 SQL 服务器中有效,试图在 Oracle 中复制

Query works in SQL Server, trying to replicate in Oracle

我有一个查询在 SQL 服务器中按预期工作,但是当我尝试在 Oracle 中复制它时,它不起作用。

Oracle 语法不是我的强项,我怎样才能让它发挥作用,如有任何建议,我们将不胜感激

SELECT
    CASE
        WHEN Column1 LIKE '__-____' 
            THEN CONCAT('000', (SUBSTR(LTRIM(RTRIM(Column1)), 1, 2)))
        WHEN Column1 LIKE '___-____' 
            THEN CONCAT('00', (SUBSTR(LTRIM(RTRIM(Column1)), 1, 3)))
        WHEN Column1 LIKE '_______-_____' 
            THEN (SUBSTR(LTRIM(RTRIM(Column1)), 3, 5))
        ELSE Column1 
    END AS NewColumn
FROM 
    schema.table1

这里又是一个 CTE,因此您可以看到它在 SQL 服务器中按预期工作:

WITH cte_test AS 
(
    SELECT '12-3456' AS Column1
    UNION ALL
    SELECT '78-9101'
    UNION ALL
    SELECT '1234567-89101'
    UNION ALL
    SELECT '123-4321'
)
SELECT 
    CASE
        WHEN Column1 LIKE '__-____' 
            THEN CONCAT('000', (SUBSTRING(LTRIM(RTRIM(Column1)), 1, 2)))
        WHEN Column1 LIKE '___-____' 
            THEN CONCAT('00', (SUBSTRING(LTRIM(RTRIM(Column1)), 1, 3)))
        WHEN Column1 LIKE '_______-_____' 
            THEN (SUBSTRING(LTRIM(RTRIM(Column1)), 3, 5))
        ELSE Column1
    END AS NewColumn
FROM 
    cte_test

Oracle 替代方案,它(在 temp CTE 中)提取字符串的第一部分(直到负号),然后 - 根据其长度 - 在左侧用最多 5 个字符的零填充它长度,或取最后 5 个字符):

SQL> WITH cte_test AS
  2  (
  3      SELECT '12-3456' AS Column1 from dual
  4      UNION ALL
  5      SELECT '78-9101' from dual
  6      UNION ALL
  7      SELECT '1234567-89101' from dual
  8      UNION ALL
  9      SELECT '123-4321' from dual
 10  ),
 11  temp as
 12    (select column1,
 13            substr(column1, 1, instr(column1, '-') - 1) val
 14     from cte_Test
 15    )
 16  select column1,
 17    lpad(case when length(val) < 5 then val
 18              else substr(val, -5)
 19         end, 5, '0'
 20        ) as result
 21  from temp;

COLUMN1       RESULT
------------- --------------------
12-3456       00012
78-9101       00078
1234567-89101 34567
123-4321      00123

SQL>

你想要这样的东西:

SELECT CASE
       WHEN Column1 LIKE '__-____             '
       THEN '000' || SUBSTR(Column1, 1, 2)
       WHEN Column1 LIKE '___-____            '
       THEN '00' || SUBSTR(Column1, 1, 3)
       WHEN Column1 LIKE '_______-_____       '
       THEN SUBSTR(Column1, 3, 5)
       ELSE Column1
       END AS NewColumn
FROM   schema.table1

或:

SELECT CASE
       WHEN REGEXP_LIKE( Column1, '^\d{2}-\d{4}\s*$' )
       THEN '000' || SUBSTR(Column1, 1, 2)
       WHEN REGEXP_LIKE( Column1, '^\d{3}-\d{4}\s*$' )
       THEN '00' || SUBSTR(Column1, 1, 3)
       WHEN REGEXP_LIKE(Column1, '^\d{7}-\d{5}\s*$' )
       THEN SUBSTR(Column1, 3, 5)
       ELSE Column1 
       END AS NewColumn
FROM   schema.table1

或者,更简单地说:

SELECT SUBSTR(
         '000' || SUBSTR(column1, 1, INSTR(column1, '-') - 1),
         -5
       ) AS newcolumn
FROM   schema.table1

其中,对于示例数据:

CREATE TABLE schema.table1( column1 CHAR(20) );

INSERT INTO schema.table1(column1)
SELECT '12-3456' FROM DUAL UNION ALL
SELECT '78-9101' FROM DUAL UNION ALL
SELECT '1234567-89101' FROM DUAL UNION ALL
SELECT '123-4321' FROM DUAL;

全部输出:

NEWCOLUMN
00012
00078
34567
00123

db<>fiddle here

问题是您已将 Oracle table 中的列声明为 char(20)char(20) 是固定宽度的数据类型,因此它总是 space 填充到 20 个字符。鉴于您的示例数据,这会浪费 space 并且意味着您的 like 子句都不会匹配示例数据,因为尾随 space。您真的想将 table 中的列声明为 varchar2(20),这样它就不会被空白填充。

如果您只是从 SQL 服务器示例中获取 CTE 并将其与您的 Oracle 代码一起使用,查询 returns 您想要什么,因为 Oracle 将 CTE 中的列视为 varchar2

WITH cte_test AS 
(
    SELECT '12-3456' AS Column1 from dual
    UNION ALL
    SELECT '78-9101' from dual
    UNION ALL
    SELECT '1234567-89101' from dual
    UNION ALL
    SELECT '123-4321' from dual
)
SELECT
    CASE
        WHEN Column1 LIKE '__-____' 
            THEN CONCAT('000', (SUBSTR(LTRIM(RTRIM(Column1)), 1, 2)))
        WHEN Column1 LIKE '___-____' 
            THEN CONCAT('00', (SUBSTR(LTRIM(RTRIM(Column1)), 1, 3)))
        WHEN Column1 LIKE '_______-_____' 
            THEN (SUBSTR(LTRIM(RTRIM(Column1)), 3, 5))
        ELSE Column1 
    END AS NewColumn
FROM cte_test

如果您将 table 创建为 char(20) 并插入数据,它会得到 space 填充,因此 like 语句不会执行您想要的操作

create table char_test( column1 char(20) );

insert into char_test
WITH cte_test AS 
(
    SELECT '12-3456' AS Column1 from dual
    UNION ALL
    SELECT '78-9101' from dual
    UNION ALL
    SELECT '1234567-89101' from dual
    UNION ALL
    SELECT '123-4321' from dual
    )
    select * from cte_test;

SELECT
    CASE
        WHEN Column1 LIKE '__-____' 
            THEN CONCAT('000', (SUBSTR(LTRIM(RTRIM(Column1)), 1, 2)))
        WHEN Column1 LIKE '___-____' 
            THEN CONCAT('00', (SUBSTR(LTRIM(RTRIM(Column1)), 1, 3)))
        WHEN Column1 LIKE '_______-_____' 
            THEN (SUBSTR(LTRIM(RTRIM(Column1)), 3, 5))
        ELSE Column1 
    END AS NewColumn
FROM char_test

您可以通过在执行 like

之前修剪 Column1 来解决这个问题
SELECT
    CASE
        WHEN trim(Column1) LIKE '__-____' 
            THEN CONCAT('000', (SUBSTR(Column1, 1, 2)))
        WHEN trim(Column1) LIKE '___-____' 
            THEN CONCAT('00', (SUBSTR(Column1, 1, 3)))
        WHEN trim(Column1) LIKE '_______-_____' 
            THEN (SUBSTR(Column1, 3, 5))
        ELSE Column1 
    END AS NewColumn
FROM char_test

但更好的解决方案是首先将列声明为 varchar2,这样您就没有 space 填充可以解决

create table varchar_test( column1 varchar2(20) );

insert into varchar_test
WITH cte_test AS 
(
    SELECT '12-3456' AS Column1 from dual
    UNION ALL
    SELECT '78-9101' from dual
    UNION ALL
    SELECT '1234567-89101' from dual
    UNION ALL
    SELECT '123-4321' from dual
    )
    select * from cte_test;

SELECT
    CASE
        WHEN Column1 LIKE '__-____' 
            THEN CONCAT('000', SUBSTR(Column1, 1, 2))
        WHEN Column1 LIKE '___-____' 
            THEN CONCAT('00', SUBSTR(Column1, 1, 3))
        WHEN Column1 LIKE '_______-_____' 
            THEN (SUBSTR(Column1, 3, 5))
        ELSE Column1 
    END AS NewColumn
FROM varchar_test

这里 a fiddle 显示了各种选项。