update one table with data from another using derived key value - sql

Table 1:
id name desc
------------------
1 a abc
2 b def
3 c adf
Table 2:
name desc
------------
x 123
y 345
How do I run an sql update query that can update Table 1 with Table 2's name and desc using the id of table 1 and rownum in table2? It's okay to assume that rownum in table2 is the same as id of table 1. So the end result I would get is
Table 1:
id name desc
------------------
1 x 123
2 y 345
3 c adf
Below are scripts for table creation and record insertion
create table table1 (
id number,
name varchar2(10),
desc_ varchar2(10)
);
create table table2 (
name varchar2(10),
desc_ varchar2(10)
);
insert into table1 values(1, 'a', 'abc');
insert into table1 values(2, 'b', 'def');
insert into table1 values(3, 'c', 'ghi');
insert into table2 values( 'x', '123');
insert into table2 values( 'y', '456');
Credits to "update one table with data from another"

There is no such thing as "rownum" in a table. SQL tables represent unordered sets, so there is no ordering without an ordering column.
Oracle does provide rowid as a built-in column identifier. This is not the same as rownum and is not guaranteed to be in order.
You can use rownum, but the value is not guarantee to have any particular meaning and might change between runs:
update table1
set (name, desc) = (select name, desc
from (select t2.*, rownum as seqnum
from table2
) t2
where seqnum = table1.id
)
where id <= (select count(*) from table2);

Related

inserte data with incremented values

I have this table tab1
name
-----
'big'
'smal'
'bird'
tab2
id name
-- ---
1 empty
2 empty
3 empty
4 empty
I want to insert the name from tab1 to tab2 with incremented id
this is desired result
id name
-- ---
1 empty
2 empty
3 empty
4 empty
5 'big'
6 'smal'
7 'bird'
The correct way to handle this is for table2 to define id as an identity column. You do this when you define the table:
create table table2 (
id int identity primary key,
. . .
Then you can simply do:
insert into table2(name)
select name
from table1;
You should consider defining the table correctly, if it is not. But, you can also do this in more recent versions of Sybase doing:
insert into table2(name)
select maxid + row_number() over (order by name), name
from table1 cross join
(select max(id) as maxid from table2) x;
Note: This will assign the id values in alphabetical order.

PostgreSQL : Get first and last inserted record for each ID column

I have the following table with two columns.
Table:
create table tbl1
(
p_id int,
p_price int
);
Insertion:
INSERT INTO tbl1 values(1,100);
INSERT INTO tbl1 values(1,50);
INSERT INTO tbl1 values(1,20);
INSERT INTO tbl1 values(2,10);
INSERT INTO tbl1 values(2,20);
INSERT INTO tbl1 values(3,22);
INSERT INTO tbl1 values(3,89);
INSERT INTO tbl1 values(3,500);
Query: Following query gives me the row number of each row.
SELECT p_id,p_price,row_number() over(partition by p_id order by p_id) rn
from tbl1
I want to get only first and last inserted record for each product id (p_id).
Expected Result:
p_id p_price
-----------------
1 100
1 20
2 10
2 20
3 22
3 500
You can do this using subquery:
SELECT p_id, p_price, rn from (
SELECT *, last_value(rn) over(partition by p_id) as last from (
SELECT p_id,p_price,row_number() over(partition by p_id order by p_id) rn
FROM tbl1
) s1
) s2 where rn=1 or rn=last;
So at inner select you get the row number by partition, one level up you get the last row numbers (first is always 1).
Then the top level can do the filter.

Update one field in a table in reference to another field on the same table Oracle

I need to Update a varchar2 field with sequential values e.g 001, 002, 002 in reference to another field entity_id on the same table. I need it such that if for example I have the same entity_id on two different rows, then the sequential values should be the same.
An example output:
Entity_id Seq_field
1234 001
1234 001
4567 002
4567 002
3412 003
I have tried with rownum but it gives different values for each entity_id and of course the values do not have the trailing zero. Please help.
merge into the_table
using
(
select rowid as rid,
entity_id,
to_char(dense_rank() over (order by entity_id), 'FM00000') as seq
from foo
) t on (the_table.rowid = t.rid)
when matched
then update set seq_field = t.seq;
If you want to start a new sequence for each entity_id you need to change the statement slightly:
merge into foo
using
(
select rowid as rid,
entity_id,
to_char(row_number() over (partition by entity_id order by null), 'FM00000') as seq
from foo
) t on (foo.rowid = t.rid)
when matched
then update set seq_field = t.seq;
Note that I used row_number() instead of dense_rank() and partition by entity_id to restart the numbering with each new value of entity_id. If you have another column that would determine the "order" for one entity_id, then you can replace the null in order by null with that column e.g. order by created_at
How many records do you have? Below is a solution I came up with, but won't work nicely with large set of data.
CREATE TABLE tab (entity_id NUMBER, seq_field VARCHAR2(3));
INSERT INTO tab VALUES (1234, NULL);
INSERT INTO tab VALUES (1234, NULL);
INSERT INTO tab VALUES (4567, NULL);
INSERT INTO tab VALUES (4567, NULL);
INSERT INTO tab VALUES (3412, NULL);
UPDATE tab t SET seq_field = (
SELECT LPAD(rnk, 3, '0')
FROM (
SELECT entity_id, seq_field, DENSE_RANK() OVER (ORDER BY entity_id) AS rnk
FROM tab
) t2
WHERE t2.entity_id = t.entity_id AND rownum = 1
);
Check at SQLFiddle: http://sqlfiddle.com/#!4/3959d/1
Consider adding both SQL and ORACLE tags to your question, guess you'll get more attention and perhaps a better solution.

SQL Server insert with row N referencing the identity of the N - 1 row. Possible?

I have a SQL Server 2008 DB with a table like this (Table1):
ID ParentID Name
-- -------- ---
11 NULL Foo
12 11 Bar
13 12 etc
ID is declared with IDENTITY.
I have the values Foo, Bar, etc as rows in another table (Table2) and I must insert them in Table1.
The inserted values must be in a parent child relation in Table1, with ParentID column from row N pointing to ID of row N-1.
Is it possible with one statement to insert the values with the relations between them?
-- Insert all names in first table
insert Table1
(Name)
select Name
from Table2
-- For each row in Table1,
-- Search for the matching row in Table2,
-- Then look up the "parent" row in Table2,
-- And back to Table1 for the "parent" id
update t1
set ParentID = t1_parent.ID
from Table1 t1
join Table2 t2
on t1.Name = t2.name
cross apply
(
select top 1 *
from Table2 t2_parent
where t2_parent.ID < t2.ID
order by
t2_parent.ID desc
) t2_parent
join Table1 t1_parent
on t1_parent.Name = t2_parent.Name
Since you asked if you could do this in one statement, here is an answer for that. I can't help but feel that if you had given more information I would be telling that whatever you're doing this for should be solved another way. I'm having a hard time coming up with a good reason to do this. Here is a way to do it regardless though:
I am assuming Table1 has Id, ParentId, and Name, and that Table2 has Id and Name (you said you got the names Foo, Bar, whatever from Table2). I'm also assuming there is some order you can impose.
CREATE TABLE #T
(
Id INT IDENTITY(1, 1)
, ParentId INT
, Name VARCHAR(100)
)
CREATE TABLE #T2
(
Id INT IDENTITY(1, 1)
, Name VARCHAR(100)
)
INSERT #T2
(
Name
)
VALUES ('Foo'), ('Bar')
INSERT #T
(
ParentId
, Name
)
SELECT
NULLIF(IDENT_CURRENT('#T')
+ ROW_NUMBER() OVER(ORDER BY T2.Name)
- 2, (SELECT ISNULL(MIN(Id), 1) - 1 FROM #T))
, T2.Name
FROM #T2 T2
SELECT * FROM #T
DROP TABLE #T
DROP TABLE #T2

How to create a view which merges two tables?

I have two tables which have the exact same structure. Both tables can store the same data with different primary keys (autoincremented integers). Therefore, there is a third table which lists which two primary keys list the same data. However, there also exist rows which don't exist in the other. Therefore, a simple join won't work since you will have two rows with the same primary key but different data. Therefore, is there a way of reassigning primary keys to unused values in the view?
Table1
ID name
1 Adam
2 Mark
3 David
4 Jeremy
Table2
ID name
1 Jessica
2 Jeremy
3 David
4 Mark
Table3
T1ID T2ID
2 4
3 3
4 2
I am looking for a result table like the following:
Result
ID name
1 Adam
2 Mark
3 David
4 Jeremy
5 Jessica
The real heart of the question is how i can assign the temporary fake id of 5 to Jessica and not just some random number. The rule I want for the ids is that if the row exists in the first table, then use its own id. Otherwise, use the next id that an insert statement would have generated (the column is on autoincrement).
Answer to edited question
select id, name from table1
union all
select X.offset + row_number() over (order by id), name
from (select MAX(id) offset from table1) X
cross join table2
where not exists (select * from table3 where t2id = table2.id)
The MAX(id) is used to "predict" the next identity that would occur if you merged the data from the 2nd table into the first. If Table3.T2ID exists at all, it means that it is already included in table1.
Using the test data below
create table table1 (id int identity, name varchar(10))
insert table1 select 'Adam' union all
select 'Mark' union all
select 'David' union all
select 'Jeremy'
create table table2 (id int identity, name varchar(10))
insert table2 select 'Jessica' union all
select 'Jeremy' union all
select 'David' union all
select 'Mark'
create table table3 (t1id int, t2id int)
insert table3 select 2,4 union all
select 3,3 union all
select 4,2
Answer to original question below
So the 3rd table is the one you want to build (a view instead of a table)?
select newid=row_number() over (order by pk_id), *
from
(
select a.*
from tblfirst a
UNION ALL
select b.*
from tblsecond b
) X
The data will contain a unique newid value for each record, whether from first or second table. Change pk_id to your primary key column name.
Assuming you have below data, as I understand reading your question:
Table: T1
ID name
--------
1 a
2 b
3 c
Table: T2
ID name
--------
2 b
3 c
4 d
Table: Rel
ID1 ID2
--------
2 2
3 3
T1 has some data which is not in T2 and vice versa.
Following query will give all data unioned
SELECT ROW_NUMBER() OVER (order by name) ID, Col
from
(
SELECT ISNULL(T1.name,'') name
FROM T1 t1 LEFT JOIN Rel TR ON TR.ID1 = T1.ID
union
SELECT ISNULL(T2.name,'') name
FROM T2 t2 LEFT JOIN Rel TR ON TR.ID2 = T2.ID
) T
If I understand you correct, following might work
Select everything from your first table
Select everything from your second table that is not linked to your third table
Combine the results
Test data
DECLARE #Table1 TABLE (ID INTEGER IDENTITY(1, 1), Value VARCHAR(32))
DECLARE #Table2 TABLE (ID INTEGER IDENTITY(1, 1), Value VARCHAR(32))
DECLARE #Table3 TABLE (T1ID INTEGER, T2ID INTEGER)
INSERT INTO #Table1 VALUES ('Adam')
INSERT INTO #Table1 VALUES ('Mark')
INSERT INTO #Table1 VALUES ('David')
INSERT INTO #Table1 VALUES ('Jeremy')
INSERT INTO #Table2 VALUES ('Jessica')
INSERT INTO #Table2 VALUES ('Jeremy')
INSERT INTO #Table2 VALUES ('David')
INSERT INTO #Table2 VALUES ('Mark')
INSERT INTO #Table3 VALUES (2, 4)
INSERT INTO #Table3 VALUES (3, 3)
INSERT INTO #Table3 VALUES (4, 2)
SQL Statement
SELECT ROW_NUMBER() OVER (ORDER BY ID), t1.Value
FROM #Table1 t1
UNION ALL
SELECT ROW_NUMBER() OVER (ORDER BY ID) + offset, t2.Value
FROM #Table2 t2
LEFT OUTER JOIN #Table3 t3 ON t3.T2ID = t2.ID
CROSS APPLY (
SELECT Offset = COUNT(*)
FROM #Table1
) offset
WHERE t3.T2ID IS NULL