How to only select existing values from oracle? - oracle

I have a table with a massive number of columns. So many, that when I do SELECT * I can't even see any values because all the columns fill up the screen. I'd like to do something like this:
SELECT * FROM my_table WHERE NAME LIKE '%unique name%' AND <THIS COLUMN> IS NOT NULL
Is this possible? Note: VALUE is not a column.
There are so many questions on SO that ask this same question, but they have some bizarre twist, and the actual question is not answered.
I've tried:
SELECT * FROM my_table WHERE NAME LIKE '%unique name%' AND VALUE NOT NULL
*
Invalid relational operator
SELECT * FROM my_table WHERE NAME LIKE '%unique name%' AND VALUE <> ''
*
'VALUE': invalid identifier
SELECT * FROM my_table WHERE NAME LIKE '%unique name%' AND COLUMN NOT NULL
*
Missing Expression
Bonus Questions:
Is there any way to force Oracle to only show one output screen at a time?
Is there a variable to use in the WHERE clause that relates to the current column? Such as: WHERE this.column = '1', where it would check each column to match that expression?
Is there any way to get back your last command in Oracle? (I have to remote into a Linux box running Oracle - it's all command line - can't even copy/paste, so I have to type every command by hand, with a wonky connection, so it's taking an extremely long time to debug this stuff)

If you are trying to find all the non null column values for a particular record you could try an unpivot provided all the columns you are unpivoting have the same data type:
SELECT *
FROM (select * from my_table where name like '%unique value%')
UNPIVOT [include nulls] (col_value FOR col_name IN (col1, col2, ..., coln))
with the above code null values will be excluded unless you include the optional include nulls statement, also you will need to explicitly list each column you want unpivoted.
If they don't all have the same data type, you can use a variation that doesn't necessarily prune away all the null values:
select *
from (select * from my_table where name like '%unique value%')
unpivot ((str_val, num_val, date_val)
for col_name in ((cola, col1, date1)
,(colb, col2, date2)
,(colc, col3, date1)));
You can have a fairly large set of column groups, though here I'm showing just three, one for each major data type, with the IN list you need to have a column listed for each column in your column group, though you can reuse columns as shown by the date_val column where I've used date1 twice. As an alternative to reusing an existing column, you could use a dummy column with a null value:
select *
from (select t1.*, null dummy from my_table t1 where name like '%unique value%')
unpivot ((str_val, num_val, date_val)
for col_name in ((dummy, col1, date1)
,(colb, dummy, date2)
,(colc, col3, dummy)));

Have tried this?
SELECT * FROM my_table WHERE NAME LIKE '%unique name%' AND value IS NOT NULL;
Oracle / PLSQL: IS NOT NULL Condition
For row number:
SELECT field1, field2, ROW_NUMBER() OVER (PARTITION BY unique_field) R WHERE R=1;
Usually in Linux consoles you can use arrow up&down to repeat the last sentence.

Related

conditionally add an xmlattribute to an xmlelement with Oracle SQL

I'm dealing with a system that accepts data loads in XML format. For example, there's a field called "col1", and that field has the value "world" in it. The system interprets <col1 />, <col1></col1>, and a missing <col1> element as "no change" to the field called col1. (This is good because, if we were creating new data, "no change" would mean to accept whatever the default value is.) If I need to delete whatever is in the field, the <col1> element needs to have an xsi:nil attribute with a value of true.
So, when I'm extracting data from one instance of the system to load into another instance (inserting with SQL is not an option), I need to conditionally add xsi:nil="true" attribute to the XML returned from a query in Oracle 12c to explicitly indicate that the value of the element is null. (Always adding xsi:nil with a value of true or false, as appropriate, could work but is not desirable as it breaks convention and bloats file size.)
A test case can be set up as follows.
create table table1 (id number(10), col1 varchar2(5));
insert into table1 values (1,'hello');
insert into table1 values (2,null);
commit;
I want to to get this back from a query:
<outer><ID>1</ID><COL1>hello</COL1></outer>
<outer><ID>2</ID><COL1 xsi:nil="true"></COL1></outer>
This query throws an error.
select
xmlelement("outer",
xmlforest(id),
(case col1
when null then xmlelement(COL1, xmlattributes('xsi:nil="true"'), null)
else xmlforest(col1)
end)
)
from table1
;
Is there some other way to conditionally include the xmlattributes call, or some other way to get the output I want?
You can use NVL2 to make it slightly less verbose:
Query 1:
SELECT XMLELEMENT(
"outer",
XMLFOREST( id ),
XMLELEMENT( col1, xmlattributes( NVL2(col1,NULL,'true') as "xsi:nil"), col1 )
).getClobVal() AS element
FROM table1;
Result:
OUTPUT
-----------------------------------------------------
<outer><ID>1</ID><COL1>hello</COL1></outer>
<outer><ID>2</ID><COL1 xsi:nil="true"></COL1></outer>
Query 2: You could also use XMLFOREST to generate the elements and then APPENDCHILDXML to append the missing element (including namespaces are left as an exercise to the OP):
SELECT APPENDCHILDXML(
XMLELEMENT( "outer", XMLFOREST( id, col1 ) ),
'/outer',
NVL2( col1, NULL, XMLTYPE('<COL1 nil="true"></COL1>') )
).getClobVal() AS element
FROM table1;
Result:
OUTPUT
-------------------------------------------
<outer><ID>1</ID><COL1>hello</COL1></outer>
<outer><ID>2</ID><COL1 nil="true"/></outer>
I found that this query works, but it's more verbose than I would like.
select
xmlelement("outer",
xmlforest(id),
xmlelement(col1,xmlattributes(case when col1 is null then 'true' else null end as "xsi:nil"), col1)
).getClobVal()
from table1
;

How to select multiple column names (not values) in a table when column value is specified-Oracle

I have a table which has around 30 columns.Out of 30 columns i need to retrieve around 25 column names where value is set to some specified value(say 1).
I am not able to find a way to do this.Will multiple if statement work as below
select if columnname1='1' then 'columnname1' else null
if columnname2='1' then 'columnname2' else null from table.
In case the value is not set to 1, i don't want to retrieve the column names.
The below query can give me the column names but i can't specify the value with below query
select DISTINCT COLUMN_NAME from ALL_TAB_COLUMNS where TABLE_NAME='table_name'.
Does this work for you?
SELECT COLUMN_NAME
from ALL_TAB_COLUMNS
where TABLE_NAME='TABLE_NAME'
AND INSTR(column_name,'1') >0

Sorting a table with a column with SQL Server 2012

I have a table like this :
How can I sort it out in the form below :
Each set of records has been marked by a FlagID at end
Each set of records has been marked by a FlagID at end
I assume this means that each record is implicitly associated with the first non-null FlagID value that occurs at or after its position along the ID primary key. Thus, we can use a correlated subquery to project this implicit FlagID value for each record, sort by it, then sort by your Row column as tiebreaker for each set.
SELECT *
FROM YourTable T1
ORDER BY
(
SELECT TOP 1 T2.FlagID
FROM YourTable T2
WHERE T2.ID <= T1.ID
AND T2.FlagID IS NOT NULL
ORDER BY T2.ID DESC
),
T1.Row
However, if you're able to alter the database content, I would recommend you to explicitly populate all the FlagID fields, as this would make your life easier. If you do so, then the query becomes:
SELECT *
FROM YourTable T1
ORDER BY T1.FlagID,
T1.Row

Oracle identity column and insert into select

Oracle 12 introduced nice feature (which should have been there long ago btw!) - identity columns. So here's a script:
CREATE TABLE test (
a INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
b VARCHAR2(10)
);
-- Ok
INSERT INTO test (b) VALUES ('x');
-- Ok
INSERT INTO test (b)
SELECT 'y' FROM dual;
-- Fails
INSERT INTO test (b)
SELECT 'z' FROM dual UNION ALL SELECT 'zz' FROM DUAL;
First two inserts run without issues providing values for 'a' of 1 and 2. But the third one fails with ORA-01400: cannot insert NULL into ("DEV"."TEST"."A"). Why did this happen? A bug? Nothing like this is mentioned in the documentation part about identity column restrictions. Or am I just doing something wrong?
I believe the below query works, i havent tested!
INSERT INTO Test (b)
SELECT * FROM
(
SELECT 'z' FROM dual
UNION ALL
SELECT 'zz' FROM dual
);
Not sure, if it helps you any way.
For, GENERATED ALWAYS AS IDENTITY Oracle internally uses a Sequence only. And the options on general Sequence applies on this as well.
NEXTVAL is used to fetch the next available sequence, and obviously it is a pseudocolumn.
The below is from Oracle
You cannot use CURRVAL and NEXTVAL in the following constructs:
A subquery in a DELETE, SELECT, or UPDATE statement
A query of a view or of a materialized view
A SELECT statement with the DISTINCT operator
A SELECT statement with a GROUP BY clause or ORDER BY clause
A SELECT statement that is combined with another SELECT statement with the UNION, INTERSECT, or MINUS set operator
The WHERE clause of a SELECT statement
DEFAULT value of a column in a CREATE TABLE or ALTER TABLE statement
The condition of a CHECK constraint
The subquery and SET operations rule above should answer your Question.
And for the reason for NULL, when pseudocolumn(eg. NEXTVAL) is used with a SET operation or any other rules mentioned above, the output is NULL, as Oracle couldnt extract them in effect with combining multiple selects.
Let us see the below query,
select rownum from dual
union all
select rownum from dual
the result is
ROWNUM
1
1

Oracle, how update statement works

Question 1
Can anyone tell me if there is any difference between following 2 update statements:
UPDATE TABA SET COL1 = '123', COL2 = '456' WHERE TABA.PK = 1
UPDATE TABA SET COL1 = '123' WHERE TABA.PK = 1
where the original value of COL2 = '456'
how does this affect the UNDO?
Question 2
What about if I update a record in table TABA using ROWTYPE like the following snippet.
how's the performance, and how does it affect the UNDO?
SampleRT TABA%rowtype
SELECT * INTO SampleRT FROM TABA WHERE PK = 1;
SampleRT.COL2 = '111';
UPDATE TABA SET ROW = SampleRT WHERE PK = SampleRT.PK;
thanks
Is your question 1 asking whether UNDO (and REDO) is generated when you're running an UPDATE against a row but not actually changing the value?
Something like?
update taba set col2='456' where col2='456';
If this is the question, then the answer is that even if you're updating a column to the same value then UNDO (and REDO) is generated.
(An exception is when you're updating a NULL column to NULL - this doesn't generate any REDO).
For Question 1:
The outcome of the two UPDATEs for rows in your table where PK=1 and COL2='456' is identical. (That is, each such row will have its COL1 value set to '123'.)
Note: there may be rows in your table with PK=1 and COL2 <> '456'. The outcome of the two statements for these rows will be different. Both statements will alter COL1, but only the first will alter the value in COL2, the second will leave it unchanged.
For question 1:
There can be a difference as triggers can fire depending on which columns are updated. Even if you are updating column_a to the same value, the trigger will fire.
The UNDO shouldn't be different as, if you expand or shrink the length of a variable length column (eg VARCHAR or NUMBER), all the rest of the bytes of the record need to be shuffled along too.
If the columns don't change size, then you MAY get a benefit in not specifying the column. You can probably test it using v$transaction queries to look at undo generated.
For question 2:
I'd be more concerned about memory (especially if you are bulk collecting SELECT * ) and triggers firing than UNDO.
If you don't need SELECT *, specify the columns (eg as follows)
cursor c_1 is select pk, col1, col2 from taba;
SampleRT c_1%rowtype;
SELECT pk, col1, col2 INTO SampleRT FROM TABA WHERE PK = 1;
SampleRT.COL2 = '111';
UPDATE (select pk, col1, col2 from taba)
SET ROW = SampleRT WHERE PK = SampleRT.PK;

Resources