Remove null values from SQL result - sql

My Oracle SQL query returns only 1 row.
I want to remove the null values from the result.
I don't want to get an empty column. I want my query to ignore this column.
For example, I have this table and query:
create table tbl (col_1 number,
col_2 number,
col_3 number);
insert into tbl values(1,null,3);
commit;
select col_1, col_2, col_3 from tbl where rownum=1;
The result is:
| COL_1 | COL_2 | COL_3 |
+-------+-------+-------+
| 1 | | 3 |
+-------+-------+-------+
In this case, I want my query to ignore "COL_2" field, and return:
| COL_1 | COL_3 |
+-------+-------+
| 1 | 3 |
+-------+-------+

Suppose this is a table that contains up to 3 columns in a single row; could be even result of a query, doesn't matter - you'd just fix line #9 in function code.
SQL> create table test (a number, b number, c number);
Table created.
SQL> insert into test values (1, null, 3);
1 row created.
Function returns refcursor. Why? That's one option to return different columns, depending on select statement.
SQL> create or replace function f_test
2 return sys_refcursor
3 is
4 l1 number;
5 l2 number;
6 l3 number;
7 rc sys_refcursor;
8 begin
9 select a, b, c into l1, l2, l3 from test;
10
11 if l1 is null and l2 is null and l3 is null then
12 open rc for select null from dual where 1 = 2;
13 elsif l1 is not null and l2 is null and l3 is null then
14 open rc for select l1 from dual;
15 elsif l1 is not null and l2 is not null and l3 is null then
16 open rc for select l1, l2 from dual;
17 elsif l1 is not null and l2 is null and l3 is not null then
18 open rc for select l1, l3 from dual;
19 elsif l1 is not null and l2 is not null and l3 is not null then
20 open rc for select l1, l2, l3 from dual;
21 elsif l1 is null and l2 is not null and l3 is null then
22 open rc for select l2 from dual;
23 elsif l1 is null and l2 is not null and l3 is not null then
24 open rc for select l2, l3 from dual;
25 elsif l1 is null and l2 is null and l3 is not null then
26 open rc for select l3 from dual;
27 end if;
28
29 return rc;
30 end;
31 /
Function created.
Let's try it: initially, we have A and B:
SQL> select f_test from dual;
F_TEST
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
:B2 :B1
---------- ----------
1 3
We have only C:
SQL> update test set a = null, b = null, c = 3;
1 row updated.
SQL> select f_test from dual;
F_TEST
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
:B1
----------
3
We don't have anything:
SQL> update test set a = null, b = null, c = null;
1 row updated.
SQL> select f_test from dual;
F_TEST
--------------------
CURSOR STATEMENT : 1
CURSOR STATEMENT : 1
no rows selected
SQL>
Of course, if it gets more complex, code won't be that simple any more and you might find yourself in maintenance problems.

Seems like you cannot get what you want with pure SQL as you need to specify the columns you want to see in response in your SELECT statement before the execution.
check out the dynamic SQL / refcursors/ pipeline functions:
https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:4843682300346852395#5421020800346627246)
https://blogs.oracle.com/connect/post/how-to-dynamically-change-the-columns-in-a-sql-query

Related

How to copy data in same table with child and MasterID in SQL Server

We have data in a SQL Server table like this:
PID Name RefNo FID
----------------------------
1 ABC G1
2 XYZ G1 1 (1 relate to PID=1)
3 DEF G1 1 (1 relate to PID=1)
To create a copy of above data in the same table for RefNO G2 we have used SQL query
INSERT INTO Table1
SELECT ISNULL(Max(PID),0) + 1, Name, 'G2', FID
FROM Table1
and it has copied the data like
1 ABC G1
2 XYZ G1 1 *(1 relate to PID=1)*
3 DEF G1 1 *(1 relate to PID=1)*
4 ABC G2
5 XYZ G2 1 *(it should be 4 but it is showing 1 by my query)*
6 DEF G2 1 *(it should be 4 but it is showing 1 by my query)*
Please guide how do I write the correct query to get my desired result as below
1 ABC G1
2 XYZ G1 1
3 DEF G1 1
4 ABC G2
5 XYZ G2 4
6 DEF G2 4
Create temporary table and insert data into it. below query help you do this.
create table #Temp
(
PID int ,
Name VARCHAR(100),
RefNo Varchar(50),
FID int
)
INSERT INTO #Temp
SELECT * FROM temp1
Below Code help to insert data into main table using Cursor.
DECLARE #Name VARCHAR(50),
#FID INT,#TFID INT = NULL,
#RefNo VARCHAR(10) = 'G2'
DECLARE cur CURSOR
FOR
SELECT Name ,FID
FROM #Temp
OPEN cur
FETCH NEXT FROM cur INTO #Name,#FID
WHILE ##FETCH_STATUS = 0
BEGIN
IF #FID IS NULL
BEGIN
SELECT #TFID = NULL
END
INSERT INTO temp1(Name,RefNo,FID)
VALUES ( #Name, #RefNo, #TFID)
IF #FID IS NULL
BEGIN
SELECT #TFID = ##IDENTITY
END
FETCH NEXT FROM cur INTO #Name,#FID
END
CLOSE cur
DEALLOCATE cur
After insert please delete #tTemp Table
drop table #Temp
You get updated main table.

To update CLOB column in Oracle

I need to update table B with column Value with CLOB type from table A
Table A
ID Value
1001 ABC
1002 CDE
1003 ABC
1004 PWD
Table B to be updated as below:
ID - varchar2(355)
Value - CLOB
ID Value
ABC 1001!1003
CDE 1002
PWD 1004
Looks more like an INSERT, not UPDATE. Anyway, LISTAGG will help in both cases.
SQL> insert into b (id, value)
2 select a.value, listagg(a.id, '!') within group (order by a.id)
3 from a
4 group by a.value;
3 rows created.
SQL> select * From b;
ID VALUE
---------- --------------------------------------------------
ABC 1001!1003
CDE 1002
PWD 1004
SQL>

Insert rows for records that exists with a distinct id

I'd like to insert a row for each distinct id that exists in my table. What is the best and efficient practice to add these rows for each distinct id?
ID Name Count
-- ---- ---
A1 ABC 4
A1 BCD 2
B1 KLM 1
C2 STU 3
C2 BCD 1
C2 DEF 5
EXPECTED RESULT AFTER INSERT
ID Name Count
-- ---- ---
A1 ABC 4
A1 BCD 2
A1 EXISTS 1
B1 KLM 7
B1 EXISTS 1
C2 STU 3
C2 BCD 4
C2 DEF 5
C2 EXISTS 1
Use union all:
select id, name, count
from t
union all
select distinct id, 'EXISTS', 1
from t;
An insert is even simpler:
insert into t (id, name, count)
select distinct id, 'EXISTS', 1
from t;

ORA-01427 Single row subquery returns more than 1 row

This error seems to be popular and there are many related answers. However, the existing answers do not seem to apply to my situation.
I am simplifying my case using 2 tables: Test1 and Test3 (see illustration)
What I am trying to do is attempting to find the records in test3 table that does not match the value in field value1 (if the field check_condition1 = 1 if it is 0 then I do not care)
so basically the result should be similar to this query in this particular scenario:
select distinct t3.* from test3 t3, test1 t1
where t3.department=t1.department
and t3.value1 not in ('A','B');
However, if I use this statement:
select distinct t3.* from test3 t3, test1 t1
where t3.department=t1.department
and t3.value1 not in
(
case t1.CHECK_CONDITION1
when 0 then
(select '1' from dual where 1=2)
when 1 then
( select value1 from test1 where department=t3.DEPARTMENT)
end
)
I got this message:
ORA-01427: single-row subquery returns more than one row
01427. 00000 - "single-row subquery returns more than one row"
*Cause:
*Action:
I thought my subquery "select value1 from test1 where department=t3.DEPARTMENT" should return a set for t3.value1 to check against.
How should the statement be corrected? My goal is to use Test1 table as a control table, the fields Check_condition1, check_condition2 are the "switches" that could be turn on and off without having to change the main query.
Please advise if my thought make sense.
Attached are the script to create the tables test1 and test3 for easier duplication of my issue.
CREATE TABLE "TEST1"
( "DEPARTMENT" NUMBER(3,0),
"VALUE1" VARCHAR2(26 BYTE),
"VALUE2" VARCHAR2(26 BYTE),
"CHECK_CONDITION1" NUMBER(3,0),
"CHECK_CONDITION2" NUMBER(3,0)
)
Insert into TEST1 (DEPARTMENT,VALUE1,VALUE2,CHECK_CONDITION1,CHECK_CONDITION2) values (1,'A','Z',1,0);
Insert into TEST1 (DEPARTMENT,VALUE1,VALUE2,CHECK_CONDITION1,CHECK_CONDITION2) values (1,'B','Y',1,0);
CREATE TABLE "TEST3"
( "DEPARTMENT" NUMBER(3,0),
"VALUE1" VARCHAR2(26 BYTE),
"VALUE2" VARCHAR2(26 BYTE),
"VALUE3" VARCHAR2(26 BYTE)
);
Insert into TEST3 (DEPARTMENT,VALUE1,VALUE2,VALUE3) values (1,'A','T','Whatever');
Insert into TEST3 (DEPARTMENT,VALUE1,VALUE2,VALUE3) values (1,'Z','Y','Whatever');
Insert into TEST3 (DEPARTMENT,VALUE1,VALUE2,VALUE3) values (1,'B','Y','Whatever');
From the CASE expression documentation:
For both simple and searched CASE expressions, all of the return_exprs must either have the same datatype (CHAR, VARCHAR2, NCHAR, or NVARCHAR2, NUMBER, BINARY_FLOAT, or BINARY_DOUBLE) or must all have a numeric datatype. If all return expressions have a numeric datatype, then Oracle determines the argument with the highest numeric precedence, implicitly converts the remaining arguments to that datatype, and returns that datatype.
The return_expr of a CASE statement expects a single value so your sub-query:
( select value1 from test1 where department=t3.DEPARTMENT)
is what is raising the exception.
Instead use the filter on the sub-query:
select distinct t3.*
from test3 t3
INNER JOIN test1 t1
ON ( t3.department=t1.department )
WHERE t3.value1 not in (
select value1
from test1
where department=t3.DEPARTMENT
AND t1.CHECK_CONDITION1 = 1
)
Which, for your test data, outputs:
DEPARTMENT | VALUE1 | VALUE2 | VALUE3
---------: | :----- | :----- | :-------
1 | Z | Y | Whatever
db<>fiddle here
That would be something like this, I presume:
SQL> select distinct t3.*
2 from test3 t3 join test1 t1 on t3.department=t1.department
3 where t3.value1 not in
4 (select t1.value1 from test1 t1
5 where t1.department = t3.department
6 and 1 = case when t1.check_condition1 = 1 then 1
7 else 0
8 end
9 );
DEPARTMENT VALUE1 VALUE2 VALUE3
---------- ---------- ---------- ----------
1 Z Y Whatever
SQL>
If condition was 0, you said you don't care, so:
SQL> update test1 set check_condition1 = 0;
2 rows updated.
SQL> select distinct t3.*
2 from test3 t3 join test1 t1 on t3.department=t1.department
3 where t3.value1 not in
4 (select t1.value1 from test1 t1
5 where t1.department = t3.department
6 and 1 = case when t1.check_condition1 = 1 then 1
7 else 0
8 end
9 );
DEPARTMENT VALUE1 VALUE2 VALUE3
---------- ---------- ---------- ----------
1 B Y Whatever
1 A T Whatever
1 Z Y Whatever
SQL>

Executing Insert into statement in SQL resulting in nulls for other columns

i am trying to use an insert into a column where the data for other columns already exists, but the data is not populating adjacent to the other columns, instead data is inserted after all the data in the table.
For example:
select * from tab1;
ID NAme Last_name
1 King
2 Queen
3 Rook
select * from tab2;
Id LastName_Name
1 Abc
2 def
3 xyz
SQL : Insert into tab1 (Last_name)
select tab2.LastName_Name from tab1,tab2, where tab1.Id=tab2.Id
Output:
Id Name Last_Name
1 King NULL
2 Queen NULL
3 Rook NULL
4 NULL Abc
5 NULL def
6 NULL xyz
But I want the data as below:
Id Name Last_Name
1 King Abc
2 Queen def
3 Rook xyz
Any work around for this? thanks in advance :)
Step2:
select * from tab1;
ID Name Id2
1 King NA
2 Queen NA
3 Rook NA
select * from tab2;
ID
1
2
3
4
5
6
I want the Output data as below:
The ID data in tab2 should populate in tab1 column (ID2) which are matching with TAB1.ID column values as below:
Id Name ID2
1 King 1
2 Queen 2
3 Rook 3
Can you please provide any query for this?
So you are wanting to UPDATE the rows in tab1 with the corresponding last names from tab2?
In which case, use an UPDATE statement instead of an INSERT:
UPDATE tab1
SET tab1.Last_name = tab2.LastName_Name
FROM tab1
JOIN tab2 ON tab1.Id = tab2.Id
You don't need an INSERT you need an UPDATE statement:
UPDATE tab1 SET tab1.Last_name = tab2.LastName_Name
FROM tab1 INNER JOIN tab2 ON tab1.Id = tab2.Id