I have a oracle table called table1 that has a foreign key from table2.
table2 has 2 columns: id, name
table2.name has a lot of duplicates that need to be sorted out, so I grouped table2 by name and kept only 1 id for each name.
However, table1.table2_id uses a lot of the duplicated fields.
How can I change all the table1.table2_id fields so that there are no duplicate names?
Currently:
table1:
id
blabla
table2_id
1
row
1001
2
row
1002
3
row
1003
4
row
1004
5
row
1004
6
row
1005
table2:
id
name
1001
Bob
1002
Bob
1003
Bob
1004
Jack
1005
Jack
Desired Result:
table1:
id
blabla
table2_id
1
row
1001
2
row
1001
3
row
1001
4
row
1004
5
row
1004
6
row
1004
table2:
id
name
1001
Bob
1004
Jack
So imo, I would need to:
update all table1.table2_id to top 1 table2.id grouped by name
delete duplicate rows from table2
And as there are thousands of duplicate fields in table2, I cannot use case for this..
The solution I am trying returns 1 id for each name, but I am failing at the part where I can update the table.
update table1 d
set d.table2_id =
(select
b.id
from table2 b
where b.name in (select min(id) keep(dense_rank first order by id) id
, name
from table2
group by name)
order by b.id ASC
)
where d.table2_id in ( SELECT b.id FROM table2 b WHERE b.name in (select min(id) keep(dense_rank first order by id) id
, name
from table2
group by name));
Please help :)
Here are syntactically correct Oracle statements
update table1 t1
set t1.table2_id = (
select new_id
from (
select id, min(id) over (partition by name) new_id
from table2
) d
where d.id = t1.table2_id
);
delete from table2
where id not in (
select min(id) from table2 group by name
);
The analytic function min(id) over (partition by name) is used here so that you can have all original ids together with their new ids (the min ids from the set where the name is the same).
here is one way:
update table1 d
set d.table2_id = x.id_tokeep
from
(
select name , id , min(id) over (partition by name ) as id_tokeep
from table2
) x
where x.id = d.table2_id
delete from table2
where id not in ( select min(id) from table2 group by name)
Related
I am trying to get all id, std_name from table1, and all id, score from table2 where std_id of table2 matches the id of table1 and deleted_at should be null for all entries of table1 and table2. But table2 can have duplicate std_ids, in that case, I only want the entries with the maximum id number from table2.
Sample table1:
id
std_name
deleted_at
1
jhon
null
2
sam
null
3
joe
null
Sample table2:
id
std_id
score
deleted_at
1
1
10
null
2
2
20
null
3
1
30
null
So far I have tried using this query:
const query = knex.select([
't1.id as t1id',
't1.std_name as name',
't2.score as score'
])
.from('table1 as t1')
.leftJoin('table2 as t2', function () {
this.on('t2.std_id', '=', 't1.id')
})
.joinRaw('left join (select MAX(id) as id, std_id from table2 group by std_id) as kst on kst.std_id = t2.std_id');
query.where({'t1.deleted_at': null}).orderBy('t1.id')
Results generated for the above query:
id
name
score
1
jhon
30
2
sam
20
But this only returns the maximum id entry of the duplicate entries from table2 and omits the entries of table1, but I also want the ids from table1 which are not included in the std_id of table2.
My desired output:
id
name
score
1
jhon
30
2
sam
20
3
joe
null
You can use window functions. In SQL this looks like:
select t1.*, t2.score
from table1 t1 left join
(select t2.*,
row_number() over (partition by t2.std_id order by t2.id desc) as seqnum
from table2 t2
) t2
on t2.std_id = t1.id and t2.seqnum = 1;
I have two tables: Table1 and Table2
Table1
id name value source
----------- ----------- ----- ------------
1 a 4 10
2 b 5 10
3 c 6 11
Table2
set text
----------- -----------
7 h
8 g
I want to copy the 'value' column to Table2 from Table1, where table1.source = 10
set text value
----------- ----------- ---------
7 h 4
8 g 5
I tried this:
ALTER TABLE Table2 ADD value INT NOT NULL DEFAULT 0
UPDATE tb2
SET tb1.value = tb2.value
from Table2 tb2
JOIN Table1 tb1
ON tb1.source=10
it has given me this :
id name value
----------- ----------- ---------
7 h 4
8 g 4
It's updating Table2 rows with only the first source value from Table1.
What am I doing wrong ?
Thanks in advance!
If you are using sQL server ,use the below query to update the table2.
Note that the script is specific to the given sample data.
ALTER TABLE Table2
ADD value INT NOT NULL DEFAULT 0
GO
WITH cte_data
as
(SELECT ROW_NUMBER() OVER(ORDER BY [set])RNo,*
FROM Table2 )
UPDATE c
SET c.Value=t.Value
FROM cte_data c
JOIN Table1 t on c.RNo=t.Id
WHERE t.Source=10
Maybe you can try this:
insert into table2 (value) select (value) from table1 where table1.source = 10
Just add new "value" field in "table2" and try this approach.
You need a row number for the join. I would advise putting this in both tables:
WITH toupdate AS (
SELECT tb1.*,
ROW_NUMBER() OVER (PARTITION BY source ORDER BY id) as seqnum
FROM table1 tb1
)
UPDATE toupdate
SET tb1.value = tb2.value
FROM toupdate tb1 JOIN
(SELECT tb2.*,
ROW_NUMBER() OVER (ORDER BY set) as seqnum
FROM table2 tb2
) tb2
ON tb2.seqnum = tb1.seqnum
WHERE tb1.source = 10;
I have following senario
table1 - having 1 record with 1001(primary key)
table2 - having 3 record with same id (1001) - not as primary key
table3 - having 3 record with same id (1001) - not as primary key
The join of the first 2 tables is returning 3 rows (it is fine). But, if I join table3 then it is returning 9 rows. I know how join work and result is expected.
I need only 3 rows in result. something like shown below
id name age sex city
1001 Jhon 20 A Z
1001 Jhon 20 B Y
1001 Jhon 20 C X
Here is fiddle example
This query may do what you ask for. To change the combination between Table2 and Table3 you can work on the two ORDER BY clauses. Really strange requierement anyway! Are you sure you're doing it right?
with ord_t2 as (
select idt1 as id, sex, row_number() over(partition by idt1 order by sex) as ord_no
from table2 t2
), ord_t3 as (
select idt3 as id, city, row_number() over(partition by idt3 order by city) as ord_no
from table3 t3
), t2_x_t3 as (
select id, sex, city
from ord_t2
natural full outer join ord_t3
)
select *
from Table1
natural left join t2_x_t3
I have three tables: Table1, Table2, Table1Table2Mapping.
Each tabel1 data having multiple data in tabel1, this table1 relation table2 is done through the mapping table the Primary key of the table1 and table2 is put in mapping table.
Table1:
Table1_ID Name ,Other columns
--------- ---- ------
1 Name1
2 Name2
3 Name3
Table2:
Table2_ID Title
--------- -----
101 Title1
102 Title2
103 Title3
104 Title4
105 Title5
Table1Table2Mapping:
Table1_ID Table2_ID
--------- ------------
1 101
1 102
2 103
3 104
3 105
I am getting all the related rows from table1 and its relation in table1 through mappping table
I need to select single row for each Table1 row.
Like this
Table1_ID Name Title
--------- ------- -----
1 Name1 Title1
2 Name2 Title3
3 Name3 Title4
The CROSS APPLY will do the trick:
SELECT
T1.Table1_ID
, T1.Name
, TMP.Title
FROM
Table1 T1
CROSS APPLY (
SELECT TOP(1)
T2.Title
FROM
Table2 T2
INNER JOIN Table1Table2Mapping TTM
ON T2.Table2_ID = TTM.Table2_ID
WHERE
TTM.Table1_ID = T1.Table1_ID
ORDER BY
TTM.TAble2_ID ASC -- You can change this order to what you want
) TMP
You can change the order of the subquery.
SQL Fiddle
Using CROSS APPLY in TechNet
EDIT
IF it is enough, you can use aggregation too:
SELECT
T1.Table1_ID
, T1.Name
, MIN(T2.Title) -- You can use MAX
FROM
Table1 T1
INNER JOIN Table1Table2Mapping TTM
ON TTM.Table1_ID = T1.Table1_ID
INNER JOIN Table2 T2
ON T2.Table2_ID = TTM.Table2_ID
GROUP BY
T1.Table1_ID
, T1.Name
(This gives the same result for the provided dataset, but in real life, the result of this and the previous solution mostly different!
use outer apply in sql server 2005 and later
Select Table1.*, ttt.Title From Table1 Outer Apply
(Select Top 1 Table2.* From Table2 Inner Join Table1Table2Mapping
On Table2.Table2_Id = Table1Table2Mapping.Table2_Id
Where Table1.Table1_Id = Table1Table2Mapping.Table1_Id) ttt
There are multiple way to get first row from each group, but none of my idea is working with access2010.
Do you have a solution to get first row in access2010 ?
Or
ID Name Age
1 Name1 3
2 Name2 4
3 Name1 2
4 Name2 5
It should get the top row in each group (name column) so the output would be
1 Name1 3
2 Name2 4
Here's a solution that still uses a sub query, but only once, instead of on each record.
SELECT T1.*
FROM mytable AS T1
WHERE T1.id IN (SELECT First(T2.id)
FROM mytable T2
GROUP BY T2.name)
select * from table t1 where ID in
(sel min(ID) from table where t1.name=name);