#sql #oracle #case #wildcard
Вопрос:
У меня есть запрос, который работает так, как задумано в SQL Server, но когда я пытаюсь воспроизвести его в Oracle, он не работает.
- В SQL Server он возвращается
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 Server:
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
Комментарии:
1. Примеры данных, желаемые результаты и четкое объяснение того, что должен делать запрос, помогут. Что такое тип данных
column1
?2. Если я использую CTE из вашего теста SQL Server и вашего Oracle
select
, он, похоже, работает для меня-вот моя скрипка, показывающая, что он делает то, что вы, похоже, хотите dbfiddle.uk/… У Oracle естьtrim
функция, поэтому в данном случае это не имеет смысла делатьltrim(rtrim())
, но это не вызывает проблем3. Вы уверены, что данные в фактической таблице-это то, что вы думаете? Если при переносе данных возникла какая-то проблема и в них есть начальные/ конечные пробелы или управляющие символы
Column1
, это может объяснить, почемуlike
выражение не подходит для вас.4. @GordonLinoff Я не могу предоставить примерные данные, помимо тестовых данных в CTE. КОНКАТ дополняет левую сторону цифрами 0, чтобы достичь 5 символов. Тип данных столбца 1-CHAR (20) Все это объясняется в исходном сообщении В SQL Server, оно возвращает столбец 1 с 5 символами. — (предназначенная функция) В Oracle он возвращает исходные значения. — (не предназначенная функция)
5. Ты смотришь на скрипку, которую я выложил? Возвращает ли скрипка нужные вам результаты? Вы не обрезаете результат перед выполнением
like
, поэтому, если есть начальные или конечные пробелы (в версии Oracle или SQL Server),like
шаблоны не будут совпадать, и вы просто вернетеColumn1
значение.
Ответ №1:
Проблема в том, что вы объявили столбец в таблице Oracle как char(20)
. char(20)
это тип данных фиксированной ширины, поэтому он всегда будет заполнен пробелом до 20 символов. Учитывая ваши примерные данные, это отнимает место и означает, что ни одно из ваших like
предложений не будет соответствовать данным образца из-за пробелов в конце. Вы действительно хотите объявить столбец в таблице varchar2(20)
таким, чтобы он не был пустым.
Если вы просто возьмете CTE из примера SQL Server и используете его с кодом Oracle, запрос вернет то, что вы хотите, потому что 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
Если вы создадите таблицу как a char(20)
и вставите данные, в ней появится пробел, поэтому 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
Вы можете обойти это, обрезав Column1
перед выполнением like
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
в первую очередь, чтобы у вас не было пробелов для обхода
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
Вот скрипка, которая показывает различные варианты.
Комментарии:
1. Спасибо, Джастин, из-за внутренней политики у меня нет доступа к базе данных Oracle, поэтому я попрошу своего POC посмотреть, решит ли это проблему, и свяжусь с вами.
2. Я поддержал ваши решения, так как они работали на меня, спасибо! У меня еще нет 15 баллов, так что это не отражено, но я очень ценю вашу помощь.
Ответ №2:
Альтернатива 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>
Комментарии:
1. Не могу использовать регулярное выражение, у вас есть решение без него?
2. Конечно, просто измените строку #13 на
substr(column1, 1, instr(column1, '-') - 1) val
Ответ №3:
Вы хотите что-то вроде:
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*
Или, проще говоря:
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;
Все выходные данные:
НОВАЯ КОЛОНКА
00012
00078
34567
00123
бд<>скрипка <>здесь
Комментарии:
1. Не могу использовать регулярное выражение, у вас есть решение без него?
2. @NicholasGregory Обновил несколько других решений.
3. Спасибо! У работы сложная система, я могу запрашивать только сторону MSSQL, а не Oracle, поэтому я попрошу своего POC попробовать это завтра :)
)
THEN '000' || SUBSTR(Column1, 1, 2)
WHEN REGEXP_LIKE( Column1, '^d{3}-d{4}s*Или, проще говоря:
Который, для выборочных данных:
Все выходные данные:
НОВАЯ КОЛОНКА 00012 00078 34567 00123
бд<>скрипка <>здесь
Комментарии:
1. Не могу использовать регулярное выражение, у вас есть решение без него?
2. @NicholasGregory Обновил несколько других решений.
3. Спасибо! У работы сложная система, я могу запрашивать только сторону MSSQL, а не Oracle, поэтому я попрошу своего POC попробовать это завтра :)
)
THEN '00' || SUBSTR(Column1, 1, 3)
WHEN REGEXP_LIKE(Column1, '^d{7}-d{5}s*Или, проще говоря:
Который, для выборочных данных:
Все выходные данные:
НОВАЯ КОЛОНКА 00012 00078 34567 00123
бд<>скрипка <>здесь
Комментарии:
1. Не могу использовать регулярное выражение, у вас есть решение без него?
2. @NicholasGregory Обновил несколько других решений.
3. Спасибо! У работы сложная система, я могу запрашивать только сторону MSSQL, а не Oracle, поэтому я попрошу своего POC попробовать это завтра :)
)
THEN SUBSTR(Column1, 3, 5)
ELSE Column1
END AS NewColumn
FROM schema.table1
Или, проще говоря:
Который, для выборочных данных:
Все выходные данные:
НОВАЯ КОЛОНКА 00012 00078 34567 00123
бд<>скрипка <>здесь
Комментарии:
1. Не могу использовать регулярное выражение, у вас есть решение без него?
2. @NicholasGregory Обновил несколько других решений.
3. Спасибо! У работы сложная система, я могу запрашивать только сторону MSSQL, а не Oracle, поэтому я попрошу своего POC попробовать это завтра 🙂