Concat subquery with other columns - sql

I have a query that returns many columns concated with : ,
SELECT DECODE(ship_ps.STATUS, 'A', 'Y', 'N') AS isactive_ship
,ship_ps.party_site_id
,ship_ps.party_site_number AS site_number
,ship_ps.col1 || ship_ps.col 2
from ...
where ....
and i have a seprate query
(SELECT hp.party_name
FROM apps.hz_cust_accounts hca,apps.hz_parties hp
WHERE 1=1
AND hp.party_id=hca.party_id
AND hca.status='A'
AND hca.cust_account_id=:p_sold_to_org_id6)
i want to concat the result of it with ship_ps.col1 || ship_ps.col 2 || THE_QUERY
How to achieve that

Did you try to run the SQL and got an error?:
SQL> select dummy||' '||(select 1 from dual) from dual;
DUMMY||''||(SELECT1FROMDUAL)
------------------------------------------
X 1

Related

Replacing and removing leading characters

I have this query
Select Distinct EMPLOYEE_ID from TABLE
and this returns bunch of EMPLOYEE ID's with leading zero's if the person's ID starts with 000 then it should be an 'e' and if it's 00 then it should be a 'u'
so for example if I have
0041258 this should show in the result as u41258 and if I have
00041258 then this should show as e41258
Is there a way to trim and replace in more efficient way that using substr and Case statement? and if no can you please show me how to use the substr and the Case statement in this case
Well, you can use case:
select (case when employee_id like '000%' then 'e' || substr(employee_id, 4)
when employee_id like '00%' then 'u' || substr(employee_id, 3)
else employee_id
end)
I doubt there is a much more efficient method than this.
Option that uses nested regular expressions:
SQL> with test (id) as
2 (select '0041258' from dual union
3 select '00041258' from dual
4 )
5 select id,
6 regexp_replace(regexp_replace(id, '^000', 'e'), '^00', 'u') result
7 from test;
ID RESULT
-------- --------------------
00041258 e41258
0041258 u41258
SQL>
Assuming you need to write an update statement (to permanently change the id's):
update <table>
set employee_id = case when employee_id like '000%'
then 'e' || substr(employee_id, 4)
else 'u' || substr(employee_id, 3) end
where employee_id like '00%'
;

Oracle XE, count and display different combinations of rows based on one column

need help with a complicated query. This is an extract from my table:
USERID SERVICE
1 A
1 B
2 A
3 A
3 B
4 A
4 C
5 A
6 A
7 A
7 B
Ok, I would like the query to return and display all possible combinations that exist in my table with their respective counts based on the SERVICE column. For example first user has A and B service, this is one combination which occurred once. Next user has only service A, this is one more combination which occurred once. Third user has service A and B, this has happened once already and the count for this combination is 2 now, etc. So my output based on this particular input would be a table like this:
A AB AC ABC B BC
3 3 1 0 0 0
So to clarify a bit more, if there are 3 services, then there is 3! possible combinations; 3x2x1=6 and they are A, B, C, AB, AC, BC and ABC. And my table should contain count of users which have these combination of services assigned to them.
I have tried building a matrix using this query and then getting all counts using the CUBE function:
select service_A, service_B, service_C from
(select USERID,
max(case when SERVICE =A then 1 else null end) service_A,
max(case when SERVICE =B then 1 else null end) service_B,
max(case when SERVICE =C then 1 else null end) service_C
from SOME_TABLE)
group by CUBE(service_A, service_B,service_C);
But I don't get the count of all combinations. I need only combinations which happened, so counts 0 are not necessary but it is ok to display them. Thanks.
Don't output it as dynamic columns (it is difficult to do without using PL/SQL and dynamic SQL) but output it as rows instead (if you have a front-end then it can usually translate rows to columns much easier than oracle can):
Oracle Setup:
CREATE TABLE some_table ( USERID, SERVICE ) AS
SELECT 1, 'A' FROM DUAL UNION ALL
SELECT 1, 'B' FROM DUAL UNION ALL
SELECT 2, 'A' FROM DUAL UNION ALL
SELECT 3, 'A' FROM DUAL UNION ALL
SELECT 3, 'B' FROM DUAL UNION ALL
SELECT 4, 'A' FROM DUAL UNION ALL
SELECT 4, 'C' FROM DUAL UNION ALL
SELECT 5, 'A' FROM DUAL UNION ALL
SELECT 6, 'A' FROM DUAL UNION ALL
SELECT 7, 'A' FROM DUAL UNION ALL
SELECT 7, 'B' FROM DUAL;
Query:
SELECT service,
COUNT( userid ) AS num_users
FROM (
SELECT userid,
LISTAGG( service ) WITHIN GROUP ( ORDER BY service ) AS service
FROM some_table
GROUP BY userid
)
GROUP BY service;
Output:
SERVICE NUM_USERS
------- ----------
AC 1
A 3
AB 3
PL/SQL for dynamic columns:
VARIABLE cur REFCURSOR;
DECLARE
TYPE string_table IS TABLE OF VARCHAR2(4000);
TYPE int_table IS TABLE OF INT;
t_services string_table;
t_counts int_table;
p_sql CLOB;
BEGIN
SELECT service,
COUNT( userid ) AS num_users
BULK COLLECT INTO t_services, t_counts
FROM (
SELECT userid,
CAST( LISTAGG( service ) WITHIN GROUP ( ORDER BY service ) AS VARCHAR2(2) ) AS service
FROM some_table
GROUP BY userid
)
GROUP BY service;
p_sql := EMPTY_CLOB() || 'SELECT ';
p_sql := p_sql || t_counts(1) || ' AS "' || t_services(1) || '"';
FOR i IN 2 .. t_services.COUNT LOOP
p_sql := p_sql || ', ' || t_counts(i) || ' AS "' || t_services(i) || '"';
END LOOP;
p_sql := p_sql || ' FROM DUAL';
OPEN :cur FOR p_sql;
END;
/
PRINT cur;
Output:
AC A AB
--- --- ---
1 3 3

How to convert String in SQL (ORACLE)

I try to select from table_1 where ITEM_FIELD_A is not in ITEM_FIELD_B. The Item_FIELD_B value are look as below. I was expecting no COVER_TAPE & SHIPPING_REELS will be selected. But unfortunately, it's not working.
The sql I used to select the table
select * from table_1 where MST.ITEM_FIELD_A not in ITEM_FIELD_B
Question:
In Oracle, is there any function to decode the string. so that the above select statement will not return COVER_TAPE and SHIPPING_REELS??
The IN operator would be used when you wish to compare (or negate) one item in a list such as
WHERE ITEM_FIELD_A NOT IN ('COVER_TAPE', 'SHIPPING_REELS', '')
What you want is the LIKE operator:
WHERE ITEM_FIELD_B NOT LIKE '%' || ITEM_FIELD_A || '%'
Apologies if I got the wildcard wrong, been a while since I last touched Oracle.
Check out below Query:
WITH TAB1 AS
( SELECT 'COVER_TAPE' ITEM_A FROM DUAL
UNION
SELECT 'CARRIER_TAPE' ITEM_A FROM DUAL
UNION
SELECT 'SHIPPING_REELS' ITEM_A FROM DUAL
),
TAB2 AS
(
SELECT 'COVER_TAPE,SHIPPING_REELS' ITEM_B FROM DUAL
)
SELECT ITEM_A, ITEM_B FROM TAB1, TAB2 WHERE INSTR(ITEM_B, ITEM_A) <=0
INSTR will return >0 if same sequence of characters is available.
SQL> with t(x , y) as
2 (
3 select 'A', q'[('A','B','C')]' from dual union all
4 select 'R', q'[('A','B','C','D')]' from dual union all
5 select 'C', q'[('A', 'C','D')]' from dual
6 )
7 select x, y
8 from t where y not like q'[%']'||x||q'['%]'
9 /
X Y
---------- --------------------------------------------------
R ('A','B','C','D')

SQL Query to show string before a dash

I would like to execute a query that will only show all the string before dash in the particular field.
For example:
Original data: AB-123
After query: AB
You can use substr:
SQL> WITH DATA AS (SELECT 'AB-123' txt FROM dual)
2 SELECT substr(txt, 1, instr(txt, '-') - 1)
3 FROM DATA;
SUBSTR(TXT,1,INSTR(TXT,'-')-1)
------------------------------
AB
or regexp_substr (10g+):
SQL> WITH DATA AS (SELECT 'AB-123' txt FROM dual)
2 SELECT regexp_substr(txt, '^[^-]*')
3 FROM DATA;
REGEXP_SUBSTR(TXT,'^[^-]*')
---------------------------
AB
You can use regexp_replace.
For example
WITH DATA AS (
SELECT 'AB-123' as text FROM dual
UNION ALL
SELECT 'ABC123' as text FROM dual
)
SELECT
regexp_replace(d.text, '-.*$', '') as result
FROM DATA d;
will lead to
WITH DATA AS (
2 SELECT 'AB-123' as text FROM dual
3 UNION ALL
4 SELECT 'ABC123' as text FROM dual
5 )
6 SELECT
7 regexp_replace(d.text, '-.*$', '') as result
8 FROM DATA d;
RESULT
------------------------------------------------------
AB
ABC123
I found this simple
SELECT distinct
regexp_replace(d.pyid, '-.*$', '') as result
FROM schema.table d;
pyID column contains ABC-123, DEF-3454
SQL Result:
ABC
DEF

Concatenate results from a SQL query in Oracle

I have data like this in a table
NAME PRICE
A 2
B 3
C 5
D 9
E 5
I want to display all the values in one row; for instance:
A,2|B,3|C,5|D,9|E,5|
How would I go about making a query that will give me a string like this in Oracle? I don't need it to be programmed into something; I just want a way to get that line to appear in the results so I can copy it over and paste it in a word document.
My Oracle version is 10.2.0.5.
-- Oracle 10g --
SELECT deptno, WM_CONCAT(ename) AS employees
FROM scott.emp
GROUP BY deptno;
Output:
10 CLARK,MILLER,KING
20 SMITH,FORD,ADAMS,SCOTT,JONES
30 ALLEN,JAMES,TURNER,BLAKE,MARTIN,WARD
I know this is a little late but try this:
SELECT LISTAGG(CONCAT(CONCAT(NAME,','),PRICE),'|') WITHIN GROUP (ORDER BY NAME) AS CONCATDATA
FROM your_table
Usually when I need something like that quickly and I want to stay on SQL without using PL/SQL, I use something similar to the hack below:
select sys_connect_by_path(col, ', ') as concat
from
(
select 'E' as col, 1 as seq from dual
union
select 'F', 2 from dual
union
select 'G', 3 from dual
)
where seq = 3
start with seq = 1
connect by prior seq+1 = seq
It's a hierarchical query which uses the "sys_connect_by_path" special function, which is designed to get the "path" from a parent to a child.
What we are doing is simulating that the record with seq=1 is the parent of the record with seq=2 and so fourth, and then getting the full path of the last child (in this case, record with seq = 3), which will effectively be a concatenation of all the "col" columns
Adapted to your case:
select sys_connect_by_path(to_clob(col), '|') as concat
from
(
select name || ',' || price as col, rownum as seq, max(rownum) over (partition by 1) as max_seq
from
(
/* Simulating your table */
select 'A' as name, 2 as price from dual
union
select 'B' as name, 3 as price from dual
union
select 'C' as name, 5 as price from dual
union
select 'D' as name, 9 as price from dual
union
select 'E' as name, 5 as price from dual
)
)
where seq = max_seq
start with seq = 1
connect by prior seq+1 = seq
Result is: |A,2|B,3|C,5|D,9|E,5
As you're in Oracle 10g you can't use the excellent listagg(). However, there are numerous other string aggregation techniques.
There's no particular need for all the complicated stuff. Assuming the following table
create table a ( NAME varchar2(1), PRICE number);
insert all
into a values ('A', 2)
into a values ('B', 3)
into a values ('C', 5)
into a values ('D', 9)
into a values ('E', 5)
select * from dual
The unsupported function wm_concat should be sufficient:
select replace(replace(wm_concat (name || '#' || price), ',', '|'), '#', ',')
from a;
REPLACE(REPLACE(WM_CONCAT(NAME||'#'||PRICE),',','|'),'#',',')
--------------------------------------------------------------------------------
A,2|B,3|C,5|D,9|E,5
But, you could also alter Tom Kyte's stragg, also in the above link, to do it without the replace functions.
Here is another approach, using model clause:
-- sample of data from your question
with t1(NAME1, PRICE) as(
select 'A', 2 from dual union all
select 'B', 3 from dual union all
select 'C', 5 from dual union all
select 'D', 9 from dual union all
select 'E', 5 from dual
) -- the query
select Res
from (select name1
, price
, rn
, res
from t1
model
dimension by (row_number() over(order by name1) rn)
measures (name1, price, cast(null as varchar2(101)) as res)
(res[rn] order by rn desc = name1[cv()] || ',' || price[cv()] || '|' || res[cv() + 1])
)
where rn = 1
Result:
RES
----------------------
A,2|B,3|C,5|D,9|E,5|
SQLFiddle Example
Something like the following, which is grossly inefficient and untested.
create function foo returning varchar2 as
(
declare bar varchar2(8000) --arbitrary number
CURSOR cur IS
SELECT name,price
from my_table
LOOP
FETCH cur INTO r;
EXIT WHEN cur%NOTFOUND;
bar:= r.name|| ',' ||r.price || '|'
END LOOP;
dbms_output.put_line(bar);
return bar
)
Managed to get till here using xmlagg: using oracle 11G from sql fiddle.
Data Table:
COL1 COL2 COL3
1 0 0
1 1 1
2 0 0
3 0 0
3 1 0
SELECT
RTRIM(REPLACE(REPLACE(
XMLAgg(XMLElement("x", col1,',', col2, col3)
ORDER BY col1), '<x>'), '</x>', '|')) AS COLS
FROM ab
;
Results:
COLS
1,00| 3,00| 2,00| 1,11| 3,10|
* SQLFIDDLE DEMO
Reference to read on XMLAGG