SQL Create A New Table off Of Query Results , in one Query - sql

Below is my attempt to create a table from a query, having a little trouble getting the insert into statement to work, the rest of the query works great, just cannot get my return results into a new table any idea how to ?
CREATE TABLE test (
a varchar(255),
b varchar(255),
)
--I assume the above is wrong , not sure why--
Insert into test (a, b)
select (B , Cor)
from
(
--below works great---
Select B,
CASE
WHEN B = 't' THEN 'test'
WHEN B = '-' THEN 'NULL'
WHEN B = 'Choos' THEN 'NULL'
WHEN B = 'Se Co' THEN 'S'
--
WHEN B LIKE 'Y%' THEN 'di'
WHEN B LIKE 'T%' THEN 'Ten'
--
ELSE B
END AS Cor
FROM
(SELECT WON AS B
FROM ma
UNION SELECT C
FROM ma )
Order By B )

The parentheses are suspicious:
Insert into test (a, b)
select (B, Cor)
-----------^
Some databases might interpret this as a single tuple (struct or record) with two fields. Some will generate an error. Basically, you want to drop the parens:
Insert into test (a, b)
select B, Cor
. . .

Related

Command for No new row in the table for the existing column

Suppose I have a table with 4 column headers a,b,c,d.
In the 1st insert statement, I insert a=1.
So my table T1 contains
T1
A B C D
1
In 2nd insert statement, I want to insert values like a=1,b=2,c=3,d=4.
So I want the output as
T1
A B C D
1 2 3 4
instead of
A B C D
1
1 2 3 4.
Point to be noted: The column might not be A all the time. It can be any one of A, B, C, D. i.e; every time I have to check for all the 4 columns if their corresponding values are there or not.
I tried the following code
PROCEDURE INSERT_FOM_SPM_B2B (
A IN VARCHAR,
B IN VARCHAR,
C IN VARCHAR,
D IN VARCHAR
)
IS
BEGIN
MERGE INTO MISIMD_FOM_SPM_B2B USING (select 1 from dual) m ON (A=A or B=B or C=C or D=D)
WHEN MATCHED THEN UPDATE SET
A = nv12(A,A,A),
B = nv12(B,B,B),
C = nv12(C,C,C),
D = nv12(D,D,D)
WHEN NOT MATCHED THEN INSERT (
A,B,C,D
) VALUES (
A,B,C,D
);
EXCEPTION
WHEN OTHERS THEN
NULL;
END INSERT_FOM_SPM_B2B;
It is giving me the error
PL/SQL statement is ignored and
missing right parenthesis.
There are several issues in your procedure:
commas missing in the SET clause
mixup of column and parameter names
Fixing those problems, to at least make it compile, results in:
create or replace PROCEDURE INSERT_FOM_SPM_B2B (
pA IN VARCHAR,
pB IN VARCHAR,
pC IN VARCHAR,
pD IN VARCHAR
) IS
BEGIN
MERGE INTO MISIMD_FOM_SPM_B2B USING (select 1 from dual) m ON (A=pA or B=pB or C=pC or D=pD)
WHEN MATCHED THEN UPDATE SET
A = nvl(A,pA),
B = nvl(B,pB),
C = nvl(C,pC),
D = nvl(D,pD)
WHEN NOT MATCHED THEN INSERT (
A,B,C,D
) VALUES (
pA,pB,pC,pD
);
END INSERT_FOM_SPM_B2B;
/
But that still does not work, as it throws an exception during execution:
exec INSERT_FOM_SPM_B2B(1,null,null,null)
ORA-38104: Columns referenced in the ON Clause cannot be updated: "A"
ORA-06512: at "MYSCHEMA.INSERT_FOM_SPM_B2B", line 10
ORA-06512: at line 1
38104. 00000 - "Columns referenced in the ON Clause cannot be updated: %s"
*Cause: LHS of UPDATE SET contains the columns referenced in the ON Clause
Not sure if MERGE can somehow be convinced to do what you want it to do, but you can use this procedure instead, making use of the sql%rowcount result counter:
create or replace PROCEDURE INSERT_FOM_SPM_B2B (
pA IN VARCHAR,
pB IN VARCHAR,
pC IN VARCHAR,
pD IN VARCHAR
) IS
BEGIN
update MISIMD_FOM_SPM_B2B
set A = nvl(A,pA),
B = nvl(B,pB),
C = nvl(C,pC),
D = nvl(D,pD)
where A = pA
or B = pB
or C = pC
or D = pD;
if sql%rowcount=0 then
insert into MISIMD_FOM_SPM_B2B (A, B, C, D)
values ( pA, pB, pC, pD );
end if;
END INSERT_FOM_SPM_B2B;
/
You should be aware that this kind of merging is awfully slow...
BTW, what is desired outcome for this sequence of procedure calls:
INSERT_FOM_SPM_B2B(1,null,null,null);
INSERT_FOM_SPM_B2B(null,2,null,null);
INSERT_FOM_SPM_B2B(null,null,3,null);
INSERT_FOM_SPM_B2B(null,null,null,4);
INSERT_FOM_SPM_B2B(1,2,3,4);
Or this one:
INSERT_FOM_SPM_B2B(1,null,null,1);
INSERT_FOM_SPM_B2B(null,2,null,2);
INSERT_FOM_SPM_B2B(1,2,null,null);
This version worked.But you should pay attention about naming standards.
create or replace procedure insert_fom_spm_b2b (param_a in varchar,
param_b in varchar,
param_c in varchar,
param_d in varchar)
is
begin
merge into misimd_fom_spm_b2b x
using (select param_a param_a,
param_b param_b,
param_c param_c,
param_d param_d
from DUAL) m
on ( (m.param_a, 'dummy') = ( (x.a, 'dummy'))
or (m.param_b, 'dummy') = ( (x.b, 'dummy'))
or (m.param_c, 'dummy') = ( (x.c, 'dummy'))
or (m.param_d, 'dummy') = ( (x.d, 'dummy')))
when matched
then
update set
a= NVL (param_a, a), b = NVL (param_b, b), c = NVL (param_c, c), d = NVL (param_d, d)
when not matched
then
insert (a,
b,
c,
d)
values (param_a,
param_b,
param_c,
param_d);
exception
when others
then
DBMS_OUTPUT.put_line (SQLERRM);
end insert_fom_spm_b2b;

Oracle SQL XOR condition with > 14 tables

I have a question on sql desgin.
Context:
I have a table called t_master and 13 other tables (lets call them a,b,c... for simplicity) where it needs to compared.
Logic:
t_master will be compared to table 'a' where t_master.gen_val =
a.value.
If record exist in t_master, retrieve t_master record, else retrieve 'a' record.
I do not need to retrieve the records if it exists in both tables (t_master and a) - XOR condition
Repeat this comparison with the remaining 12 tables.
I have some idea on doing this, using WITH to subquery the non-master tables (a,b,c...) first with their respective WHERE clause.
Then use XOR statement to retrieve the records.
Something like
WITH a AS (SELECT ...),
b AS (SELECT ...)
SELECT field1,field2...
FROM t_master FULL OUTER JOIN a FULL OUTER JOIN b FULL OUTER JOIN c...
ON t_master.gen_value = a.value
WHERE ((field1 = x OR field2 = y ) AND NOT (field1 = x AND field2 = y))
AND ....
.
.
.
.
Seeing that I have 13 tables that I need to full outer join, is there a better way/design to handle this?
Otherwise I would have at least 2*13 lines of WHERE clause which I'm not sure if that will have impact on the performance as t_master is sort of a log table.
**Assume I cant change any schema.
Currently I'm not sure if this SQL will working correctly yet, so I'm hoping someone can guide me in the right direction regarding this.
update from used_by_already's suggestion:
This is what I'm trying to do (comparison between 2 tables first, before I add more, but I am unable to get values from ATP_R.TBL_HI_HDR HI_HDR as it is in the NOT EXISTS subquery.
How do i overcome this?
SELECT LOG_REPO.UNIQ_ID,
LOG_REPO.REQUEST_PAYLOAD,
LOG_REPO.GEN_VAL,
LOG_REPO.CREATED_BY,
TO_CHAR(LOG_REPO.CREATED_DT,'DD/MM/YYYY') AS CREATED_DT,
HI_HDR.HI_NO R_VALUE,
HI_HDR.CREATED_BY R_CREATED_BY,
TO_CHAR(HI_HDR.CREATED_DT,'DD/MM/YYYY') AS R_CREATED_DT
FROM ATP_COMMON.VW_CMN_LOG_GEN_REPO LOG_REPO JOIN ATP_R.TBL_HI_HDR HI_HDR ON LOG_REPO.GEN_VAL = HI_HDR.HI_NO
WHERE NOT EXISTS
(SELECT NULL
FROM ATP_R.TBL_HI_HDR HI_HDR
WHERE LOG_REPO.GEN_VAL = HI_HDR.HI_NO
)
UNION ALL
SELECT LOG_REPO.UNIQ_ID,
LOG_REPO.REQUEST_PAYLOAD,
LOG_REPO.GEN_VAL,
LOG_REPO.CREATED_BY,
TO_CHAR(LOG_REPO.CREATED_DT,'DD/MM/YYYY') AS CREATED_DT,
HI_HDR.HI_NO R_VALUE,
HI_HDR.CREATED_BY R_CREATED_BY,
TO_CHAR(HI_HDR.CREATED_DT,'DD/MM/YYYY') AS R_CREATED_DT
FROM ATP_R.TBL_HI_HDR HI_HDR JOIN ATP_COMMON.VW_CMN_LOG_GEN_REPO LOG_REPO ON HI_HDR.HI_NO = LOG_REPO.GEN_VAL
WHERE NOT EXISTS
(SELECT NULL
FROM ATP_COMMON.VW_CMN_LOG_GEN_REPO LOG_REPO
WHERE HI_HDR.HI_NO = LOG_REPO.GEN_VAL
)
Full outer joins used to exclude all matching rows can be an expensive query. You don't supply much detail, but perhaps using NOT EXISTS would be simpler and maybe it will produce a better explain plan. Something along these lines.
select
cola,colb,colc
from t_master m
where not exists (
select null from a where m.keycol = a.fk_to_m
)
and not exists (
select null from b where m.keycol = b.fk_to_m
)
and not exists (
select null from c where m.keycol = c.fk_to_m
)
union all
select
cola,colb,colc from a
where not exists (
select null from t_master m where a.fk_to_m = m.keycol
)
union all
select
cola,colb,colc from b
where not exists (
select null from t_master m where b.fk_to_m = m.keycol
)
union all
select
cola,colb,colc from c
where not exists (
select null from t_master m where c.fk_to_m = m.keycol
)
You could union the 13 a,b,c ... tables to simplify the coding, but that may not perform so well.

finding number of people in a table that are NOT in other tables in SQL Server

I have 3 tables (let's say A, B, and C), and I have a common key column in all 3, called G.
I need a script to find the number of G that are in A (the main table - Level 1) that are not in either of B or C (level 2 tables). Basically, I want to left join a table on the result of full join of other 2 tables.
I tried the left join but the result is not correct. I used following script:
SELECT COUNT(DISTINCT A.G)
FROM A LEFT JOIN B ON A.G = B.G
FULL JOIN C ON A.G = C.G
WHERE (B.G IS NULL) OR (C.G IS NULL)
Appreciate your help.
P.S.
Choice of correct answer is based on the superiority in processing time. I ran both alternatives (exists vs. left joins) on my data set (which is relatively large and time consuming).
LEFT JOIN approach (selected answer) is far more process efficient than the EXISTS. It took former approach 0:23 minutes, compared to 7:52 minutes for later approach.
using not exists() to count() rows where G does not exist in B or C:
select count(*)
from A
where not exists (select 1 from B where A.G = B.G)
or not exists (select 1 from C where A.G = C.G)
If you want to count() rows where G does not exist in both B and C, change or to and in the above code.
rextester example demo: http://rextester.com/MSVVN6153
You are close - You need a left join to both B and C tables as well as AND instead of OR in your where clause:
SELECT COUNT(DISTINCT A.G)
FROM A
LEFT JOIN B ON A.G = B.G
LEFT JOIN C ON A.G = C.G
WHERE B.G IS NULL
AND C.G IS NULL;
I suspect that you want:
select count(*)
from a
where not exists (select 1 from b where a.g = b.g) and
not exists (select 1 from c where a.g = c.g);
You specify: "in A . . . that are not in either of B or C ". This suggests that G doesn't exist in B and doesn't exist in C. Hence the and rather than or (as in your version of the query).
I also removed the count(distinct). Instinct suggests that a.g is unique. If not, then count(distinct a.g) is correct..
And one last option using set operators you should learn. I'll leave counting out just to demonstrate the correctness:
set nocount on;
declare #a table (id smallint not null);
declare #b table (id smallint not null, xx smallint not null);
declare #c table (id smallint not null, yy smallint not null);
insert #a(id) values (1), (2), (3), (4);
insert #b(id, xx) values (1,0), (1,1), (3, 0);
insert #c(id, yy) values (1,9), (2, 1), (2,2), (5,1); -- notice the value 5 does not exist in #a
select id from #a except
select id from #b except
select id from #c
;

How to set nulls the values of column B and column C if they already exist on column A sql?

Select BillName as A, ConsigneeName as B, ShipperName as C
from Sum_Orders
where (OrderStatus in ('Complete','Invoiced')
)
and
OrderPeriodYear IN (
(
YEAR(GETDATE())-1
)
)
Group by billname,ConsigneeName,ShipperName
I'm having duplicates in A, B, C (which is expected)
I'm trying to make a condition to
keep the value in A and set to nulls the values that repeat in B OR C
IF A = B or C then keep A and SET B or C to NULLS
Thank you, guys, :D
Is this what you want?
update t
set B = (case when B <> A then B end),
C = (case when C <> A then C end)
where B <> A or C <> A;
If you have to do this inline the perhaps a case will help.
Select Billname AS A,
CASE WHEN ConsigneeName = Billname THEN NULL ELSE ConsigneeName END,
CASE WHEN ShipperName = Billname THEN NULL ELSE ShipperName
from Sum_Orders etc ...
If the table is big, this maybe expensive on the query and pushing this logic into the query itself might be better.
If a,b and c has same value, b and c should set null, so:
Update tablename
Set B = if(A=B, null, B) , C=if(A=C, null, C)
-- where A=B or A=C
You can use 'where' if optimization is interesting!
If you're going to 'Select' value:
Select A, if(A=B, null, B) as B , if(A=C, null, C) as C from tablename

Fetching rows from two sql tables

I have two tables RecordMaster and Dummy
Both have columns like Mobile_Number and Insert_Date
I want a row like
1) from Dummy table I want to fetch those rows whose Mobile_Number And Insert_Date are same compared to RecordMaster.
2) from Dummy table I want to fetch those rows whose Mobile_Number And Insert_Date are different compared to RecordMaster.
After that in 1) condition I want to fetch only those rows whose Cpv_Status is not null.
(CPV_STATUS) is one column in the Dummy table..
Help me please ........
To meet your 1) and 3) needs ( optionally include the WHERE as you need).
SELECT d.*
FROM Dummy d
INNER JOIN RecordMaster r
ON r.mobile_number = d.mobile_number
AND r.insert_date = d.insert_date
WHERE d.Cpv_Status IS NOT NULL
2.
SELECT d.*
FROM Dummy d
WHERE NOT EXISTS
(SELECT 1
FROM RecordMaster r
WHERE r.mobile_number = d.mobile_number
AND r.insert_date = d.insert_date
)
To insert these:
INSERT INTO RecordMaster(mobile_number, insert_date)
SELECT d.mobile_number, insert_date
FROM Dummy d
WHERE NOT EXISTS
(SELECT 1
FROM RecordMaster r
WHERE r.mobile_number = d.mobile_number
AND r.insert_date = d.insert_date
)
The following query will give you all records in dummy that match the records in RecordMaster
SELECT a.Mobile_Number,a.Insert_Date ,a.Cpv_Status
FROM RecordMaster a, Dummy b
WHERE a.Mobile_Number = b.Mobile_Number and a.Insert_Date = b.Insert_Date
The following query will give you records in Dummy that don't have matching records in RecordMadter
SELECT a.Mobile_Number,a.Insert_Date ,a.Cpv_Status
FROM Dummy a
WHERE STR(a.Mobile_Number)+STR(a.Mobile_Number) not in
(SELECT STR(Mobile_Number)+STR(Insert_Date) FROM RecordMaster)
if you need both of these results combined in one result set, then use UNION like this
SELECT a.Mobile_Number,a.Insert_Date ,a.Cpv_Status
FROM RecordMaster a, Dummy b
WHERE a.Mobile_Number = b.Mobile_Number and a.Insert_Date = b.Insert_Date
UNION
SELECT a.Mobile_Number,a.Insert_Date ,a.Cpv_Status
FROM Dummy a
WHERE STR(a.Mobile_Number)+STR(a.Mobile_Number) not in
(SELECT STR(Mobile_Number)+STR(Insert_Date) FROM RecordMaster)
Lastly, you can apply any filter you want to the final result set like this:
select * from (
SELECT a.Mobile_Number,a.Insert_Date , a.Cpv_Status,a.Cpv_Status
FROM RecordMaster a, Dummy b
WHERE a.Mobile_Number = b.Mobile_Number and a.Insert_Date = b.Insert_Date
UNION
SELECT a.Mobile_Number,a.Insert_Date ,a.Cpv_Status
FROM Dummy a
WHERE STR(a.Mobile_Number)+STR(a.Mobile_Number) not in
(SELECT STR(Mobile_Number)+STR(Insert_Date) FROM RecordMaster)
) where Cpv_Status is not null