SQL or procedure to conditionally insert or update in Oracle database - sql

I don't have much of a hands-on in SQL and procedures. I need a migration script wherein I need to update or insert a table based on data in other two tables.
Organization: id name pid 1 org1 null 2
org2 null 3
org3 1 4
org4 2
Org_Channel: org_id channel 1 CH_100 2
CH_101
Organization table has a parent-child self referenced relation. (pid null in case of parent). Org_Channel is a mapping table for parent organizations only.
Now I have a third table Org_Settings in which I need to migrate the data based on the above two tables. Each record here indicates a organization id, a setting name which is prefixed by channel name(for child org.this will be parent org.channel), and a flag. I need a migration SQL script / procedure for a setting Sign_On to be enabled as 'Y' for every organization
The current table is something like this:
Org_Settings: org_id s_name enabled 1 CH_100_Sign_On N 1 CH_100_X_O Y
4 CH_101_Sign_On Y
Now Org_Settings may or may not contain entry for each org. Also I need to migrate such that, if entry is present for Sign_On then need to update enabled = Y. Such that the result would be:
Org_Settings: org_id s_name enabled 1 CH_100_Sign_On Y 2 CH_101_Sign_On Y
3 CH_100_Sign_On Y 4 CH_101_Sign_On Y
I could think of pseudo code like:
for i in each org
var pid = getPid(i)
var id = (null == pid) ? i : pid
var channel = getChannel(id);
var sname = channel + "_Sign_On"
if(settingsEntryExists(i, sname))
updateSettingsEnable(i, sname, 'Y')
else
insertSettings(i, sname, 'Y')

Try this MERGE INTO statement. I did not understand the logic behind updating to 'Y' if entry exists and also inserting 'Y' if it does not exist. Isn't it same as simple insert?. or am I missing something? . You may tweak this query slightly if there is some missing info to clarify my question above.
SQLFiddle
MERGE
INTO Org_Settings d
USING ( select
org.id org_id,
ch.channel||
'_Sign_On' s_name ,
'Y' enabled
FROM
Organization org
JOIN Org_Channel ch ON NVL(org.pid,id) = ch.org_id
)s
ON ( d.org_id = s.org_id
AND d.s_name = s.s_name )
WHEN MATCHED THEN
UPDATE SET d.enabled = 'Y'
WHEN NOT MATCHED THEN
INSERT
(org_id,s_name,enabled
) VALUES
(s.org_id,s.s_name,s.enabled
);

Related

How to migrate datas using .sql script?

Im struggling how to migrate datas using .sql script I'm quite new to SQL and trying to figure out how to migrate data's purely on .SQL. I want to add my old data to the new table as a new record with a different structure
Here's my case: I have old two tbl and i want to merge it to my new structured tbl with an additional columns. I'm kinda stuck here since I'm not used in using conditional on .SQL
Prefixes of the tables are schemas
Old table
old.groups
id
group_name
10
Apex
11
Pred
12
Tor
old.sub_groups
parent_id
sub_group
10
sub-apex
11
sub-pred
11
sub-sub-pred
New Table:
Expected Migrated Data
public.new_groups *id is auto incremented
Fresh New populated table
id
group_name
level
parent_id
0
Apex
1
10
1
Pred
1
11
2
Tor
null
null
3
sub-apex
2
10
4
sub-pred
2
11
5
sub-sub-pred
2
11
I want to merge it with conditions. but i can't keep up with SQL queries
Condition 1: If old.groups.id doesn't detect any match on old.sub_groups.parent_id it will be inserted to public.new_groups but the public.new_groups.level and public.new_groups.parent_id will be default to null.
Condition 2: If old.groups.id detects a match on old.sub_groups.parent_id it will be also inserted to public.new_groups then tag the level as 1 (1 means parent group in my structure) but with another new three inserted records which is the sub_groups it detected refer to tbl.new_groups id [3, 4, and 5] and tag the level as 2. and the parent_id will be the parent_id of the old.sub_groups or the id of the parent in old.groups
This is my unfinished Query im only able to call the data its missing out the conditional and the update but i think this is also wrong:
INSERT INTO public.new_groups(
SELECT *, b.sub_group as group_name, b.parent_id FROM old.groups as a
LEFT JOIN old.sub_groups as b ON a.id = b.parent_id....
)
When you created your table like this:
CREATE TABLE new (
id SERIAL PRIMARY KEY ,
group_name VARCHAR(20),
level INTEGER,
parent_id INTEGER
);
You can copy the tables with this statement:
INSERT INTO new(group_name, level, parent_id)
SELECT DISTINCT
group_name,
CASE WHEN subgroups.parent_id IS NULL THEN NULL ELSE 1 END as level,
subgroups.parent_id
FROM old
LEFT JOIN subgroups ON old.id = subgroups.parent_id
UNION ALL
SELECT
sub_group,
2,
parent_id
FROM subgroups;
see: DBFIDDLE
just my id starts with 1, and not with 0.

Display column which contains dynamic values based upon values in other tables

I have two tables: PROJECT_SELECTED and COMPANY
What I want to do is create a query which displays all COMPANIES along with a column that identifies whether or not that COMPANY has been selected for a project (which is in PROJECT_SELECTED) based upon a variable.
COMPANY
COMPANY_ID
COMPANY_NAME
1
Company1
2
Company2
3
Company3
PROJECT_SELECTED
This table shows whether a certain company has been selected for a specific project.
PROJECT_ID
COMPANY_ID
1
1
1
2
2
1
3
2
This is the output that I want
Variable: PROJECT_ID = 1
COMPANY_ID
PROJECT_TENDERED
1
True
2
True
3
False
The SQL I wrote out goes something like this:
SELECT CASE
WHEN COMPANY_ID EXISTS IN
(SELECT COMPANY_ID FROM PROJECT_SELECTED WHERE PROJECT_ID=1) THEN "TRUE"
ELSE "FALSE"
END AS PROJECT_TENDERED
FROM COMPANY;
The variable referenced above this table is what I will be using to determine which project I am referencing. I am not worried about the changing of variable as the program I am using (Microsoft Access/VBA) has a requery functionality.
Simply put, how do I make a column that does not exist in either table which defaults to no but yes if it is found in PROJECT_SELECTED. The important part is that I can see all companies.
Isn't it easier with LEFT JOIN?
SELECT
company.company_name,
IIF(project_selected.project_id IS NULL, 'False', 'True')
FROM
company
LEFT JOIN
project_selected
ON project_selected.company_id = company.company_id
AND project_selected.project_id = 1
Finally figured it out at my own peril.
Seems Access does not support CASE statements. We must use IIF instead. In the IIF expression I have an inner query which determines if the COMPANY_ID is in the PROJECT_SELECTED table for a certain project. This is achieved using the WHERE statement in the inner query.
I have figured out the query based upon this link
SELECT COMPANY_NAME,
IIF(COMPANY_ID IN
(SELECT COMPANY_ID FROM PROJECT_SELECTED WHERE PROJECT_ID = 1),'TRUE','FALSE')
AS PROJECT_TENDERED
FROM COMPANY;

how to insert using join in query

i have a table like this
registrationId | standardId | courseId | marks
===============================================
5001 | 1 | 1 | 67
5001 | 1 | 2 | 87
and so on my question is the standard name and course name come from different tables so while updating i have to use 3 diffent queries 1st to get standardId according to standard name courseid acording to coursename and later update into this table. can it be done in one query?
Punctuation exists for a reason; you should use it. Without it, such a long sentence is difficult to read and understand.
Title says "insert", body says "update"; which one is it?
For UPDATE, something like this might do what you need:
update this_table tt set
tt.standardid = (select s.standardid
from standard s
where s.standard_name = :some_unique_standard_name
),
tt.courseid = (select c.courseid
from course c
where c.course_name = :some_unique_course_name
)
where tt.registrationid = :some_registration_id;
For INSERT:
insert into this_table
(registrationid, standardid, courseid, marks)
select
:some_registration_id,
(select s.standardid
from standard s
where s.standard_name = :some_unique_standard_name
),
(select c.courseid
from course c
where c.course_name = :some_unique_course_name
),
:marks_value
from dual;
in both cases, subqueries must return a single value
colon (:) represents a variable whose value you need to provide
syntax is based on Oracle; your database might differ (especially for INSERT, as there's probably no DUAL table elsewhere).

finding int_ids that have more than one row with a flag set to Y

I have a table that can store multiple descriptions for each code. However there is a flag in that table that is to indicate which of those is the main or primary description. In some instances, we have codes that have more than one with this flag set to Y which is not correct.
I am having trouble coming up with the SQL to get all the rows in that table that have more than one description set to Y.
I've used this SQL to identify rows that do not have ANY dsp_fg = 'Y'
select *
from table A
where dsp_fg = 'N'
and not exists (select 1 FROM table where cod_int_id = A.cod_int_id AND dsp_fg = 'Y')
But I am having trouble writing the SQL to get me the cod_int_ids that have more than one Y record, can someone help?
SELECT int_id FROM A
WHERE dsp_fg = 'Y'
GROUP BY int_id
HAVING count(1) > 1
This is not perfect, but it identifies what I need.

Oracle sql - identify and update primary and secondary rows in same table

I have a scenario where i need to identify a combination of records which are duplicates and use them to mark and identify which one is primary and which is secondary and then use an additional column to update the keys. This will help me update another child table which has referential integrity. Here's an example
Table Member
ID Name Birthdt MID
1 SK 09/1988 312
2 SK 09/1988 999
3 SL 06/1990 315
4 GK 08/1990 316
5 GK 08/1990 999
So from the above table my logic to identify duplicate is -- I do a group by on Name and Birthdate and when MID is 999 i consider that as a duplicate
so I created another temp table to capture dups.
Table member_dups
ID NAME BIRTHDT MID M_flg M_Key
1 SK 09/1988 P 1
2 SK 09/1988 S 1
4 GK 08/1990 P 4
5 GK 08/1990 S 4
For my table member_dups im able to load the duplicate records and update the flag . however I'm finding it difficult to get the right M_KEY for records marked as secondary. If i can achieve that then I can take that record and update the other table accordingly.
Thanks for any help offered.
If I understand your logic right the records that had MID = 999 is the secondary in member_dups.
If so you should be able to use an simple update with a join:
update member_dups
set m_key = m.id
from member_dups md
inner join Member m on m.name = mb.name and m.birthdt = mb.birthdt
where mb.m_flg = 's' and m.mid = 999
This example uses MSSQL syntax and thus isn't valid Oracle syntax, but you should get the idea, and hopefully you know Oracle better than I do. I'll try to work out the correct Oracle syntax and update the answer soon.
EDIT: I think this is the working Oracle syntax, but I haven't been able to test it:
MERGE INTO member_dups
USING
(
SELECT id,
name,
birthdt
FROM Member
where m.mid = 999
) m ON (m.name = mb.name and m.birthdt = mb.birthdt and mb.m_flg = 's')
WHEN MATCHED THEN UPDATE
SET member_dups.m_key = m.id