Skip Update of Table when no records present-SQL - sql

enter image description hereI want to migrate data from old table (table_old) to new table (table_new).
table_old has following columns.
recordseq
startdate
enddate
field1
field2
field3
recordnum
table_new has following columns.
recordseq
startdate
enddate
field1
field2
field3
field4
field5
field6
recordnum
recordnum_old
Each recordseq can have multiple records which can be found out by recordnum for example:
If for a particular recordseq has two records, then 1 and 2 will be present in recordnum column data.
Requirement is while migrating the data, every two records in old table should appear in 1 record.
Here data migration means consider field1, field2, field3 and recordnum.
For example, if a particular seq has 4 records in old table then first record will be inserted in 1st row of new table in field1, field2, field3 and 2nd row data will be inserted into field4, field5 and field6.
Similarly for 3rd row data in old table will be inserted in 2nd row of new table in field1, field2 and field3 and 4th row data will be inserted into field4, field5 and field6 of 2nd row in new table.
Some recordseqs may have only one record. Different seqs may have different recordnums.
In new table recordnum _old will hold the recordnum column data of old table and recordnum will contain new record number after migrating.
So while migrating first we have inserted recordseq, startdate, enddate and recordnum _old data
And recordnum be constant number like 999 which will be later updated to actual recordnum.
After this we wrote below code to migrate remain data those are field1,field2, field3 as explained above.
Do
Begin
DECLARE MAX_REC INT;
DECLARE REC_IDX INT;
Select max(recordnum) into MAX_REC FROM table _old;
MAX_REC := 0;
REC_IDX:=0;
while(REC_IDX<= MAX_REC)
Do
Begin
IF(mod(REC_IDX,2)=0)
Then
Update table_new a set (a. recordNum,a.field1,a.field2,a.field3)
= (select cast(REC_IDX/2 as int),b. field1,b.field2,b.field3 from table_old b Where
a.recordseq=b.recordseq and a.startdate=b.startdate and a.enddate = b.enddate and
b.recordnum=REC_IDX) from table_new a where a.recordnum_old= cast(REC_IDX/2 as int);
ELSEIF
THEN
Update table_new a set (a. recordNum,a.field4,a.field5,a.field6)
= (select cast(REC_IDX/2 as int),b. field1,b.field2,b.field3 from table_old b Where
a.recordseq=b.recordseq and a.startdate=b.startdate and a.enddate = b.enddate and
b.recordnum=REC_IDX) from table_new a where a.recordnum_old= cast(REC_IDX/2 as int);
END IF
once execution is finished new records can be filtered out by checking records which dont have pagenum 999
Main Issue with this code is if a particual seq has only one record and Max record number in old table is 5
On first iteration first row of the old record is inserting to first row of new table with rownumber as 1 then null value is overriding for recordnum in 2nd iteration as there are no more records present for this record seq.
So I don’t want to update the new table for a seq which has no more records in old table while iterating through while loop.
Can you please help me to achive this.

Related

SQL Merge Statement not working with Batch Data

I have created a stored procedure using MERGE statement as follows.
MERGE Tasks S
USING (SELECT id, name, field1, field2, field3 FROM Tasks_Temp) SS
ON S.id=SS.id
WHEN MATCHED
THEN UPDATE SET S.name=SS.name, S.field1=SS.field1, S.field2=SS.field2, S.field3=SS.field3
WHEN NOT MATCHED
THEN INSERT (id, name, field1, field2, field3) VALUES (SS.id, SS.name, SS.field1, SS.field2, SS.field3)
Tasks_temp:
id
name
field1
field2
field3
1
Task1
NULL
NULL
STARTED
2
Task2
SUBMITTED
NULL
STARTED
1
Task1
SUBMITTED
NULL
STARTED
3
Task3
NULL
NULL
STARTED
1
Task1
APPROVED
NULL
STARTED
2
Task2
APPROVED
NULL
STARTED
Tasks:(required)
id
name
field1
field2
field3
1
Task1
APPROVED
NULL
STARTED
2
Task2
APPROVED
NULL
STARTED
3
Task3
NULL
NULL
STARTED
Now here the Tasks_Temp table is empty at first and then it's filled with a sequential form of data as displayed where for each ID there's multiple changes like the field1, field2 or field3. The merge statement is inserting all the values into the other table, even duplicate IDs i.e., exactly the records as present in Tasks_Temp.
The next time when I run it gives me errors saying
Trying to update multiple records not allowed
Is merge not able to handle batch data like this? Even if I ignore getting the latest data for each fields MERGE still inserts the same number of rows as present in Tasks_Temp table. If not, what are some other optimal approaches?
I feel that even if merge worked, it wouldn't necessarily mean it's taking the most updated field values for an id.
However, if I have a timestamp provided, how can I insert the most recent records from the Tasks_Temp table to the Tasks table?
CREATE TABLE Tasks_Temp(
id INTEGER NOT NULL
,name VARCHAR(100) NOT NULL
,field1 VARCHAR(100)
,field2 VARCHAR(100)
,field3 VARCHAR(100) NOT NULL
);
INSERT INTO Tasks_Temp
(id,name,field1,field2,field3) VALUES
(1,'Task1',NULL,NULL,'STARTED'),
(2,'Task2','SUBMITTED',NULL,'STARTED'),
(1,'Task1','SUBMITTED',NULL,'STARTED'),
(3,'Task3',NULL,NULL,'STARTED'),
(1,'Task1','APPROVED',NULL,'STARTED'),
(2,'Task2','APPROVED',NULL,'STARTED');
As #Larnu said you should use a criterion for choosing same id, based on my perspective it should be APPROVED>SUBMITTED>NULL for field1
hence I use ROW_NUMBER alphabetically and filter best values of Tasks_temp as follows:
SELECT id,
 NAME,
       field1,
       field2,
       field3
FROM   (SELECT id,
               NAME,
               field1,
               Row_number()
                 OVER (
                   partition BY NAME
                   ORDER BY IIF(field1 IS NULL, 'xxx', field1)) Stats,
               field2,
               field3
        FROM   tasks_temp) a
WHERE  stats = 1
That gives following table
id
name
field1
field2
field3
1
Task1
APPROVED
null
STARTED
2
Task2
APPROVED
null
STARTED
3
Task3
null
null
STARTED
Hence you should use the above written query as a subquery for use with the MERGE in order to facilitate the operation:
MERGE Tasks S
USING (SELECT id,
       NAME,
       field1,
       field2,
       field3
FROM   (SELECT id,
               NAME,
               field1,
               Row_number()
                 OVER (
                   partition BY NAME
                   ORDER BY Iif(field1 IS NULL, 'xxx', field1)) Stats,
               field2,
               field3
        FROM   tasks_temp) a
WHERE  stats = 1 ) SS
ON S.id=SS.id
WHEN MATCHED
THEN UPDATE SET S.name=SS.name, S.field1=SS.field1, S.field2=SS.field2, S.field3=SS.field3
WHEN NOT MATCHED
THEN INSERT (id, name, field1, field2, field3) VALUES (SS.id, SS.name, SS.field1, SS.field2, SS.field3)
dbfiddle

Update bulk number of records in oracle

I am new to sql. Can someone help me with this requirement.
I have table with 10000 records like this
CompanyID Name
300001 A
300004 B
300005 C
300007 D
|
|
|
310000 XXX
And I have a another list of companyIDs that I am going to update the above table(It is just an excel sheet not a table)
OldID NewID
300001 500001
300002 500002
300003 500003
300004 500004
300005 500005
|
|
310000 510000
My requirement is, If I found the companyID in the first table I need to update it with the NewID and If I didn't find the companyId in the first table I have to create a new row in the table with the NewID regardless of oldID.
Is there any possibility to do both update and insert in a single query?
You're describing an "upsert" or MERGE statement, typically:
merge into table_a
using (<some_statement>)
on (<some_condition>)
when matched then
update
set ...
when not matched then
insert (<column_list>)
values (<column_list>);
However, a MERGE can't update a value that's referenced in the ON clause, which is what will be required in order to do what you're asking. You will, therefore, require two statements:
update table_to_be_updated t
set companyid = (select newid from new_table where oldid = t.companyid )
insert into table_to_be_updated
select newid
from newtable t
where not exists ( select 1
from table_to_be_updated
where t.newid = companyid )
If it's possible for a newid and an oldid to be the same then you're going to run into problems. This also assumes that your new table is unique on oldid and newid - it has to be unique in order to do what you want so I don't think this is an unreasonable assumption.

Changing the values in a column with a value from the same column

Is it possible in access to select a record from a given column, and update that same column with the record you selected?
For example:
----column----
test
---------------
becomes
-----Column------
test
test
test
test
-------------------
Notice the blanks in the first table, and how in the second table those blanks were filled with the value that was in the first row. Is there a way to do this without having to specifically say "update to test"? I'm at a loss as to how to do this without telling Access that it needs to specifically update the blanks to "test".
This will do what you want:
UPDATE Table1, (SELECT TOP 1 Field1 As F FROM Table1 WHERE Field1 Is Not Null)
SET Field1 = F
WHERE Field1 Is Null
It handles several special cases safely:
If more than one row has a value in Fleld1, the value from the first such row is used.
The first row of the table need not have a value in Field1.
If none of the rows have a value in Field1, nothing bad will happen.
Before:
Field1 Field2
apple
pet cat
dog
color red
blue
After:
Field1 Field2
pet apple
pet cat
pet dog
color red
pet blue
Assuming you have:
a table MY_TABLE
a column COL_1
multiple records of which only one holds a value (not null) for COL_1
The update statement to fill COL_1 of all records with the non-null value :
update MY_TABLE
set COL_1 = (select COL_1 FROM MY_TABLE where COL_1 is not null)
where COL_1 IS NULL;

How to insert, update, delete when import data from table to table?

I have a query that I need to run more than once a day. This query is importing data from a database to another.
The target table structure is:
Id Date Department Location PersonId Starttime EndTime State
1 2012-01-01 2 5 200 12:00:00.000 15:00:00.000 2
An application can also insert data to the target table. The records that are inserted by the application may not be updated also when this record exists in the source(temp table) table with another state.
To make this possible I have an solution created. I will create an new column in the target table with a second state so that I can check.
Id Date Department Location PersonId Starttime EndTime State StateSource
1 2012-01-01 2 5 200 12:00:00.000 15:00:00.000 2 2
Some Requirements:
If a record is added by the application than StateSource will be NULL. Means that this record may not be deleted, updated or inserted again from the source table.
If a Record is updated by the application than the value State and StateSource will be different. In this case I do not update this record.
I will update if the state from the sourcetable and targettable are not same and the values from target table State = StateSource.
I will INSERT a record when this is not exists in the target table. When records already exists do not insert (no matter if this is added by the application or my query on the first run).
I will delete the records from the target when they are no more exists in my sourcetable and State=StateSource.
I already have the following queries. I have decided to make 3 statements.
--Delete Statement first
Delete from t
from TargetTable t LEFT JOIN SourceTable s ON t.Id=s.Id
and t.Date=s.Date
and t.departments=s.Department
and t.PersonId=s.PersonId
and t.State=t.StateSource
--Just delete if a date is no more exists from the source table and this records is NOT
--changed by the application (t.State=t.StateSource)
--Update statement second
Update t
set t.State = s.State
From Targettable t INNER JOIN SourceTable s ON t.Id=s.Id
and t.Date=s.Date
and t.departments=s.Department
and t.PersonId=s.PersonId
The problem here is:
--when I have State 2 already in the targettable and in my sourcetable i have
--another state then the state in the targettable changes. This would not be the case.
--Insert Statement thirth
insert into TargetTable (Id, Date, Department, Location, PersonId, Starttime, EndTime,State, StateSource)
select Id, Date, Department, Location, PersonId, Starttime, EndTime,State, StateSource
from SourceTable s
WHERE Date not in (select Date
from TargetTable t
where t.id=s.id
and t.PersonId=s.PersonId
and t.date=s.date
and t.department=s.department)
--I have no idea about how the insert should be because the application also can
--insert records. When a record exists then no insert. What to do with the State?
Remember that the states that are changed by the application are leading.
Can anyone help me with the desired result?
you may use a merge statement.. something like this...
with target_T as (select * from UR_TARGET_TABLE
where statesource is not null) -- to dont change the data inserted from application...
merge target_T as TARGET
using UR_SOURCE_TABLE as SOURCE
on SOURCE.id = TARGET.id -- id is unique? anyway, put your primary key here...
when matched and TARGET.state = TARGET.statesource then --if inserted/updated from application, will not change data
update set TARGET.state = SOURCE.state
,TARGET.statesource = SOURCE.state --important update it together to be different from an application update
--, other collumns that you have to set...
--should use another when matched then update if need to change something on inserted/updated from application data
when not matched by TARGET then
insert (Id, Date, Department, Location, PersonId, Starttime, EndTime,State, StateSource)
values(SOURCE.Id, SOURCE.Date, SOURCE.Department, SOURCE.Location, SOURCE.PersonId, SOURCE.Starttime, SOURCE.EndTime,SOURCE.State, SOURCE.StateSource);
if you set an sample with declaring your tables and inserting some data...
I should help more, with a code that really works.. not just a sample...

Insert into select and update in single query

I have 4 tables: tempTBL, linksTBL and categoryTBL, extra
on my tempTBL I have: ID, name, url, cat, isinserted columns
on my linksTBL I have: ID, name, alias columns
on my categoryTBL I have: cl_id, link_id,cat_id
on my extraTBL I have: id, link_id, value
How do I do a single query to select from tempTBL all items where isinsrted = 0 then insert them to linksTBL and for each record inserted, pickup ID (which is primary) and then insert that ID to categoryTBL with cat_id = 88. after that insert extraTBL ID for link_id and url for value.
I know this is so confusing, put I'll post this anyhow...
This is what I have so far:
INSERT IGNORE INTO linksTBL (link_id,link_name,alias)
VALUES(NULL,'tex2','hello'); # generate ID by inserting NULL
INSERT INTO categoryTBL (link_id,cat_id)
VALUES(LAST_INSERT_ID(),'88'); # use ID in second table
I would like to add here somewhere that it only selects items where isinserted = 0 and iserts those records, and onse inserted, will change isinserted to 1, so when next time it runs, it will not add them again.
As longneck said, you cannot do multiple things in one query, but you can in a stored procedure.
http://dev.mysql.com/doc/refman/5.1/en/insert-select.html
INSERT INTO linksTBL (link_id,link_name,alias)
SELECT field1, field2, field3
FROM othertable
WHERE inserted=0;
this is not possible to do in a single query. you will have to insert the rows, then run a separate update statement.