I have a table in oracle and I want to convert it in matrix form
table 1 : I have two type of users with corresponding weights
User_name M_User Total
user 1 user 2 7
user 1 user 3 19
user 1 user 7 5
user 3 user 2 1
user 2 user 7 1
The final result should be something like this: user 1 - > user two has weight 7 so this value appears in that cell and so on
user 1 user 2 user 3 user 7
user 1 0 7 19 5
user 3 0 1 0 0
user 2 0 0 0 1
user 7 0 0 0 0
After a bit of research I found Pivot function and used it.
SELECT *
FROM (SELECT USER_NAME, M_USER, TOTAL
FROM TEST)
PIVOT (MAX(TOTAL) FOR (M_USER) IN ('user 2' AS User2, 'user 3' AS User3 , 'user7' AS User7))
First problem is that it is showing null values for 'User 7' and it shouldn't, second problem is that I have lot of data in my file (107k records,including duplicates) for limited data like above I can use 'user 2' AS User2, 'user 3' AS User3 , 'user7' AS User7 after IN command in case of such big data how can i write this line? of course I can't write 100k records after IN
UPDATE:
ran the commands in sql developer as "run script"
Error starting at line 2 in command:
EXEC :rc := getusers;
Error report:
ORA-06550: line 1, column 13:
PLS-00905: object SYSTEM.GETUSERS is invalid
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
06550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
rc
This may be helpful for you. I have used CASE WHEN THEN END blocks to achieve the PIVOT.
SELECT USERS.USER_NAME
, MAX(COALESCE(TEST.USER1, 0)) USER1
, MAX(COALESCE(TEST.USER2, 0)) USER2
, MAX(COALESCE(TEST.USER3, 0)) USER3
, MAX(COALESCE(TEST.USER7, 0)) USER7
FROM (
SELECT DISTINCT USER_NAME
FROM (
SELECT USER_NAME FROM TEST
UNION ALL
SELECT M_USER FROM TEST
)
) USERS
LEFT OUTER JOIN (
SELECT
USER_NAME
, M_USER
, CASE WHEN M_USER = 'user 1' THEN TOTAL ELSE 0 END AS USER1
, CASE WHEN M_USER = 'user 2' THEN TOTAL ELSE 0 END AS USER2
, CASE WHEN M_USER = 'user 3' THEN TOTAL ELSE 0 END AS USER3
, CASE WHEN M_USER = 'user 7' THEN TOTAL ELSE 0 END AS USER7
FROM TEST
) TEST ON USERS.USER_NAME = TEST.USER_NAME
GROUP BY USERS.USER_NAME
ORDER BY USERS.USER_NAME
UPDATE
I could not find a way write this in a single query. After some analysis i found this.
CREATE OR REPLACE FUNCTION GETUSERS RETURN SYS_REFCURSOR AS
QUERY VARCHAR2(32767);
RC SYS_REFCURSOR;
BEGIN
QUERY := 'SELECT USERS.USER_NAME ';
FOR TMP IN (SELECT DISTINCT UPPER(REPLACE(USER_NAME, ' ', '')) USER_NAME FROM (SELECT USER_NAME FROM TEST UNION ALL SELECT M_USER FROM TEST) ORDER BY USER_NAME)
LOOP
QUERY := QUERY || ' , MAX(COALESCE(TEST.' || TMP.USER_NAME || ' , 0)) ' || TMP.USER_NAME;
END LOOP;
QUERY := QUERY || ' FROM ( ';
QUERY := QUERY || ' SELECT DISTINCT USER_NAME ';
QUERY := QUERY || ' FROM ( ';
QUERY := QUERY || ' SELECT USER_NAME FROM TEST ';
QUERY := QUERY || ' UNION ALL ';
QUERY := QUERY || ' SELECT M_USER FROM TEST ';
QUERY := QUERY || ' ) ';
QUERY := QUERY || ' ) USERS ';
QUERY := QUERY || ' LEFT OUTER JOIN ( ';
QUERY := QUERY || ' SELECT USER_NAME';
FOR TMP IN (SELECT DISTINCT USER_NAME, REPLACE(USER_NAME, ' ', '') USER_COL_NM FROM (SELECT USER_NAME FROM TEST UNION ALL SELECT M_USER FROM TEST))
LOOP
QUERY := QUERY || ', CASE WHEN M_USER = ''' || TMP.USER_NAME
|| ''' THEN TOTAL ELSE 0 END AS ' || TMP.USER_COL_NM ;
END LOOP;
QUERY := QUERY || ' FROM TEST';
QUERY := QUERY || ' ) TEST ON USERS.USER_NAME = TEST.USER_NAME ';
QUERY := QUERY || 'GROUP BY USERS.USER_NAME ';
QUERY := QUERY || 'ORDER BY USERS.USER_NAME';
OPEN RC FOR QUERY;
RETURN RC;
END;
/
Created function which dynamically creates the SQL and returns SYS_REFCURSOR. This can be run in SQL*Plus or SQL Developer (with 'run as a script'),
VAR RC REFCURSOR;
EXEC :RC := GETUSERS;
PRINT RC
Related
Trying to update a table using stored proc. Getting error as
SQL Error [42601]: ERROR: query "SELECT 'update view.recon_dashboard
set dlv_count = (select count(*) from ' || $1 || ') where id='|| $2 , 'set alv_count = (select count(*) from ' || $3 || ') where id='|| $4 , CASE WHEN $5 is not null then 'set tgt_count = (select count(*) from ' || $6 || ') where id='|| $7 end" returned 3 columns
Where: PL/pgSQL function "sp_count_recon_refresh" line 7 at execute statement
1)I have a table recon_dashboard for which i loop through values of each column tgt,alv,dlv and query the db to fetch the count and update the recon_dashboard table. It is working when i update a single value in update statement like : execute 'update ca_adhoc_view.recon_dashboard set dlv_count = (select count(*) from ' || f.dlv || ') where id='|| f.id;
but it is throwing error when trying to updaate multiple columns in update statement.
create or replace procedure view.refresh_sp()
language plpgsql as
$$
declare
f record;
BEGIN
for f in select tgt,alv,dlv,id from view.recon_dashboard
loop
raise notice '% -#',f.dlv;
execute 'update view.recon_dashboard
set dlv_count = (select count(*) from ' || f.dlv || ') where id='|| f.id,
'set alv_count = (select count(*) from ' || f.alv || ') where id='|| f.id,
CASE
WHEN f.alv is not null then
'set tgt_count = (select count(*) from ' || f.tgt || ') where id='|| f.id
end;
end loop;
END;
$$;
How to take where clause conditions from table column in oracle plsql.
E.g. data in table
Condition
1.sourceSystemId = 'SN'
2.AND(coverageType='AD',amountType1='PREMIUM',premiumFrequency='REGULAR',yearOfPremium='1')
e.g query:
select * from xyz where rule='abc' and "sourceSystemId = 'SN'"
select * from xyz where rule='abc' AND(coverageType='AD',amountType1='PREMIUM',premiumFrequency='REGULAR',yearOfPremium='1')
Not entirely sure what you're asking here, but I would imagine that
select * from xyz where rule='abc' AND(coverageType='AD',amountType1='PREMIUM',premiumFrequency='REGULAR',yearOfPremium='1')
would become
select * from xyz
where rule='abc'
AND coverageType='AD'
and amountType1='PREMIUM'
and premiumFrequency='REGULAR'
and yearOfPremium='1'
I suppose you want something like :
DECLARE
l_query VARCHAR2(2000) := 'select * from xyz where rule=''abc''';
l_result xyz%ROWTYPE;
l_cursor SYS_REFCURSOR;
BEGIN
dbms_output.put_line(l_query);
FOR clause IN (SELECT condition
FROM conditions)
LOOP
l_query := l_query||' AND '||clause.condition;
END LOOP;
OPEN l_cursor FOR l_query;
LOOP
FETCH l_cursor INTO l_result;
EXIT WHEN l_cursor%NOTFOUND;
..
-- your processing
END LOOP;
CLOSE l_cursor;
END;
Here is example of SQL solution. I used justt first and last condition but you can get them all...
WITH
xyz As
(
Select 1 "ID", 'abc' "RULE", 'AD' "COVERAGETYPE", 'PREMIUM' "AMOUNTTYPE1", 'REGULAR' "PREMIUMFREQUENCY", '1' "YEAROFPREMIUM" From Dual
UNION
Select 2 "ID", 'abc' "RULE", 'BF' "COVERAGETYPE", 'ORDINARY' "AMOUNTTYPE1", 'EXTRA' "PREMIUMFREQUENCY", '2' "YEAROFPREMIUM" From Dual
UNION
Select 3 "ID", 'abc' "RULE", 'AD' "COVERAGETYPE", 'PREMIUM' "AMOUNTTYPE1", 'REGULAR' "PREMIUMFREQUENCY", '1' "YEAROFPREMIUM" From Dual
),
conditions As
(
SELECT UPPER('coverageType=AD,amountType1=PREMIUM,premiumFrequency=REGULAR,yearOfPremium=1') "CND" From Dual
)
SELECT
x.ID, x.RULE, x.COVERAGETYPE, x.AMOUNTTYPE1, x.PREMIUMFREQUENCY, x.YEAROFPREMIUM
FROM
xyz x
INNER JOIN
conditions c ON(1=1)
WHERE
x.RULE = 'abc' And
x.COVERAGETYPE = CASE WHEN InStr(c.CND || ',', 'COVERAGETYPE=') = 0 THEN x.COVERAGETYPE
ELSE SubStr(SubStr(c.CND || ',', InStr(c.CND || ',', 'COVERAGETYPE=') + Length('COVERAGETYPE=')), 1, InStr(SubStr(c.CND || ',', InStr(c.CND || ',', 'COVERAGETYPE=') + Length('COVERAGETYPE=') + 1), ',')) END And
x.YEAROFPREMIUM = CASE WHEN InStr(c.CND || ',', 'YEAROFPREMIUM=') = 0 THEN x.YEAROFPREMIUM
ELSE SubStr(SubStr(c.CND || ',', InStr(c.CND || ',', 'YEAROFPREMIUM=') + Length('YEAROFPREMIUM=')), 1, InStr(SubStr(c.CND || ',', InStr(c.CND || ',', 'YEAROFPREMIUM=') + Length('YEAROFPREMIUM=') + 1), ',')) END
Result:
ID RULE COVERAGETYPE AMOUNTTYPE1 PREMIUMFREQUENCY YEAROFPREMIUM
1 abc AD PREMIUM REGULAR 1
3 abc AD PREMIUM REGULAR 1
I have to update all the tables having column name like '%DIV%' with a value DD wherever it is MG , I have written the script for it , but I am not getting the idea of how to verify if columns of all the tables are updated to value DD after the activity is performed. I have written this query .
SELECT 'SELECT '||OWNER||'.'||TABLE_NAME||', '||COLUMN_NAME||' FROM '||OWNER||'.'||TABLE_NAME||' WHERE '||COLUMN_NAME||' = ''MG'' ;'
FROM RADHA.CHANGE_TABLE
WHERE VALID_FLAG='Y'
I was planning to make a table structure like
OWNER TABLE_NAME PREV_COUNT
The PREV_COUNT will hold the count of rows having Column Value as MG and after the activity is performed , I will verify with following query if the corresponding rows have been updated to DD .
SELECT 'SELECT '||OWNER||'.'||TABLE_NAME||', '||COLUMN_NAME||' FROM '||OWNER||'.'||TABLE_NAME||' WHERE '||COLUMN_NAME||' = ''DD'' ;' FROM RADHA.CHANGE_TABLE WHERE VALID_FLAG='Y'
And the output of this query would go into table
OWNER TABLE_NAME NEW_COUNT
But I am not able to get how to fetch records from the Select query as it is the string which is written inside the select query but I want the result set such that I can insert the records in my table mentioned above, please guide how to approach further
I don't have your tables, but - based on Scott's sample schema, here's a script which search through all its tables for a column named JOB (line #8) and checks how many of them have value that looks like (hint: like) CLERK in it (line #12).
See how it works, adjust it so that it works for you.
SQL> DECLARE
2 l_str VARCHAR2(500);
3 l_cnt NUMBER := 0;
4 BEGIN
5 FOR cur_r IN (SELECT u.table_name, u.column_name
6 FROM user_tab_columns u, user_tables t
7 WHERE u.table_name = t.table_name
8 AND u.column_name = 'JOB'
9 )
10 LOOP
11 l_str := 'SELECT COUNT(*) FROM ' || cur_r.table_name ||
12 ' WHERE ' || cur_r.column_name || ' like (''%CLERK%'')';
13
14 EXECUTE IMMEDIATE (l_str) INTO l_cnt;
15
16 IF l_cnt > 0 THEN
17 dbms_output.put_line(l_cnt ||' : ' || cur_r.table_name);
18 END IF;
19 END LOOP;
20 END;
21 /
4 : EMP --> there are 4 CLERKs in the EMP table
PL/SQL procedure successfully completed.
SQL>
I have the following script to count all line of every table for a specific owner. It works perfectly.
However, some tables have a specific column called 'OLD' and other don't...
My current script does not take into account if this column exists or not:
DECLARE
val NUMBER;
BEGIN
FOR I IN (SELECT table_name FROM all_tables where owner='myowner') LOOP
EXECUTE IMMEDIATE 'SELECT count(*) FROM myowner.' || i.table_name INTO val;
DBMS_OUTPUT.PUT_LINE(i.table_name || ';' || val );
END LOOP;
END;
So what I would like to add is something like:
if the OLD column exists, take it in account when OLD=0 (where OLD=0), if it does not exist keep doing the 'normal' count without taking this column into account.
Hope I've been clear enough ;)
Thanks a lot!
An example:
let's say I have 2 tables:
Table1 - columns A B C with the following data:
1 "test" "Steve"
2 "test2" "George"
Table2 - columns E F G OLD with the following data:
1 "test3" "Martin" 0
2 "test4" "Lucas" 0
3 "test5" "Marley" 0
4 "test6" "Bob" 55
The result should then be:
Table1;2 -> there was not the 'OLD' column so I made a simples count
which returned 2
Table2;3 -> there was the 'OLD' column so I made a count where OLD=0
and it returned then 3
Try:
DECLARE
val NUMBER;
BEGIN
FOR I IN (
select a.table_name, c.column_name
from all_tables a
left join all_tab_cols c
ON a.owner = c.owner and a.table_name = c.table_name and c.column_name = 'OLD'
where a.owner = 'MYOWNER'
)
LOOP
IF i.column_name IS NULL THEN
EXECUTE IMMEDIATE 'SELECT count(*) FROM MYOWNER.' || i.table_name INTO val;
ELSE
EXECUTE IMMEDIATE 'SELECT count(*) FROM MYOWNER.' || i.table_name
|| ' WHERE old = 0' INTO val;
END IF;
DBMS_OUTPUT.PUT_LINE(i.table_name || ';' || val );
END LOOP;
END;
I'm wondering if it possible to debug similar statements in an easy way.
When I save the 'select string' in a variable , it become 'long' and I would need to split it in more variables. I' presenting the very simplified sample:
OPEN o_recordset FOR
'SELECT distinct
a, b, c
FROM t1,t2
WHERE'
|| CASE
WHEN i_use_ctr_id = 1 then ' a = b'
END
|| ' ORDER BY 1 ASC , DECODE('''||i_sort_order||''',null, '''', ''a'', '' NULLS LAST '', ''b'' ,'',2 ASC NULLS LAST'')'
;
I wish to see the select like this (i_use_ctr_id = 1, i_sort_order = a)
SELECT distinct
a, b, c
FROM t1,t2
WHERE a = b
END
ORDER BY 1 ASC , DECODE('a',null, '''', ''a'', '' NULLS LAST '', ''b'' ,'',2 ASC NULLS LAST'')'
;
Use a debug procedure that either writes to a file or inserts in a table (with an autonomous transaction).
For instance:
CREATE TABLE debug_t (ts timestamp default systimestamp, data VARCHAR2(4000));
CREATE OR REPLACE PROCEDURE debug_p (p VARCHAR2) IS
PRAGMA autonomous_transaction;
BEGIN
-- you should split p if length is > 4000
INSERT INTO debug_t (data) VALUES (p);
COMMIT;
END;
/
Then you can debug values by inserting a single line of code:
SQL> DECLARE
2 l_sql VARCHAR2(4000);
3 i_use_ctr_id NUMBER;
4 i_sort_order NUMBER;
5 BEGIN
6 l_sql := 'SELECT distinct
7 a, b, c
8 FROM t1,t2
9
10 WHERE'
11 || CASE
12 WHEN i_use_ctr_id = 1 then ' a = b'
13 END
14 || ' ORDER BY 1 ASC , DECODE('''||i_sort_order
15 ||''',null, '''', ''a'', '' NULLS LAST '', ''b'' ,'',2 ASC NULLS LAST'')'
16 ;
17 debug_p(l_sql); -- debug before opening cursor
18 END;
19 /
PL/SQL procedure successfully completed
SQL> select * from debug_t;
TS DATA
----------------- --------------------------------------------------------------------------------
11/09/13 11:52:30 SELECT distinct
a, b, c
FROM t1,t2
WHERE ORDER BY 1 ASC , DECODE('',null, '', 'a', ' NULLS LAST ', 'b' ,',2 ASC