Overview: I am tasked with providing a data extract from an Oracle database as a pipe-delimited output text file. I will be using SQLPlus to do this on the server where the data lives. Ordinarily, this task is not beyond my experience, but this time, the business desires column headers to be present.
Consider the following five columns that I need to output:
SELECT
a.USER_NAME || '|'
|| a.LAST_NAME || '|'
|| a.FIRST_NAME || '|'
|| b.PRODUCT_PURCHASED || '|'
|| c.DATEPURCHASED
FROM ...
WHERE ... ;
This SQL works fine, where the output looks like:
omnusruthius|ruthius|omnus|stackoverflow_prod|19-APR-16
However, the business wants it to look like:
USER_NM|LAST|FIRST|PROD|EFFECTIVE_DATE
omnusruthius|ruthius|omnus|stackoverflow_prod|19-APR-16
Problem: So the objective here is essentially to output the first row with custom-named column headers (aliases), as shown above. So my first approach was to try something like:
SELECT
a.USER_NAME AS USER_NM || '|'
|| a.LAST_NAME AS LAST || '|'
|| a.FIRST_NAME AS FIRST || '|'
|| b.PRODUCT_PURCHASED AS PROD || '|'
|| c.DATEPURCHASED AS EFFECTIVE_DATE
FROM ...
WHERE ...
Unfortunately, I receive:
ORA-00923: FROM keyword not found where expected
I'm not sure how that would help anyway, as the original SQL output without aliases does not show column headers in the first row anyway. Remember, this is through the command line (SQLPlus), not Toad or some other RDMS.
So then I tried:
SELECT
'USER_NM', 'LAST', 'FIRST', 'PROD', 'EFFECTIVE_DATE' FROM DUAL
UNION ALL
SELECT
a.USER_NAME || '|'
|| a.LAST_NAME || '|'
|| a.FIRST_NAME || '|'
|| b.PRODUCT_PURCHASED || '|'
|| c.DATEPURCHASED
FROM ...
WHERE ...
Which gives the following error:
ORA-01789: query block has incorrect number of result columns
I feel so close to the solution, what am I missing here? Any help will be appreciated!
Edit: Just a note to a future reader, both answers here will help you solve this problem, but upon further tweaking, I realize we've all been overthinking the solution. I'm not going to propose a new solution as the change is trivial, but consider doing the following instead:
SELECT 'USER_NM|LAST|FIRST|PROD|EFFECTIVE_DATE' FROM DUAL;
SELECT a.USER_NAME AS USER_NM || '|'
|| a.LAST_NAME AS LAST || '|'
|| a.FIRST_NAME AS FIRST || '|'
|| b.PRODUCT_PURCHASED AS PROD || '|'
|| c.DATEPURCHASED AS EFFECTIVE_DATE
FROM ...
WHERE ...
ORDER BY ... ;
The key here is the use of the semicolons in SQL*Plus. That first SELECT statement is completely independent from the second; no UNION is necessary as the output of the first query is automatically displayed immediately before the output of the second query. Both can have their own rules, which is especially convenient if your latter query is much more complicated. I can confirm the above query is working, and I'm surprised it took me that long to make that realization...
When concatenating make sure the header is a single string. Because you are concatenating the values in columns to be on one row.
If comma separation is used, as you have it in the question, the result block should also have 5 columns,which is not the case.
SELECT
'USER_NM|LAST|FIRST|PROD|EFFECTIVE_DATE' FROM DUAL
UNION ALL
SELECT
a.USER_NAME || '|'
|| a.LAST_NAME || '|'
|| a.FIRST_NAME || '|'
|| b.PRODUCT_PURCHASED || '|'
|| c.DATEPURCHASED
FROM ...
WHERE ...
Edit: The columns can also be sorted.
SELECT 'USER_NM|LAST|FIRST|PROD|EFFECTIVE_DATE' FROM DUAL
UNION ALL
SELECT * FROM (
SELECT
a.USER_NAME || '|'
|| a.LAST_NAME || '|'
|| a.FIRST_NAME || '|'
|| b.PRODUCT_PURCHASED || '|'
|| c.DATEPURCHASED
FROM ...
WHERE ...
ORDER BY DATEPURCHASED) --add any other columns needed
Since you tagged the question with SQL*Plus, you can use the PROMPT command to generate the header, which avoids complications ordering the results with a union:
PROMPT USER_NM|LAST|FIRST|PROD|EFFECTIVE_DATE
SELECT
a.USER_NAME AS USER_NM || '|'
|| a.LAST_NAME AS LAST || '|'
|| a.FIRST_NAME AS FIRST || '|'
|| b.PRODUCT_PURCHASED AS PROD || '|'
|| c.DATEPURCHASED AS EFFECTIVE_DATE
FROM ...
WHERE ...
ORDER BY ...
That takes the headings out of the SQL and into the client realm, where it arguably belongs. This also works in SQL Developer, and other clients may be able to do something similar. It won't work if you run the query on its own from another client, or over JDBC, or whatever; but then whatever is running the query can (and maybe should) provide the header in that case too.
If you aren't already, you could also consider doing SET HEADING OFF or SET PAGESIZE 0 to suppress the column headings from the query itself (though from what you said you're already doing that); and possibly SET EMBED OFF, though I don't think that's needed unless you do a separate query to generate the header line.
I have a column called notation in the correspondence table in our database. The values are as such for this column:
notation
SSQSUPER405575681 || 032-797 || 034828 1141289
SGQSUPER405575091 || 032-797 || 034828 1140802
SGQSUPER395729693 || 032-797 || 034828 1061943
I want to have this value only SSQSUPER405575681 or SGQSUPER405575091 for notation column and trim the rest part of the string such as || 032-797 || 034828 1141289 in the 1st row and || 032-797 || 034828 1140802 in 2nd row.
Please tell me how can i do that.
Well, Sybase functions are often pretty similar to T-SQL for SQL Server, so to extract the desired substrings out the notation column, try:
select
substring([notation], 1, patindex ('%||%',[notation]) - 1) as f1,
substring([notation],
patindex ('%||%',[notation]),
len([notation]) - patindex ('%||%',[notation]) ) as f2
from [correspondence]
If that doesn't work exactly, you might see if there is some variation in the way the Sybase functions work.
Is there any SQL SELECT query that can be done in oracle to detect ascii characters such as LF, CR in fields? Basically any characters people have known to cause trouble in a oracle db environment in terms of breaking jobs/procedures.etc
I doubt this would work: - happy to use regex if possible
select * from table
where column like '%chr(13)%'
select * from table
where regexp_like(column, '(' || chr(13) || '|' || chr(10) || ')')
The regex used here is a form of (a|b|c) which matches the string if it contains a OR b OR c
I've got some SQL that I'd like to format correctly for a mailout (generated directly from SQL - don't ask!). The code is as follows:
SELECT wm_concat('<br>• ' || FIELD1 || ' ' || FIELD2 || ' : ' || FIELD 3 || ' text') AS "Team"
Okay, so this kinda works - but it places a comma at the end of each line. Silly question, and possibly quite trivial, but is there anyway at all to remove the comma please? I think it's being added by the wm_concat function
Thanks
Yes the WM_CONCAT function puts a comma between each value it concatenates.
If there are no commas in your data you could do this:
SELECT replace (wm_concat('<br>• ' || FIELD1 || ' ' || FIELD2 || ' : '
|| FIELD 3 || ' text'),
',', null) AS "Team"
If you are on 11G you can use the new LISTAGG function instead:
SELECT LISTAGG ('<br>• ' || FIELD1 || ' ' || FIELD2 || ' : '
|| FIELD 3 || ' text')
WITHIN GROUP (ORDER BY <something>) AS "Team"
That will produce a result without commas.
Just trim the string for trailing commas:
RTRIM( wm_concat(...), ',' )
Oracle 10g provides a very convenient function wm_concat used to solve line reclassified demand, very easy to use this function, but the function provides only ',' this kind of delimiter.
In fact, as long as some simple conversion you can use other delimiters separated, the first thought is replace function
with t as( select 'a' x from dual union select 'b' from dual )
select replace(wm_concat(x),',','-') from t;
But taking into account the string itself may contain ',' character, use the above SQL will lead to erroneous results, but also made some changes to the above SQL.
with t as( select 'a' x from dual union select 'b' y from dual)
select substr(replace(wm_concat('%'||x),',%','-'),2) from t;
In the above SQL by a '%' as a separator, and then replace the '%' to remove the error. The program assumes that the string does not exist within the '%' string to replace the '%' in the SQL can also use other special characters.
Source: http://www.databaseskill.com/3400944/
You can create your own aggregate functions in Oracle and use those to aggregate strings.
Or use the StrAgg function written by Tom Kyte: http://www.sqlsnippets.com/en/topic-11591.html
SELECT StrAgg('<br>• ' || FIELD1 || ' ' || FIELD2 || ' : ' || FIELD 3 || ' text') AS "Team"
FROM Abc
I need to trim New Line (Chr(13) and Chr(10) and Tab space from the beginning and end of a String) in an Oracle query. I learnt that there is no easy way to trim multiple characters in Oracle. "trim" function trims only single character. It would be a performance degradation if i call trim function recursivelly in a loop using a function. I heard regexp_replace can match the whitespaces and remove them.
Can you guide of a reliable way to use regexp_replace to trim multiple tabspaces or new lines or combinations of them in beginning and end of a String. If there is any other way, Please guide me.
If you have Oracle 10g, REGEXP_REPLACE is pretty flexible.
Using the following string as a test:
chr(9) || 'Q qwer' || chr(9) || chr(10) ||
chr(13) || 'qwerqwer qwerty' || chr(9) ||
chr(10) || chr(13)
The [[:space:]] will remove all whitespace, and the ([[:cntrl:]])|(^\t) regexp will remove non-printing characters and tabs.
select
tester,
regexp_replace(tester, '(^[[:space:]]+)|([[:space:]]+$)',null)
regexp_tester_1,
regexp_replace(tester, '(^[[:cntrl:]^\t]+)|([[:cntrl:]^\t]+$)',null)
regexp_tester_2
from
(
select
chr(9) || 'Q qwer' || chr(9) || chr(10) ||
chr(13) || 'qwerqwer qwerty' || chr(9) ||
chr(10) || chr(13) tester
from
dual
)
Returning:
REGEXP_TESTER_1: "Qqwerqwerqwerqwerty"
REGEXP_TESTER_2: "Q qwerqwerqwer qwerty"
Hope this is of some use.
This how I would implement it:
REGEXP_REPLACE(text,'(^[[:space:]]*|[[:space:]]*$)')
How about the quick and dirty translate function?
This will remove all occurrences of each character in string1:
SELECT translate(
translate(
translate(string1, CHR(10), '')
, CHR(13), '')
, CHR(09), '') as massaged
FROM BLAH;
Regexp_replace is an option, but you may see a performance hit depending on how complex your expression is.
You could use both LTRIM and RTRIM.
select rtrim(ltrim('abcdab','ab'),'ab') from dual;
If you want to trim CHR(13) only when it comes with a CHR(10) it gets more complicated. Firstly, translated the combined string to a single character. Then LTRIM/RTRIM that character, then replace the single character back to the combined string.
select replace(rtrim(ltrim(replace('abccccabcccaab','ab','#'),'#'),'#'),'#','ab') from dual;
TRANSLATE (column_name, 'd'||CHR(10)||CHR(13), 'd')
The 'd' is a dummy character, because translate does not work if the 3rd parameter is null.
For what version of Oracle? 10g+ supports regexes - see this thread on the OTN Discussion forum for how to use REGEXP_REPLACE to change non-printable characters into ''.
I know this is not a strict answer for this question, but I've been working in several scenarios where you need to transform text data following these rules:
No spaces or ctrl chars at the beginning of the string
No spaces or ctrl chars at the end of the string
Multiple ocurrencies of spaces or ctrl chars will be replaced to a single space
Code below follow the rules detailed above:
WITH test_view AS (
SELECT CHR(9) || 'Q qwer' || CHR(9) || CHR(10) ||
CHR(13) || ' qwerqwer qwerty ' || CHR(9) ||
CHR(10) || CHR(13) str
FROM DUAL
) SELECT
str original
,TRIM(REGEXP_REPLACE(str, '([[:space:]]{2,}|[[:cntrl:]])', ' ')) fixed
FROM test_view;
ORIGINAL FIXED
---------------------- ----------------------
Q qwer Q qwer qwerqwer qwerty
qwerqwer qwerty
1 row selected.
If at all anyone is looking to convert data in 1 variable that lies in 2 or 3 different lines like below
'Data1
Data2'
And you want to display data as 'Data1 Data2' then use below
select TRANSLATE ('Data1
Data2', ''||CHR(10), ' ') from dual;
it took me hrs to get the right output. Thanks to me I just saved you 1 or 2 hrs :)
In cases where the Oracle solution seems overly convoluted, I create a java class with static methods and then install it as a package in Oracle. This might not be as performant, but you will eventually find other cases (date conversion to milliseconds for example) where you will find the java fallback helpful.
Below code can be used to Remove New Line and Table Space in text column
Select replace(replace(TEXT,char(10),''),char(13),'')
Try the code below.
It will work if you enter multiple lines in a single column.
create table products (prod_id number , prod_desc varchar2(50));
insert into products values(1,'test first
test second
test third');
select replace(replace(prod_desc,chr(10),' '),chr(13),' ') from products where prod_id=2;
Output :test first test second test third
TRIM(BOTH chr(13)||chr(10)||' ' FROM str)
Instead of using regexp_replace multiple time use (\s) as given below;
SELECT regexp_replace('TEXT','(\s)','')
FROM dual;
Fowloing code remove newline from both side of string:
select ltrim(rtrim('asbda'||CHR(10)||CHR(13) ,''||CHR(10)||CHR(13)),''||CHR(10)||CHR(13)) from dual
but in most cases this one is just enought :
select rtrim('asbda'||CHR(10)||CHR(13) ,''||CHR(10)||CHR(13))) from dual
UPDATE My_Table
SET Mycolumn1 =
TRIM (
TRANSLATE (Mycolumn1,
CHR (10) || CHR (11) || CHR (13),
' '))
WHERE ( INSTR (Mucolumn1, CHR (13)) > 0
OR INSTR (Mucolumn1, CHR (10)) > 0
OR INSTR (Mucolumn1, CHR (11)) > 0);