how to add different column with one code into one column? - oracle

id text
1 hi
1 how are u
1 fine ?
2 rad
2 qey
3
I am searching for a query where it can let me insert id = 1 to another table in one column
id test
1 hi how are you fine ?
2 rad qey
with the listagg function , i will have such result : hi how are you fine ? .. can i have it such
hi
how are u
fine ?

This query can be used to achieve your result:
WITH tab(id,text) AS (
SELECT 1, 'hi' FROM dual UNION ALL
SELECT 1, 'how are u' FROM dual UNION ALL
SELECT 1, 'fine ?' FROM dual UNION ALL
SELECT 2, 'rad' FROM dual UNION ALL
SELECT 2, 'qey' FROM dual UNION ALL
SELECT 3, NULL FROM dual)
-----
--End of data
-----
SELECT ID,
listagg(text, ' ') within GROUP (ORDER BY ROWNUM) AS text
FROM tab
GROUP BY ID;
Output
ID TEXT
1 hi how are u fine ?
2 rad qey
3
But there is one problem, although order by rownum is used but you cannot guaranty the order of text, its better to have one more column in your table that can define the order of the text as below
id text order_text
1 hi 1
1 how are u 2
1 fine ? 3
2 rad 1
2 qey 2
3 1
and the use the query as
SELECT ID,
listagg(text, ' ') within GROUP (ORDER BY order_text) AS text
FROM tab
GROUP BY ID;

You can try the LISTAGG function.
For more information, see here.

Related

How to achieve one to many relation ship data as coma separated in below format

I have 2 tables and it is one to many relationship (parent & chdild). Its a dynamic table ,not a fixed data. More data can come in table.
user
Aid userName
1 author1
2 author2
3 author3
4 author4
etc
books
bid NAME Aid
1 x 1
2 y 1
3 z 2
4 z1 3
The Expected output is like below
'author1' AS author1,'x' AS x,'y' AS y,'author2' AS author2,'z' AS z,'author3' AS author3,'z1' AS z1
I have tried with parent table but how to get all row like in above format.
select listagg('''' || UserName || ''' as "' || UserName || '"', ',') within group (order by Aid)
from (select distinct Aid,UserName from user order by Aid);
Firstly, don't do this. If you want to pivot the data, do it in the third-party application (Java, C#, PHP, etc.) that you are using to access the database because that will support pivoting a data set rather than trying to force it through some dynamic SQL and trying to get a query to do something it is not intended to do.
However, if you really must (don't) then:
SELECT LISTAGG('''' || name || ''' AS ' || name, ',')
WITHIN GROUP (ORDER BY name) AS names
FROM (
SELECT username AS name
FROM "USER"
UNION
SELECT name
FROM books
)
Which, for the sample data:
CREATE TABLE "USER" (Aid, userName) AS
SELECT 1, 'author1' FROM DUAL UNION ALL
SELECT 2, 'author2' FROM DUAL UNION ALL
SELECT 3, 'author3' FROM DUAL UNION ALL
SELECT 4, 'author4' FROM DUAL;
CREATE TABLE books (bid, NAME, Aid) AS
SELECT 1, 'x', 1 FROM DUAL UNION ALL
SELECT 2, 'y', 1 FROM DUAL UNION ALL
SELECT 3, 'z', 2 FROM DUAL UNION ALL
SELECT 4, 'z1', 3 FROM DUAL;
Outputs:
NAMES
'author1' AS author1,'author2' AS author2,'author3' AS author3,'author4' AS author4,'x' AS x,'y' AS y,'z' AS z,'z1' AS z1
fiddle

PL/SQL: Need help creating calculated columns based on conditions. to be done in select query

I am trying to count all the distinct ids based on conditions. But I am unable to figure out where I am going wrong with the syntax. The logic is
COUNTD(IF ([column_name1] = 1) THEN [DATAPAGEID] END)
This is the formula I used in Tableau. However when writing it in a PL/SQL query as
Select FT.NAME, COUNT(DISTINCT FT.pageID IF FT."column_name" = 1 )
as total_expected
FROM
( Sub Query) FT
Group by FT.Name
Order by FT.Name
Needless to say its throwing errors. Now I can write separate queries which can give me each number using a where condition. For example, if I wanted a count of distinct pageid where column_name1 = 1, I would write something like this
Select FT.SITENAME, COUNT(DISTINCT DATAPAGEID) as Datapage
from
(sub query)
WHERE FT."column_name" = 1
but the problem with that is that I have other calculated columns in the query which will all need to be part of the same row. To illustrate here's what the table would look like
name Calculated_Column1 Calculated_Column2 Calculated_column3
abc 781 811 96.54%
pqr 600 800 75.00%
where calculated_column3 is the result of 781/811. Therefore I can't have a new query for each column. I thought using an if condition when calculating columns will solve this, but I can't get the syntax right somehow.
Therefore, I need to know how can I create conditional calculated columns within the select query. If I have not explained this well, please let me know and I will try to clarify further.
You can use a CASE block inside the count (DISTINCT ) as shown.
SELECT FT.NAME,
COUNT(DISTINCT
CASE
WHEN DATAPAGEID = 1
THEN 1
ELSE 0
END ) Calculated_Column1,
COUNT(DISTINCT
CASE
WHEN DATAPAGEID = 2
THEN 1
ELSE 0
END ) Calculated_Column2,
( COUNT(DISTINCT
CASE
WHEN DATAPAGEID = 1
THEN 1
ELSE 0
END ) / COUNT(DISTINCT
CASE
WHEN DATAPAGEID = 2
THEN 1
ELSE 0
END ) ) * 100||'%' Calculated_Column3
FROM
( SELECT 'abc' name, 1 DATAPAGEID FROM dual
UNION ALL
SELECT 'abc' name, 1 DATAPAGEID FROM dual
UNION ALL
SELECT 'pqr' name, 2 DATAPAGEID FROM dual
UNION ALL
SELECT 'pqr' name, 2 DATAPAGEID FROM dual
UNION ALL
SELECT 'pqr' name, 3 DATAPAGEID FROM dual
) FT
GROUP BY FT.Name
ORDER BY FT.Name;
Output is
abc 1 1 100%
pqr 1 2 50%

Parse Values with Delimiters Using REGEXP_SUPSTR in Oracle 10g

I have a table called TVL_DETAIL that contains column TVL_CD_LIST. Column TVL_CD_LIST contains three records:
TVL_CD_LIST:
M1180_Z6827
K5900_Z6828
I2510
I've used the following code in an attempt to return the values only(so excluding the underscore):
SELECT
TVL_CD_LIST
FROM TVL_DETAIL
WHERE TVL_CD_LIST IN (SELECT regexp_substr(TVL_CD_LIST,'[^_]+', 1, level) FROM DUAL
CONNECT BY regexp_substr(TVL_CD_LIST,'[^_]+', 1, level) IS NOT NULL)
What I was expecting to see returned in separate rows was:
M1180
Z6827
K5900
Z6828
I2510
But it only returns I2510(which is the original value that doesn't contain an underscore).
What am I doing wrong? Any help is appreciated. Thanks!
To answer your question, you are querying for the list where it matches a sub-element and that will only happen where the list is comprised of one element. What you really wanted to select are the sub-elements themselves.
Note: Explanation of why parsing strings using the regex form '[^_]+' is bad here: https://stackoverflow.com/a/31464699/2543416
You want to parse the list, selecting the elements:
SQL> with TVL_DETAIL(TVL_CD_LIST) as (
select 'M1180_Z6827' from dual union
select 'K5900_Z6828' from dual union
select 'I2510' from dual
)
SELECT distinct regexp_substr(TVL_CD_LIST, '(.*?)(_|$)', 1, level, NULL, 1) element
FROM TVL_DETAIL
CONNECT BY level <= LENGTH(regexp_replace(TVL_CD_LIST, '[^_]', '')) + 1;
-- 11g CONNECT BY level <= regexp_count(TVL_CD_LIST, '_') + 1;
ELEMENT
-----------
Z6827
K5900
M1180
I2510
Z6828
SQL>
And this is cool if you want to track by row and element within row:
SQL> with TVL_DETAIL(row_nbr, TVL_CD_LIST) as (
select 1, 'M1180_Z6827' from dual union
select 2, 'K5900_Z6828' from dual union
select 3, 'I2510' from dual
)
SELECT row_nbr, column_value substring_nbr,
regexp_substr(TVL_CD_LIST, '(.*?)(_|$)', 1, column_value, NULL, 1) element
FROM TVL_DETAIL,
TABLE(
CAST(
MULTISET(SELECT LEVEL
FROM dual
CONNECT BY level <= LENGTH(regexp_replace(TVL_CD_LIST, '[^_]', '')) + 1
-- 11g CONNECT BY LEVEL <= REGEXP_COUNT(TVL_CD_LIST, '_')+1
) AS sys.OdciNumberList
)
)
order by row_nbr, substring_nbr;
ROW_NBR SUBSTRING_NBR ELEMENT
---------- ------------- -----------
1 1 M1180
1 2 Z6827
2 1 K5900
2 2 Z6828
3 1 I2510
SQL>
EDIT: Oops, edited to work with 10g as REGEXP_COUNT is not available until 11g.
The query you have used creates the list but you are comparing the list of record with column it self using the in clause, as such M1180 or Z6827 cannot be equal to M1180_Z6827 and so for K5900_Z6828. I2510 has only one value so it gets matched.
You can use below query if your requirement is exactly what you have mentioned in your desired output.
SQL> WITH tvl_detail AS
2 (SELECT 'M1180_Z6827' tvl_cd_list FROM dual
3 UNION ALL
4 SELECT 'K5900_Z6828' FROM dual
5 UNION ALL
6 SELECT 'I2510' FROM dual)
7 ---------------------------
8 --- End of data preparation
9 ---------------------------
10 SELECT regexp_substr(tvl_cd_list, '[^_]+', 1, LEVEL) AS tvl_cd_list
11 FROM tvl_detail
12 CONNECT BY regexp_substr(tvl_cd_list, '[^_]+', 1, LEVEL) IS NOT NULL
13 AND PRIOR tvl_cd_list = tvl_cd_list
14 AND PRIOR sys_guid() IS NOT NULL;
OUTPUT:
TVL_CD_LIST
--------------------------------------------
I2510
K5900
Z6828
M1180
Z6827

Getting Results in Horizontal way in oracle

I wrote query
select s_id from emp
where s_inv=12
i got results in this manner
1
2
3
4
5
but i want it in this format
1 2 3 4 5
If you need your result in a single column, you can use LISTAGG:
with emp(s_id, s_inv) as
(
select 1, 12 from dual union all
select 2, 12 from dual union all
select 3, 12 from dual union all
select 4, 12 from dual union all
select 5, 12 from dual
)
select listagg(s_id, ' ') within group (order by s_id)
from emp
where s_inv = 12
If you need to build many columns on the same row, you should first define how many columns will your result have

remove a varchar2 string from the middle of table data values

Data in the file_name field of the generation table should be an assigned number, then _01, _02, or _03, etc. and then .pdf (example 82617_01.pdf).
Somewhere, the program is putting a state name and sometimes a date/time stamp, between the assigned number and the 01, 02, etc. (82617_ALABAMA_01.pdf or 19998_MAINE_07-31-2010_11-05-59_AM.pdf or 5485325_OREGON_01.pdf for example).
We would like to develop a SQL statement to find the bad file names and fix them. In theory it seems rather simple to find file names that include a varchar2 data type and remove it, but putting the statement together is beyond me.
Any help or suggestions appreciated.
Something like:
UPDATE GENERATION
SET FILE_NAME (?)
WHERE FILE_NAME (?...LIKE '%STRING%');?
You can find the problem rows like this:
select *
from Files
where length(FILE_NAME) - length(replace(FILE_NAME, '_', '')) > 1
You can fix them like this:
update Files
set FILE_NAME = SUBSTR(FILE_NAME, 1, instr(FILE_NAME, '_') -1) ||
SUBSTR(FILE_NAME, instr(FILE_NAME, '_', 1, 2))
where length(FILE_NAME) - length(replace(FILE_NAME, '_', '')) > 1
SQL Fiddle Example
You can also use Regexp_replace function:
SQL> with t1(col) as(
2 select '82617_mm_01.pdf' from dual union all
3 select '456546_khkjh_89kjh_67_01.pdf' from dual union all
4 select '19998_MAINE_07-31-2010_11-05-59_AM.pdf' from dual union all
5 select '5485325_OREGON_01.pdf' from dual
6 )
7 select col
8 , regexp_replace(col, '^([0-9]+)_(.*)_(\d{2}\.pdf)$', '\1_\3') res
9 from t1;
COL RES
-------------------------------------- -----------------------------------------
82617_mm_01.pdf 82617_01.pdf
456546_khkjh_89kjh_67_01.pdf 456546_01.pdf
19998_MAINE_07-31-2010_11-05-59_AM.pdf 19998_MAINE_07-31-2010_11-05-59_AM.pdf
5485325_OREGON_01.pdf 5485325_01.pdf
To display good or bad data regexp_like function will come in handy:
SQL> with t1(col) as(
2 select '826170_01.pdf' from dual union all
3 select '456546_01.pdf' from dual union all
4 select '19998_MAINE_07-31-2010_11-05-59_AM.pdf' from dual union all
5 select '5485325_OREGON_01.pdf' from dual
6 )
7 select col bad_data
8 from t1
9 where not regexp_like(col, '^[0-9]+_\d{2}\.pdf$');
BAD_DATA
--------------------------------------
19998_MAINE_07-31-2010_11-05-59_AM.pdf
5485325_OREGON_01.pdf
SQL> with t1(col) as(
2 select '826170_01.pdf' from dual union all
3 select '456546_01.pdf' from dual union all
4 select '19998_MAINE_07-31-2010_11-05-59_AM.pdf' from dual union all
5 select '5485325_OREGON_01.pdf' from dual
6 )
7 select col good_data
8 from t1
9 where regexp_like(col, '^[0-9]+_\d{2}\.pdf$');
GOOD_DATA
--------------------------------------
826170_01.pdf
456546_01.pdf
To that end your update statement might look like this:
update your_table
set col = regexp_replace(col, '^([0-9]+)_(.*)_(\d{2}\.pdf)$', '\1_\3');
--where clause if needed

Resources