Insert rows in table while maintaining IDs - sql

TABLEA
MasterCategoryID MasterCategoryDesc
1 Housing
1 Housing
1 Housing
2 Car
2 Car
2 Car
3 Shop
TABLEB
ID Description
1 Home
2 Home
3 Plane
4 Car
INSERT into TableA
(
[MasterCategoryID]
[MasterCategoryDesc]
)
Select
case when (Description) not in (select MasterCategoryDesc from TableA)
then (select max(MasterCategoryID)+1 from TableA)
else (select top 1 MasterCategoryID from TableA where MasterCategoryDesc = Description)
end as [MasterCategoryID]
,Description as MasterCategoryDesc
from TableB
I want to enter rows using SQL/Stored Procedure from tableB to tableA. for example when inserting first row 'Home' it does not exist in MastercategoryDesc therefore will insert '4' in MasterCategoryID. Second row should keep the '4' again in MasterCategoryID.
The code below does it however after the first row the MastercategoryID remains the same for all rows. I Dont know how to keep track of ids while inserting the new rows.
p.s. Pls do not reply by saying i need to use IDENTITY() index. I have to keep the table structure the same and cannot change it. thanks

Create a new table your_table with fields x_MasterCategoryDesc ,x_SubCategoryDesc
Insert all your values in that table and the run the below SP.
CREATE PROCEDURE x_experiment
AS
BEGIN
IF object_id('TEMPDB..#TABLES') IS NOT NULL
BEGIN
DROP TABLE #TABLES
END
DECLARE #ROWCOUNT INT
DECLARE #ROWINDEX INT =0,
#MasterCategoryDesc VARCHAR(256),
#SubCategoryDesc VARCHAR(256)
select IDENTITY(int,1,1) as ROWID,*
into #TABLES
From your_table
SELECT #ROWCOUNT=COUNT(*) from #TABLES --where ROWID between 51 and 100
WHILE (#ROWINDEX<#ROWCOUNT)
BEGIN
set #ROWINDEX=#ROWINDEX+1
Select
#MasterCategoryDesc=x_MasterCategoryDesc,
#SubCategoryDesc=x_SubCategoryDesc
from #TABLES t
where rowid = #ROWINDEX
INSERT into Table1
([MasterCategoryID], [MasterCategoryDesc], [SubCategoryDesc], [SubCategoryID])
select TOP 1
case when #MasterCategoryDesc not in (select [MasterCategoryDesc] from Table1)
then (select max([MasterCategoryID])+1 from Table1)
else (select distinct max([MasterCategoryID]) from Table1
where [MasterCategoryDesc]=#MasterCategoryDesc
group by [MasterCategoryID])
end as [MasterCategoryID]
,#MasterCategoryDesc as [MasterCategoryDesc]
,#SubCategoryDesc as [SubCategoryDesc]
,case when #SubCategoryDesc not in (select [SubCategoryDesc] from Table1)
then (select max([SubCategoryID])+1 from Table1 )
else (select max([SubCategoryID]) from Table1
where [SubCategoryDesc]=#SubCategoryDesc
group by [SubCategoryID])
end as [SubCategoryID]
from Table1
END
select * from Table1 order by MasterCategoryID
END
GO
exec x_experiment --SP Execute
SQL FIDDLE

Use a CURSOR to do the work. The cursor loops through each row of TableA and the MasterCategoryID increases if it is not found in TableB. This happens before the next row of TableA is loaded into the cursor ...
DECLARE #ID int
DECLARE #Description VARCHAR(MAX)
DECLARE my_cursor CURSOR FOR
SELECT ID, Description FROM TableB
OPEN my_cursor
FETCH NEXT FROM my_cursor
INTO #ID, #Description
WHILE ##FETCH_STATUS = 0
BEGIN
INSERT into TableA(MasterCategoryID, MasterCategoryDesc)
SELECT CASE WHEN #Description NOT IN (SELECT MasterCategoryDesc FROM TableA)
THEN (SELECT MAX(MasterCategoryID)+1 FROM TableA)
ELSE (SELECT TOP 1 MasterCategoryID
FROM TableA
WHERE MasterCategoryDesc = #Description)
END AS MasterCategoryID, Description as MasterCategoryDesc
FROM TableB
WHERE ID = #ID
FETCH NEXT FROM my_cursor
INTO #ID, #Description
END

Your data structure leaves something to be desired. You shouldn't have a master id column that has repeated values.
But you can still do what you want:
INSERT into TableA ([MasterCategoryID], [MasterCategoryDesc])
Select coalesce(a.MasterCategoryId,
amax.maxid + row_number() over (partition by (a.MasterCategoryId) order by b.id)
),
coalesce(a.MasterCategoryDesc, b.desc)
from TableB b left outer join
(select desc, max(MasterCaegoryId) as maxid
from TableA a
group by desc
) a
on b.desc = a.desc left outer join
(select max(MasterCategoryID) as maxid
from TableA
) amax
The idea is to take the information from the master table when it is available. When not available, then MasterCategoryId will be NULL. A new id is calculated, using row_number() to generate sequential numbers. These are then added to the previous maximum id.

Related

SQL how to update the last row with a where conditon

Update table1 set status='open' where user='test' order by id DESC
i want to update the last row with a where conditon
You can use window function row_number() to get the first row in descending order of id.
with cte as
(
select *,row_number()over(order by id desc)rn from table1
)
Update cte set status='open' where user='test' and rn=1
Or you can use subquery to achieve same result:
UPDATE table1 SET status='open'
WHERE ID=(SELECT MAX(ID)FROM table1 where user='test') and user='test'
In order to find the record you want, you must first find the record you want and then change that record in the table. To do this, you need to create a temporary table and put the desired record in it, then update the table using the information obtained.
--Container to Insert Id which are to be iterated
Declare #temp1 Table
(
ID int
)
--Container to Insert records in the inner select for final output
Insert into #temp1
SELECT top 1 t.id FROM table1 t
WHERE t.user = 'test'
order by t.id desc
-- Keep track of #temp1 record processing
Declare #columnID int
Declare #columnValue varchar(100)
Begin
Set #columnID=(Select Top 1 id From #temp1)
Set #columnValue = 'open'
UPDATE table1 SET status = #columnValue WHERE id = #columnID
Delete #temp1 Where ID=#columnID
End
This should work, presume DBMS is MySQL
UPDATE table1
SET status = "open"
WHERE id in
(SELECT *
FROM
(SELECT id
FROM table1
WHERE USER = "test"
ORDER BY id DESC
LIMIT 1) tmp_tbl);

Update fetched rows in SQL Server

I have a stored procedure which looks like this:
alter procedure newProcedure
#take int,
#skip int
as
begin
set nocount on
declare #countRowNumbers int;
set #countRowNumbers = (select count(*) from TableA)
select *
from tableA a
order by a.ID
offset ISNULL(#skip,0) rows
fetch next ISNULL(#take, #countRowNumbers) rows only
--update only fetched rows (first 100, or second 100)
-- update TableA set Status = 2
end
I have column status which is representing if the row is under processing or not, so when I grab those 100 documents I need to update that Status status to 2.
How can I do that?
Combining the other answers, using an updatable CTE to carry out the update first, then using the output clause to capture the ID's updated and then select them to return.
declare #SelectedId table (id int);
with toupdate as (
select *
from tableA a
order by a.ID
offset isnull(#skip,0) rows
fetch next isnull(#take, #countRowNumbers) rows only
)
update toupdate
set [status] = 2
output Inserted.id into #SelectedId;
select *
from tableA
where ID in (select id from #SelectedId)
order by ID;
You should be able to use an updatable CTE for this:
with toupdate as (
select *
from tableA a
order by a.ID
offset ISNULL(#skip,0) rows
fetch next ISNULL(#take, #countRowNumbers) rows only
)
update toupdate
set status = 2;
alter procedure newProcedure
#take int,
#skip int
as
begin
set nocount on
declare #countRowNumbers int;
set #countRowNumbers = (select count(*) from TableA)
update tableA set status = 2 where ID in (
select a.ID
from tableA a
order by a.ID
offset ISNULL(#skip,0) rows
fetch next ISNULL(#take, #countRowNumbers) rows only )
--update only fetched rows (first 100, or second 100)
-- update TableA set Status = 2
end

How to add a row number to new table in SQL?

I'm trying to create a new table using an existing table already using:
INSERT INTO NewTable (...,...)
SELECT * from SampleTable
What I need to is add a record number at the beginning or the end, it really doesn't matter as long as it's there.
Sample Table
Elizabeth RI 02914
Emily MA 01834
Prospective New Table
1 Elizabeth RI 02914
2 Emily MA 01834
Is that at all possible?
This is what I ultimately I'm shooting for... except right now those tables aren't the same size because I need my ErrorTemporaryTable to have a column in which the first row has a number which increments by the previous one by one.
declare #counter int
declare #ClientMessage varchar(255)
declare #TestingMessage carchar(255)
select #counter = (select count(*) + 1 as counter from ErrorValidationTesting)
while #counter <= (select count(*) from ErrorValidationTable ET, ErrorValidationMessage EM where ET.Error = EM.Error_ID)
begin
insert into ErrorValidationTesting (Validation_Error_ID, Program_ID, Displayed_ID, Client_Message, Testing_Message, Create_Date)
select * from ErrorTemporaryTable
select #counter = #counter + 1
end
You can use into clause with IDENTITY column:
SELECT IDENTITY(int, 1,1) AS ID_Num, col0, col1
INTO NewTable
FROM OldTable;
Here is more information
You can also create table with identity field:
create table NewTable
(
id int IDENTITY,
col0 varchar(30),
col1 varchar(30)
)
and insert:
insert into NewTable (col0, col1)
SELECT col0, col1
FROM OldTable;
or if you have NewTable and you want to add new column see this solution on SO.
INSERT INTO NewTable (...,...)
SELECT ROW_NUMBER() OVER (ORDER BY order_column), * from SampleTable
If you are in SQL Server
INSERT INTO newTable (idCol, c1,c2,...cn)
SELECT ROW_NUMBER() OVER(ORDER BY c1), c1,c2,...cn
FROM oldTable
Try this query to insert 1,2,3... Replace MyTable and ID with your column names.
DECLARE #myVar int
SET #myVar = 0
UPDATE
MyTable
SET
ID = #myvar ,
#myvar = #myVar + 1

How to view the first 2 rows in to single row

How to view the first 2 rows in to single row
Table1
id name value size result
----------------------------------
001 rajan 100 280DD 100%
002 Vijayan 200 120DD 80%
003 Sidarth 300 150DD 90%
004 Rakesh 400 270DD 95%
...
I want to select first 2 row in to single row....
Expected Output
id id name name value value size size result result
---------------------------------------------------------
001 002 rajan vijayan 100 200 280DD 120DD 100% 80%
003 004 Sidarth Rakesh 300 400 150DD 270DD 90% 95%
.....
How to do this?
SELECT
t.Id, tt.Id, t.name, tt.name, t.value, tt.value, t.size, tt.size, t.result, tt.result
FROM YourTable t
INNER JOIN YourTable tt ON tt.Id = t.Id + 1
WHERE tt.Id % 2 = 0
That works for me. Hope it help you.
Please try that if you stil need help.
Declare #TempTable as table (FirstId int, SecondId int null, FirstCaption nvarchar(max), SecondCaption nvarchar(max) null, FirstDescription nvarchar(max), SecondDescription nvarchar(max) null)
DECLARE #TempId int
DECLARE curs CURSOR FOR
SELECT ID FROM Categories
open curs
fetch next from curs into #TempId
WHILE ##FETCH_STATUS = 0
begin
IF (#TempId % 2 = 1)
BEGIN
INSERT INTO #TempTable
SELECT
t.Id, null, t.Caption, null, t.Description, null
FROM categories t
WHERE t.Id = #TempId
END
ELSE
BEGIN
UPDATE #TempTable SET SecondId = t.Id, SecondCaption = t.Caption, SecondDescription = t.Description
FROM categories t
INNER JOIN #TempTable tt ON tt.FirstId = #TempId - 1
WHERE t.Id = #TempId
END
fetch next from curs into #TempId
end
close curs
deallocate curs
SELECT * FROM #TempTable
with cte as (
select row_number() over (order by id) as rn,
* from Table1
)
select a.id, b.id, a.name, a.value, b.value, a.size, b.size, a.result, b.result
from cte a join cte.b on a.id = b.id - 1
where a.rn <insert your criteria for which to show, for example in (1,3,5,7) or a modulus operator to see every 2nd row to avoid duplicate data>

T SQL Looping on insert or update

I have two tables.
Table A and Table B. The columns are same.
create table TableA (
id int
, name varchar
, last datetime
)
create table TableB (
id int
, name varchar
, last datetime
)
I m populating table A with mass data. and i would like to either insert or update the data in table A into table B.
I d like to take the data from table A and either insert into table B if id and name doenst match or update if the id and name does match.
I tried some ETL tool but the result was very slow. I have indexing on id and name, I wanted to try this with SQL.
I have the following but not working correct:
SELECT #id = ID,
#name = name,
#LSDATE = LastSeen_DateTime
FROM DBO.A
IF EXISTS (SELECT ID, name FROM DBO.A
WHERE #ID = ID AND #name = Name)
begin
-- update
end
else
begin
--insert
end
i guess i need to put this in a loop and not quite sure how I can make this run.
Thanks.
Its probably faster to do it two statements one update and one insert rather than a loop
This statement updates all B rows using the data from A where the ID is the same but the name is different
Update
Update
tableB
SET
name = a.Name
From
tableB a
INNER JOIN tableA a
on b.ID = a.ID
and A.Name <> b.Name
This statement inserts all B rows into A where the id doesn't exist in A
INSERT
INSERT INTO
tableB
( ID,
Name
)
SELECT
a.ID
a.Name
FROM
tableA b
WHERE
not exists (Select A.ID From tableB a WHERE a.ID = b.ID)
Updated (reversed it from A into B rather than B into A)
If you were using SQL Server 2008 (or Oracle or DB2), then you could use a merge statement.
MERGE B
USING A AS source
ON (B.ID = source.ID and B.Name = source.Name)
WHEN MATCHED THEN
UPDATE SET Last = source.Last
WHEN NOT MATCHED BY TARGET THEN
INSERT (ID, Name, Last) VALUES (source.ID, source.Name, source.Last)
-- the following is optional, if you remove it, add a semicolon to the end of the above line.
OUTPUT $action,
inserted.ID AS SourceID, inserted.Name AS SourceName,
inserted.Last AS SourceLast,
deleted.ID AS TargetID, deleted.Name AS TargetName,
deleted.Last AS TargetLast ;
The bit with the "output $action" will display what rows are getting updated and what rows are getting updated.
weasel words: I recognize this isn't exactly what you were looking for, but since others may search this topic, it may be helpful for others in the future.
DECLARE #id int
DECLARE #name nvarchar
DECLARE #last datetime
DECLARE TableA_Cursor CURSOR FOR
select id
, name
, last
from TableA;
OPEN TableA_Cursor;
FETCH NEXT from TableA_Cursor
INTO #id, #name, #last;
WHILE ##FETCH_STATUS = 0
BEGIN
IF (EXISTS select 1 from TableB b where b.Id = #id)
update TableB
set Name = #name
, Last = #last
ELSE
insert into TableB (Id, Name, Last)
values (#id, #name, #last)
FETCH NEXT from TableA_Cursor
INTO #id, #name, #last
END
CLOSE TableA_Cursor;
DEALLOCATE TableA_Cursor;
There may be some syntax error, particularly around the IF condition, but you may get the point.