append string to varchar2 field based on the value of another field - oracle

Table 1 has
col1 varchar2(85)
col2 date
There is plenty of character space available in col1. If col2 value is previous to 2001, need to append to whatever value is in col1 the value OLD to the front end of whatever value may be in col1.
In some cases, col1 will be NULL. At most it will have values less than 40 characters in length.
Is there a SQL statement that can accomplish this without getting into PL/SQL?
Appreciate any and all help.

Something like the following should work:
select case when to_char(COL2, 'yyyy') < 2001
then 'OLD ' || nvl(COL1, '')
else COL1 end case
from TAB1
For example:
insert into TAB1 values ('testpost2001', trunc(sysdate));
insert into TAB1 values ('testpre2001', '01/Jul/2000');
insert into TAB1 values (null, trunc(sysdate));
insert into TAB1 values (null, '01/Jul/2000');
select COL1, COL2,
case when to_char(COL2, 'yyyy') < 2001
then 'OLD ' || nvl(COL1, '')
else COL1 end case
from TAB1;
Returns:
COL1 COL2 CASE
testpost2001 15/12/2011 testpost2001
testpre2001 1/07/2000 OLD testpre2001
15/12/2011
1/07/2000 OLD

This will also work in only one SQL statement as it will update all rows having value less than 2001...
update TAB1 set col1='OLD ' || nvl(COL1, '') where to_char(COL2, 'yyyy') < 2001;

Related

Oracle Unique Key - get PK or RowID

Is it possible to catch the master key or the record rowID that triggered the duplication exception?
table1 have PK: col1 and Unique1: col2
e.g.
begin
insert into table1(col1, col2, col3)
values (1, 2, 3);
exception
when dup_val_on_index then
--- here, can you somehow indicate either PK or ROWID of the record that generated the exception of uniqueness?
e.g.
update table1 set
col3 = 100
where rowid = "GETROWID" or col1 = "GETPK";
end;
In "normal" code you don't use constants to insert values; you'd normally have the value in a variable so your code would look more like:
DECLARE
strVar1 TABLE1%TYPE;
nVar2 NUMBER;
nVar3 NUMBER;
begin
SELECT s1, n2, n3
INTO strVar1, nVar2, nVar3
FROM SOME_TABLE;
insert into table1(col1, col2, col3)
values (strVar1, nVar2, nVar3);
exception
when dup_val_on_index then
update table1
set col3 = 100
where col1 = strVar1;
end;
But a better idea is to avoid the exception in the first place by using a MERGE statement:
MERGE INTO TABLE1 t1
USING (SELECT S1, N2, N3
FROM SOME_TABLE) s
ON (t1.COL1 = s.S1)
WHEN MATCHED THEN
UPDATE SET COL3 = 100
WHEN NOT MATCHED THEN
INSERT (COL1, COL2, COl3)
VALUES (s.S1, s.N2, s.N3);
The LOG ERRORS INTO could help here. You have to prepare an error table before using this clause:
begin
dbms_errlog.create_error_log('table1');
end;
That will create err$_table1 table. Now run the insert using additional feature
insert into table1(col1, col2, col3) values (1, 2, 3)
log errors into err$_table1 ('some_tag_to_look_for') reject limit unlimited;
Querying the err$_table1 with
select * from err$_table1;
won't give you the rowid (it gets filled for updates and deletes only) but you'll get the exact column values causing the error and the index violated.
If that is not enough you can find the indexed columns here
select * from all_ind_columns where owner='OWNER_NAME_from_error_table' and index_name = 'Name_from_err_table';
Thus you'll know which column(s) in the destination table already has the value you are trying to insert --> this is how you'll find the rowid or whatever you need

Insert into table by selecting all from another and when a statement is true change the value in PL/SQL

So what I would like to do is take the values of a table (all of them) insert
them into a new one and when it meets any value that article identifier(sa.art_ident) replace it with the word bighead and the sa.art_moddate be replaced with the current system time. When ever I try to run it it tells me missing right parenthesis... Please help
PROCEDURE p_copier_one IS
BEGIN
INSERT INTO article_new
(
SELECT * FROM article_old sa
CASE
WHEN sa.art_ident='%' THEN
sa.art_ident = 'Bighead'
END
CASE
WHEN sa.art_moddate='%' THEN
sa.art_moddate = to_date(
'02/04/2012'
,'DD/MM/YYYY')
,trunc(SYSDATE)
END
);
END p_copier_one;
Welcome to SO. You would need to do something like shown below. Read my comments inline.
CREATE OR REPLACE PROCEDURE p_copier_one
IS
BEGIN
---List down all your columns here. Although its option to mention your table column but its good practise.
INSERT INTO article_new (
col1,
col2,
col3,
col4,
col5
)
SELECT col1,
col2,
--Put your case here
CASE
WHEN sa.art_ident = '%' THEN 'Bighead'
END col3,
CASE
WHEN sa.art_moddate = '%' THEN TO_DATE('02/04/2012','DD/MM/YYYY')
END col4,
trunc(SYSDATE) col5
FROM article_old sa;
COMMIT;
END;

How to retrieve only columns which have at least one not null value in any row in Oracle

I have table structure and data as below
https://ibb.co/mkGp67
I want a SQL Query to retrieve data only for those columns which have at least one not null value in it, in above case i want data comes out to be
https://ibb.co/mz9967
i.e. i don't need column Col2, Col5 and Col6, also which column having all null value is not fixed.
Please let me know the SQL query which retreive data that having only those column which having not null value with data as above.
As far, as I know, you will not be able to achieve this with an SQL query. One of the strong assumptions of SELECT statements is that the list of returned columns is static - defined in the query, not by the data. Even for PIVOT queries (available - as far, as I know - since Oracle 11), the list of columns is defined in the query, by providing a list of values to be converted to columns has to be explicitly given.
What you are looking for is some kind of code, dynamically generating the query. This can be PL/SQL, returning cursor references or any application code.
Edit:
What you could do with a query, is to have a clear information on which columns do contain nulls, which do not, etc. It could look something like this:
SELECT CASE
WHEN COUNT(*) = 0 THEN 'no rows'
WHEN COUNT(Col1) = 0 THEN 'all NULLs'
WHEN COUNT(Col1) = COUNT(*) THEN 'no NULLs'
ELSE 'some NULLs'
END Col1NullStatus,
CASE
WHEN COUNT(*) = 0 THEN 'no rows'
WHEN COUNT(Col2) = 0 THEN 'all NULLs'
WHEN COUNT(Col2) = COUNT(*) THEN 'no NULLs'
ELSE 'some NULLs'
END Col2NullStatus,
CASE
WHEN COUNT(*) = 0 THEN 'no rows'
WHEN COUNT(Col3) = 0 THEN 'all NULLs'
WHEN COUNT(Col3) = COUNT(*) THEN 'no NULLs'
ELSE 'some NULLs'
END Col3NullStatus,
CASE
WHEN COUNT(*) = 0 THEN 'no rows'
WHEN COUNT(Col4) = 0 THEN 'all NULLs'
WHEN COUNT(Col4) = COUNT(*) THEN 'no NULLs'
ELSE 'some NULLs'
END Col4NullStatus,
CASE
WHEN COUNT(*) = 0 THEN 'no rows'
WHEN COUNT(Col5) = 0 THEN 'all NULLs'
WHEN COUNT(Col5) = COUNT(*) THEN 'no NULLs'
ELSE 'some NULLs'
END Col5NullStatus,
CASE
WHEN COUNT(*) = 0 THEN 'no rows'
WHEN COUNT(Col6) = 0 THEN 'all NULLs'
WHEN COUNT(Col6) = COUNT(*) THEN 'no NULLs'
ELSE 'some NULLs'
END Col6NullStatus
FROM myTable
See SQL Fiddle for the above.
Edit 2:
And the output of this query would look something like this:
Col1NullStatus | Col2NullStatus | Col3NullStatus | Col4NullStatus | Col5NullStatus | Col6NullStatus
---------------+----------------+----------------+----------------+----------------+----------------
no NULLs | all NULLs | some NULLs | no NULLs | all NULLs | all NULLs
This is the format, you could be using, to post your input data and expected results.
So, since you give no no formal table structure, and you seem to be confusing numbers and chars(s), I will do my best to try and make a query that will at least produce the results you want.
create table foo as (
col1 varchar(10),
col2 varchar(10),
col3 varchar(10),
col4 varchar(10),
col5 varchar(10),
col6 varchar(10)
);
select *
CASE cust1 WHEN null then 'null' else cust1 as cust1 end,
CASE cust2 WHEN null then 'null' else cust1 as cust1 end,
CASE cust3 WHEN null then 'null' else cust1 as cust1 end,
CASE cust4 WHEN null then 'null' else cust1 as cust1 end,
CASE cust5 WHEN null then 'null' else cust1 as cust1 end,
CASE cust6 WHEN null then 'null' else cust1 as cust1 end
from foo ;
As per below query , I able to get not null columns at row-level col1,col3 and col4.
Query :
select 'col1' as "Name",col1 from temp
where exists (select 1
from temp
group by to_char(col1)
having (count(to_char(col1)))> 0)
union all
select 'col2' as "Name",to_char(col2) from temp
where exists (select 1
from temp
group by to_char(col2)
having (count(to_char(col2)))> 0)
union all
select 'col3' as "Name" , to_char(col3) from temp
where exists (select 1
from temp
group by to_char(col3)
having (count(to_char(col3)))> 0)
union all
select 'col4'as "Name" , to_char(col4) from temp
where exists (select 1
from temp
group by to_char(col4)
having (count(to_char(col4)))> 0)
union all
select 'col5' as "Name" , to_char(col5) from temp
where exists (select 1
from temp
group by to_char(col5)
having (count(to_char(col5)))> 0)
union all
select 'col6' as "Name" , to_char(col6) from temp
where exists (select 1
from temp
group by to_char(col6)
having (count(to_char(col6)))> 0)
output:
col1 A
col1 B
col1 C
col1 D
col3 10
col3 20
col3 -
col3 10
col4 12
col4 23
col4 34
col4 43
I tried to make this output of rows to columns but I couldn't make it in single query ... Hope this will be helpful ...
I would do this usually in three steps.
Firstly, make sure that the table statistics are up to date. Check if last_analyzed is later than the last change to the table.
SELECT last_analyzed FROM user_tables WHERE table_name = 'MYTABLE';
If in doubt, update the statistics with
BEGIN dbms_stats.gather_table_stats('MYSCHEMA','MYTABLE'); END;
/
Now, the view user_tab_columns has a column num_nulls. This is the number of rows where this column is NULL. If the value is the same than the number of rows in the table, all rows are NULL. This can be used to let Oracle generate the required SQL:
WITH
qtab AS (SELECT owner, table_name, num_rows
FROM all_tables
WHERE owner='SCOTT' -- change to your schema
AND table_name='EMPLOYEES' -- change to your table name
),
qcol AS (SELECT owner, table_name, column_name, column_id
FROM qtab t
JOIN all_tab_columns c USING (owner, table_name)
WHERE c.nullable = 'N' -- protected by NOT NULL constraint
OR c.num_nulls = 0 -- never NULL
OR c.num_nulls < t.num_rows -- at least 1 row is NOT NULL
)
)
SELECT 'SELECT '||LISTAGG(column_name,',') WITHIN GROUP (ORDER BY column_id)||
' FROM '||owner||'.'||table_name||';' AS my_query
FROM qcol
GROUP BY owner, table_name;
This will output a query like
SELECT col1, col3, col4, col5 FROM myschema.mytable;
This query can now be executed to show the column values.

Change Default Hive result to some values

I was trying to get duplicate record count from table, but for particular partitions data is not available, so hive is only printing "OK" result.
Is it possible to change this result with some value like 0 Or NULL.
Yes have tried with nvl,COALESCE,case option still it showing OK. AND goal is to only check duplicate count, so required at least one value
select col1, col2, nvl(count(*),0) AS DUPLICATE_ROW_COUNT, 'xyz' AS TABLE_NAME
from xyz
where data_dt='20170423'
group by col1,col2
having count(*) >1
It will return no rows on empty dataset because you are using group by and having filter. Group by having nothing to group, that is why it does not return any rows. Without group by and having query returns 0:
select nvl(count(*),0) cnt, 'xyz' AS TABLE_NAME
from xyz
where data_dt='20170423'
As a solution you can UNION ALL with null row when empty dataset
select col1, col2, nvl(count(*),0) AS DUPLICATE_ROW_COUNT, 'xyz' AS TABLE_NAME
from xyz
where data_dt='20170423'
group by col1,col2
having count(*) >1
UNION ALL --returns 1 row on empty dataset
select col1, col2, DUPLICATE_ROW_COUNT, TABLE_NAME
from (select null col1, null col2, null AS DUPLICATE_ROW_COUNT, 'xyz' AS TABLE_NAME
)a --inner join will not return rows when non-empty dataset
inner join (
select count(*) cnt from --should will return 0 on empty dataset
( --your original query
select col1, col2, nvl(count(*),0) AS DUPLICATE_ROW_COUNT, 'xyz' AS TABLE_NAME
from xyz
where data_dt='20170423'
group by col1,col2
having count(*) >1
)s --your original query
)s on s.cnt=0
Also it's may be possible to use CTE (WITH) and WHERE NOT EXISTS instead of inner joinfor your subquery, didn't test it.
Also you can use shell to get result and test it on empty value:
dataset=$(hive -e "set hive.cli.print.header=false; [YOUR QUERY HERE]);
# test on empty dataset
if [[ -z "$dataset" ]] ; then
dataset=0
fi

Oracle, get all columns

I got this statement:
select count(*),
article_no_external,
article_group_id
from tbl_erp_article
where article_no_external != ' '
group by article_no_external, article_group_id
having count(*) >1
I want to group by group_id and external_no, this works just fine, I get 128 records. But I would like to see all columns not only those 2. I tried to add them to the select, but then I get an error with the group by. I need 4 more columns cause I need to grab them to make a new record using the selected data.
select article_no_external, article_group_id, col2, col3, col4, col5
from (
select article_no_external, article_group_id, col2, col3, col4, col,
count(*) over (partition by article_no_external, article_group_id) as cnt
from tbl_erp_article
where article_no_external <> ' '
)
where cnt > 1;
If you want to find non-empty varchar columns remember that Oracle doesn't have an empty string. An '' is converted to NULL during inserts or updates. So you probably want where article_no_external IS NOT NULL
You cant get all column values when you aggregate your fields for count, sum etc.
Not exacly same result but this may help you.
select *
from tbl_erp_article
where article_no_external != ' ' and
(article_no_external, article_group_id) in (
select article_no_external, article_group_id
from tbl_erp_article
where article_no_external != ' '
group by article_no_external, article_group_id
having count(*) >1)

Resources