查询在 SQL 服务器中有效,试图在 Oracle 中复制
Query works in SQL Server, trying to replicate in Oracle
我有一个查询在 SQL 服务器中按预期工作,但是当我尝试在 Oracle 中复制它时,它不起作用。
- 在SQL服务器中,returns
Column1
有5个字符。
- 在 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 显示了各种选项。
我有一个查询在 SQL 服务器中按预期工作,但是当我尝试在 Oracle 中复制它时,它不起作用。
- 在SQL服务器中,returns
Column1
有5个字符。 - 在 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 显示了各种选项。