String concatenation after DISTINCT result selected - oracle

I have below query:
SELECT xmlagg(xmlparse(content RESULTS || '|' wellformed) ORDER BY RESULTS).getclobval() AS RESULTS
FROM
(
SELECT distinct ' ' || result|| ' - ' || result_final || ' xxx' as RESULTS from myTable where ID = '123456'
);
Currently the " xxx" will append at the end of each result_final, how can achieve by concatenating it to the very beginning of the final string of the query?
' xxx'|| RESULTS
With condition, above concatenation should only take place when result=x, else only RESULTS should be printed.

Move that string in front of the "result" not behind it.
Though, as additional condition should be met, use your current query (without 'xxx') as a subquery and apply condition via CASE.
With dummy sample data:
SQL> DESC mytable
Name Null? Type
----------------------------------------- -------- ----------------------------
RESULT CHAR(1)
RESULT_FINAL CHAR(1)
ID CHAR(6)
SQL> SELECT * FROM mytable;
R R ID
- - ------
x y 123456
SQL> SELECT CASE
2 WHEN TO_CHAR (results) = 'x' THEN ' xxx' || results
3 ELSE results
4 END AS results
5 FROM (SELECT XMLAGG (XMLPARSE (CONTENT RESULTS || '|' WELLFORMED)
6 ORDER BY RESULTS).getclobval () AS RESULTS
7 FROM (SELECT DISTINCT
8 ' ' || result || ' - ' || result_final AS RESULTS
9 FROM myTable
10 WHERE ID = '123456'));
RESULTS
--------------------------------------------------------------------------------
x - y|
SQL>

Related

Oracle Number type without precision - how do I know if it is a whole number or not

Our vendor's database has Number types for all numbers including whole numbers and decimal numbers. Literally, every numeric type column is created as NUMBER without precision and scale.
This is a big problem as we need to map these columns to proper data types on our target system, we are loading data from these tables into.
We need to know if a number is an integer or decimal.
Other than doing a random sampling/data profiling, is it possible to infer proper data types?
UPDATE:
I accepted the answer below and suggestion from #Bohemian. In addition to that, I will use SAMPLE clause that will do a random sampling of the table since my source tables are huge (many billions of rows).
SELECT
MAX(CASE WHEN col1 IS NOT NULL AND col1 <> round(col1, 0) then 1 else 0 end) as col1,
MAX(CASE WHEN col2 IS NOT NULL AND col2 <> round(col2, 0) then 1 else 0 end) as col2
FROM TABLE
SAMPLE(0.05)
If I want to sample only X rows, use formula below to SAMPLE(N):
Xrows*100/table_rows_total
You can try selecting each FIELD, and seeing if all values of FIELD are equal to ROUND(FIELD, 0). If they are, then that field should be integer. If not, decimal.
I have answered it in this other post and the query that you would use to find the maximum number of decimal places in all of the number columns is the same as that one.
To identify the columns with the their maximum decimal position digits, you can run the SQL below after substituting the MY_SCHEMA, MY_TABLE and the number 10 with say 25 to identify columns that have values over 25 decimal places. This SQL will generate a SQL that should be run to get your result.
SELECT 'SELECT ' || LISTAGG('MAX(LENGTH(TO_CHAR(ABS(' || column_name || ') - FLOOR(ABS(' || column_name || '))))) - 1 AS decimals_' || column_name || CHR(13)
, CHR(9)|| ', ') WITHIN GROUP (ORDER BY rn) ||
' FROM ' || owner || '.' || table_name || CHR(13) ||
' WHERE ' || CHR(13) ||
LISTAGG('(LENGTH(TO_CHAR(ABS(' || column_name || ') - FLOOR(ABS(' || column_name || ')))) - 1) > 10 ' || CHR(13)
, CHR(9)|| ' OR ')
WITHIN GROUP (ORDER BY rn) AS Nasty_Numbers_Finder_Query
FROM
(
SELECT owner, table_name, column_name,
row_number() OVER ( PARTITION BY table_name ORDER BY rownum) rn
FROM dba_tab_columns
WHERE
OWNER = 'MY_SCHEMA'
AND table_name = 'MY_TABLE'
AND (data_type LIKE '%FLOAT%'
OR data_type LIKE '%NUMERIC%')
) a
GROUP BY owner, table_name
For more information, I have blogged about it here.

plsql to fetch the max sequence line for every header and update the null values of the column with next sequence number for the particular header

I have a requirement like below .
I have a table with 2 columns, (contract_id,line_num)
create table tx (contract_id number,line_num number);
I have data like
contract_id || line_num
----------- ---------
1 || 1
1 || null
1 || null
2 || 1
2 || null
2 || null
3 || 1
3 || null
I have to write a plsql block , first I have to get the max(line_num) for each contract_id, and then update the next sequence number for each contract_id where ever there is null in line_num column for each contract_id using cursor for loop.
I should get like below
contract_id || line_num
----------- ---------
1 || 1
1 || 2
1 || 3
2 || 1
2 || 2
2 || 3
3 || 1
3 || 2
can u pls help me with this...
DECLARE
var1 NUMBER := 0;
BEGIN
SELECT MAX (gocpd.column46)
INTO var1
FROM gecm_okc_con_part_details gocpd, okc_rep_contracts_all orca
WHERE gocpd.contract_id = orca.contract_id
AND orca.attribute12 = 'GE-Power' --AND GOCPD.COLUMN46 = NULL AND GOCPD.CONTRACT_ID = 525215; END
;
BEGIN
UPDATE GECM_OKC_CON_PART_DETAILS GOCPD
SET GOCPD.COLUMN46 = var1 + 1
FROM okc_rep_contracts_all orca
WHERE gocpd.contract_id = orca.contract_id
AND orca.attribute12 = 'GE-Power'
AND gocpd.column46 = NULL
AND gocpd.contract_id = 525215;
COMMIT;
END;
END;
You have not provided enough details I requested and I cannot correlate your PL/SQL code with the data you provided.
I am assuming that you are simply interested to update the rows based on NULL values and then incrementing from the MAX(LINE_NUM). If yes, something like this should solve your purpose. If not, please add more details in your question.
MERGE INTO tx tgt USING (
SELECT
ROWID,
contract_id,
CASE
WHEN line_num IS NULL THEN ROW_NUMBER() OVER(
PARTITION BY contract_id
ORDER BY
contract_id
) + MAX(line_num) OVER(
PARTITION BY contract_id
) - 1
ELSE line_num
END
AS line_num
FROM
tx
)
src ON ( src.rowid = tgt.rowid )
WHEN MATCHED THEN UPDATE SET tgt.line_num = src.line_num;
SQL Fiddle Demo

Showing Multiple rows against an ID in One Row - Oracle SQL

My question is somewhat related to :
Display multiple values of a column in one row (SQL Oracle)
However, I could not achieve desired results. Following is my Problem Statement;
I have a SQL Query ;
SELECT initiator_msisdn, trx_type || '/' || SUM(trx_amt/100) || '/' || SUM(merchant_comm_amt/100) agent_data
FROM LBI_DM_MK.T_M_INTERNAL_AUDIT_D
WHERE DATA_DATE = '20180401'
AND trx_status ='Completed'
GROUP BY initiator_msisdn, trx_type
;
That returns these rows;
The SQL That brings this data is ;
But, I want following result.
Please help to sort out this issue;
You could use LISTAGG:
WITH cte AS (
SELECT initiator_msisdn,
trx_type || '/' || SUM(trx_amt/100) || '/' ||
SUM(merchant_comm_amt/100) agent_data
FROM LBI_DM_MK.T_M_INTERNAL_AUDIT_D
WHERE DATA_DATE = '20180401'
AND trx_status ='Completed'
GROUP BY initiator_msisdn, trx_type
)
SELECT initiator_msisdn,
LISTAGG(agent_data, '|') WITHIN GROUP (ORDER BY agent_data) AS agent_data
FROM cte
GROUP BY initiator_msisdn;

How to speed up this oracle select query?

I have following sql query in code, which is makes query go slow:
SELECT a.*,
(SELECT CASE
WHEN (score IS NOT NULL OR comments IS NOT NULL)
THEN
' ( score : ' || TO_CHAR (SCORE) || ' )'
ELSE
' ( hələ )'
END
FROM t_lecture_task_present b
WHERE b.t_idx = a.t_idx AND B.STUDENT_ID = '{$member_code}')
AS task_score
FROM t_lecture_task a
WHERE a.lec_open_idx = '24422'
ORDER BY s_date ASC, t_idx ASC
(16 seconds)
If I try query without
(SELECT CASE
WHEN (score IS NOT NULL OR comments IS NOT NULL)
THEN
' ( score : ' || TO_CHAR (SCORE) || ' )'
ELSE
' ( hələ )'
END
FROM t_lecture_task_present b
WHERE b.t_idx = a.t_idx AND B.STUDENT_ID = '{$member_code}')
as task_score
it works faster.
So, I tried removing or comments is not null, and it works got 2 seconds faster.
You can't compare the performance of queries that produce different results :)
Depending on data distribution in your tables, you would likely benefit from these indexes:
t_lecture_task(lec_open_idx)
t_lecture_task_present(t_idx, student_id)
Try to re-write your query to use joins instead of scalar sub queries (select as a column). Not only are they more awkward to read, they are more difficult to optimize.
select a.*
,case when score is not null
or comments is not null then ' ( score : ' || to_char (score) || ' )'
else ' ( hələ )'
end as task_score
from t_lecture_task a
left join t_lecture_task_present b on(
b.t_idx = a.t_idx
and b.student_id = '{$member_code}')
)
where a.lec_open_idx = '24422';

Oracle how do I update a table with data from another table, using a join on multiple tables?

I have a bunch of tables that I need to link together with the goal of updating the name and address in the ub_gl_movement Table (relevant columns listed).
|ub_gl_movement|
:-------------------------------------------------------------------------------------------------:
|UBGL_UBCT_CONTRACT_ID|UBGL_UBIN_INVESTMENT_ID|UBGL_PAYEE_NAME|ADDR_1 |ADDR_2|ADDR_3|SUBURB |
:-------------------------------------------------------------------------------------------------:
|194875 |000000Z0000480 |John Smith |123 Some St|(null)|(null)|Somewhere|
The zz_person table is as follows
|zz_person|
:-------------------------------------------:
|ZZPD_PERSON_ID|ZZPD_FIRST_NAME|ZZPD_SURNAME|
:-------------------------------------------:
|21916908 |Bill |Jones |
The Address table is as follows
|ADDRESS|
:-----------------------------------------------------------:
|ZZAD_ZZPD_PERSON_ID|ZZAD_LINE_1 |ZZAD_LINE_2|ZZAD_LINE_3|
:-----------------------------------------------------------:
|21916908 |456 Main Street|(null) |(null) |
There's no way to link these tables as is, so I tried to link via another table called zz_investment_person using the INVESTMENT_ID and PERSON_ID.
EDIT: Adding DESC UB_INVESTMENT
DESC UTB.UB_INVESTMENT
Name Null Type
-------------------------- -------- ------------
UBIN_INVESTMENT_ID NOT NULL VARCHAR2(14)
UBIN_DATE_FROM NOT NULL DATE
UBIN_DATE_TO NOT NULL DATE
UBIN_USER_LAST_UPD NOT NULL VARCHAR2(8)
UBIN_DATE_LAST_UPD NOT NULL DATE
UBIN_UBTC_COUNTRY_CODE VARCHAR2(8)
UBIN_REF_TAX_INVEST_TYPE VARCHAR2(8)
UBIN_BAD_TAX_EXEMPTION_YN VARCHAR2(1)
UBIN_WITH_TAX_EXEMPTION_YN VARCHAR2(1)
UBIN_TFN_TAX_EXEMPTION_YN VARCHAR2(1)
UBIN_EXTERNAL_REF VARCHAR2(40)
UBIN_REF_EXTRACT_MAIL VARCHAR2(8)
UBIN_VESTING_EXIST_YN VARCHAR2(1)
UBIN_REF_TAX_LEVEL VARCHAR2(8)
UBIN_UBML_MARGIN_LENDER_ID VARCHAR2(10)
UBIN_REF_BUSINESS_TYPE VARCHAR2(8)
UBIN_REF_BUSINESS_DIVISION VARCHAR2(8)
UBIN_REF_SOURCE VARCHAR2(8)
UBIN_CUSTOMER_REF_NUMBER VARCHAR2(18)
|zz_investment_person|
:--------------------------------------:
|ZZIP_INVESTMENT_ID|ZZIP_ZZPD_PERSON_ID|
:--------------------------------------:
|000000Z0000480 |21916908 |
DESC UTB.ZZ_INVESTMENT_PERSON
Name Null Type
------------------------ -------- ------------
ZZIP_INVESTMENT_ID NOT NULL VARCHAR2(14)
ZZIP_ZZPD_PERSON_ID NOT NULL NUMBER(8)
ZZIP_REF_PERSON_RELN NOT NULL VARCHAR2(8)
ZZIP_DATE_FROM NOT NULL DATE
ZZIP_DATE_TO NOT NULL DATE
ZZIP_USER_LAST_UPD NOT NULL VARCHAR2(8)
ZZIP_DATE_LAST_UPD NOT NULL DATE
ZZIP_VEST_AGE NUMBER(2)
ZZIP_DATE_VEST_EFFECTIVE DATE
ZZIP_DATE_VEST_PROCESSED DATE
I need to update the ub_gl_movement table so that the UBGL_PAYEE_NAME is set to Bill Jones, with an address of 456 Main Street. My query is
UPDATE
(
SELECT G.UBGL_PAYEE_NAME PAYEE_NAME,
P.ZZPD_FIRST_NAME F_NAME,
P.ZZPD_SURNAME L_NAME
FROM UTB.UB_GL_MOVEMENT G
JOIN UTB.UB_INVESTMENT I
ON G.UBGL_UBIN_INVESTMENT_ID = I.UBIN_INVESTMENT_ID
JOIN UTB.ZZ_INVESTMENT_PERSON IP
ON IP.ZZIP_INVESTMENT_ID = I.UBIN_INVESTMENT_ID
JOIN UTB.ZZ_PERSON P
ON P.ZZPD_PERSON_ID = IP.ZZIP_ZZPD_PERSON_ID
WHERE G.UBGL_PAYEE_NAME IS NOT NULL
)
SET PAYEE_NAME = F_NAME || ' ' || L_NAME;
However I get the error
SQL Error: ORA-01779: cannot modify a column which maps to a non key-preserved table
01779. 00000 - "cannot modify a column which maps to a non key-preserved table"
*Cause: An attempt was made to insert or update columns of a join view which
map to a non-key-preserved table.
*Action: Modify the underlying base tables directly.
and if I run this query
UPDATE UTB.UB_GL_MOVEMENT G
SET G.UBGL_PAYEE_NAME =
(SELECT CASE WHEN (UPPER(ZZPD_REF_TITLE) = 'EST OF')
THEN SUBSTR(ZZPD_REF_TITLE, 1, 3) || ' ' || ZZPD_FIRST_NAME || ' ' || ZZPD_SURNAME
WHEN (ZZPD_REF_TITLE IS NOT NULL AND ZZPD_FIRST_NAME IS NOT NULL AND ZZPD_SURNAME IS NOT NULL )
THEN ZZPD_REF_TITLE || ' ' || ZZPD_FIRST_NAME || ' ' || ZZPD_SURNAME
WHEN (ZZPD_REF_TITLE IS NULL AND ZZPD_FIRST_NAME IS NOT NULL AND ZZPD_SURNAME IS NOT NULL)
THEN ZZPD_FIRST_NAME || ' ' || ZZPD_SURNAME
ELSE 'SIR / MADAM' END
FROM UTB.ZZ_PERSON P
JOIN UTB.ZZ_INVESTMENT_PERSON IP
ON P.ZZPD_PERSON_ID = IP.ZZIP_ZZPD_PERSON_ID
JOIN UTB.UB_INVESTMENT I
ON G.UBGL_UBIN_INVESTMENT_ID = I.UBIN_INVESTMENT_ID
AND ROWNUM = 1
)
WHERE G.UBGL_PAYEE_NAME IS NOT NULL;
I get a different error
Error at Command Line:14 Column:21
Error report:
SQL Error: ORA-00904: "G"."UBGL_UBIN_INVESTMENT_ID": invalid identifier
00904. 00000 - "%s: invalid identifier"
I haven't updated the Address table in this query. I figured I'll just start with the names first.
Any input would be greatly appreciated :)
EDIT 2 - I have changed the second update query to
UPDATE UTB.UB_GL_MOVEMENT G
SET G.UBGL_PAYEE_NAME = (SELECT CASE WHEN (UPPER(ZZPD_REF_TITLE) = 'EST OF')
THEN SUBSTR(ZZPD_REF_TITLE, 1, 3) || ' ' || ZZPD_FIRST_NAME || ' ' || ZZPD_SURNAME
WHEN (ZZPD_REF_TITLE IS NOT NULL AND ZZPD_FIRST_NAME IS NOT NULL AND ZZPD_SURNAME IS NOT NULL )
THEN ZZPD_REF_TITLE || ' ' || ZZPD_FIRST_NAME || ' ' || ZZPD_SURNAME
WHEN (ZZPD_REF_TITLE IS NULL AND ZZPD_FIRST_NAME IS NOT NULL AND ZZPD_SURNAME IS NOT NULL)
THEN ZZPD_FIRST_NAME || ' ' || ZZPD_SURNAME
ELSE 'SIR / MADAM' END
FROM UTB.ZZ_PERSON P
JOIN UTB.ZZ_INVESTMENT_PERSON IP ON P.ZZPD_PERSON_ID = IP.ZZIP_ZZPD_PERSON_ID
JOIN UTB.UB_INVESTMENT I ON I.UBIN_INVESTMENT_ID = IP.ZZIP_INVESTMENT_ID
JOIN UTB.UB_GL_MOVEMENT GMT ON GMT.UBGL_UBIN_INVESTMENT_ID = I.UBIN_INVESTMENT_ID
WHERE ROWNUM = 1
)
WHERE G.UBGL_PAYEE_NAME IS NOT NULL;
which does execute, but all PAYEE_NAMEs are the same, so it seems it has taken the first row from the ZZ_PERSON table and used that for all rows, instead of searching the table for the relevant ID / Name combination. If I remove the rownum=1, I get an error
SQL Error: ORA-01427: single-row subquery returns more than one row
01427. 00000 - "single-row subquery returns more than one row"

Resources