We have a legacy table
create table table1 (col1 int);
insert into table1 values(1);
insert into table1 values(2);
insert into table1 values(3);
SELECT * FROM table1;
1
2
3
now it gets a new column
alter table table1 add column col2 int;
alter table table1 ADD CONSTRAINT unique1 UNIQUE (col2);
SELECT * FROM table1;
1;null
2;null
3;null
then we have another table
create table table2 (col1 int);
insert into table2 values(7);
insert into table2 values(8);
insert into table2 values(9);
SELECT * FROM table2;
7
8
9
now we want to spread the values of table 2 into table1.col2
UPDATE table1 up
SET col2 = (SELECT col1
FROM table2 t2
WHERE NOT EXISTS (SELECT 1 FROM table1 t1 WHERE t1.col2=t2.col1)
LIMIT 1);
but the update statement does not see the already updated rows
ERROR: duplicate key value violates unique constraint "unique1"
Any ideas how to do that? It would be ok, if table1 remains with some rows col2=null if table2 has less rows than table1
This seems much easier with a join:
with t2 as (
select t2.*, row_number() over (order by col1) as seqnum
from table2 t2
)
update table1 t1
set col2 = t2.col1
from t2
where t1.col1 = t2.seqnum;
If col1 in table1 is not strictly sequential, you can still do this:
with t2 as (
select t2.*, row_number() over (order by col1) as seqnum
from table2 t2
),
t1 as (
select t1.*, row_number() over (order by col1) as seqnum
from table1 t1
)
update table1 toupdate
set col2 = t2.col1
from t1 join
t2
on t1.seqnum = t2.seqnum
where toupdate.col1 = t1.col1;
i think i found a solution
WITH rownumbers AS (
SELECT col1, row_number() over (partition by 1 ORDER BY col1) FROM table1
)
UPDATE table1 up SET col2 =
(SELECT col1 FROM table2 t2 WHERE NOT EXISTS (SELECT 1 FROM table1 t1 WHERE t1.col2=t2.col1)
LIMIT 1 OFFSET (
SELECT row_number-1 FROM rownumbers WHERE col1=up.col1
)
)
any cons about it?
Related
I have test table(1) with following values
Yet I have an update of this table called table(2) :
As you can see table(2) is similar table(1) but it has new values with new dates for each ID.
How should I use update command to update table1 based on new values of table2
In sql the fastest way to do so via a merge function, it will add the new rows to the table1 that are existing in table2 and not in table1.
merge into table1 t1
using table2 t2
on t1.id = t2.id
and t1.date = t2.date
when not matched then
insert (t1.id, t1.date, t1.value1, t1.value2 , t1.value3, t1.value4)
values (t2.id, t2.date, t2.value1, t2.value2 , t2.value3, t2.value4)
What I understood from your question is that you have multiple records for each id in table2 and you want the values against the latest row based on the data to be updated to table1. in such a case, you can try with a ROW_NUMBER or RANK function, just like this
;WITH CTE
AS
(
SELECT
RN = ROW_NUMBER() OVER(PARTITION BY ID ORDER BY Date DESC),
id,
date,
val1,
val2,
val3
FROM Table2
)
UPDATE T1
SET
Val1 = T2.Val1
Val2 = T2.Val2
FROM Table1 T1
INNER JOIN CTE T2
ON T1.id = T2.id
WHERE T2.RN = 1
Let's say I have two tables t1 and t2.
t1 has two integer cols col1 (primary) and col2
t2 has two cols a foreign key of t1.col1 and t2.col2
I want to do the following
Retrieve only the records where t1.col2 is unique OR if t1.col2 is duplicate only those if t2.col2 is not null.
Insert the above records into another summary table, let's say t3
This is what I tried:
insert into t3 (col1,col2)
select col1, col2
from t1
where t.col1 in (select A.col1 from t1 as A
group by 1
having count(*) > 1
union
select col1, col2
from t1, t2
where t.col1 in (select A.col1 from t1 as A
group by 1
having count(*) > 1
and t2.col2 is not null;
While the 'union qry' works on its own, the insert is not happening.
Any ideas or any other efficient way to achieve this please
You can select the records you want using:
select t1.*
from (select t1.*, count(*) over (partition by col2) as cnt
from t1
) t1
where cnt = 1 or
exists (select 1 from t2.col1 = t1.col1 and t2.col2 is null);
The rest is just an insert.
I have the following 2 table:
Col1|Col2|Col3
Val1 T1
Val2 T2
Col1|Col2|Col3|Col4
Val1 test 1
Val1 test 2
Val1 T1 3
Val2 test 1
Val2 T2 2
I need to update the values for Col3 of Table 1 with the summation of Col3 of table 2 until Col2 of Table 2 reaches the value from Col2 of Table 1. So, Table 1 should look like this:
Col1|Col2|Col3
Val1 T1 6
Val2 T2 3
So, it adds up 1+2+3 = 6 for T1 and 1+2 = 3 for T2.
Basically, the Col1 for both tables will be the key. I am using MSSQL2008 server. I tried to do this with Cursor but no luck so far.
Please note, the order by column in Table2 is a Date column (Column4). It is ordered by Desc.
You can get this by GROUP BY:
CREATE TABLE #Table1(Col1 VARCHAR(10),Col2 VARCHAR(10),Col3 INT)
CREATE TABLE #Table2(Col1 VARCHAR(10),Col2 VARCHAR(10),Col3 INT,Col4 DATETIME)
INSERT INTO #Table1 VALUES('Val1','T1',0)
INSERT INTO #Table1 VALUES('Val2','T2',0)
INSERT INTO #Table2 VALUES('Val1','test',1,GETDATE())
INSERT INTO #Table2 VALUES('Val1','test',2,GETDATE()-1)
INSERT INTO #Table2 VALUES('Val1','T1',3,GETDATE()-2)
INSERT INTO #Table2 VALUES('Val1','test',4,GETDATE()-3)
INSERT INTO #Table2 VALUES('Val2','test',1,GETDATE())
INSERT INTO #Table2 VALUES('Val2','T2',2,GETDATE()-1)
UPDATE T1
SET T1.Col3 = T2.SummationValue
FROM #Table1 T1
JOIN (
SELECT T2.Col1,T2.Col2,SUM(T2.Col3) OVER(PARTITION BY T2.Col1 ORDER BY Col4 DESC)SummationValue
FROM #Table2 T2
JOIN #Table1 T1 ON T2.Col1 = T1.Col1
)T2
ON T1.Col1 = T2.Col1 AND T1.Col2 = T2.Col2
SELECT * FROM #Table1
DROP TABLE #Table1
DROP TABLE #Table2
OutPut:
Col1 Col2 Col3
Val1 T1 6
Val2 T2 3
SQL Fiddle
This is a bit tricky. You can get the cutoff point using a correlated subquery:
update t1
set col3 = t2.sum_col3
from t1 join
(select t2.col1, sum(t2.col3) as sum_col3
from t2
where t2.t4 >= (select tt2.t4
from t2 tt2 join
t1 tt1
on tt2.col1 = tt1.col1 and
tt2.col2 = tt1.col2
)
group by t2.col1
) t2
on t2.col1 = t1.col1;
Alternatively, you can use window functions (but not a cumulative sum):
update t1
set col3 = t2.sum_col3
from t1 join
(select t2.col1,
sum(t2.col3) as sum_col3
from (select t2.col1,
min(case when tt2.col1 = tt1.col2 then tt2.col4 end) over (partition by tt2.col1) as col4_match
from t2 tt2 join
t1 tt1
on tt2.col1 = tt1.col1
) t2
where col4 >= col4_match
group by t2.col1
) t2
on t2.col1 = t1.col1
I want to find the entries where col2 record present in col1.
Table:
CREATE TABLE Test_Table
(
Col1 int,
Col2 int
);
Entries:
INSERT INTO Test_Table VALUES(111,112),
(112,113),
(114,115),
(116,117),
(117,118),
(118,119);
Expected Result:
Col1 Col2
-------------
111 112
112 113
116 117
117 118
118 119
Note: Record 114,115 not displyed because 115 is not present in col1.
My try:
WITH CTE1
AS
(
SELECT Col1, Col2
FROM Test_Table
),
CTE2
AS
(
SELECT t.Col1, t.Col2
FROM Test_Table t
INNER JOIN CTE1 s1
ON s1.Col2 = t.Col1
OR s1.Col2 = t.Col2
)
SELECT DISTINCT * FROM CTE2;
But getting all records.
This might also work
select t.*
from Test_Table t
where exists (select 1
from test_table t2
where t2.col1 = t.col2 or t2.Col2 = t.Col1
)
I think this is what you want.
select t.*
from #test_table t
where exists (select 1
from #test_table t2
where t2.col1 = t.col2
)
or exists (select 1
from #test_table t3
where t3.col2 = t.col1
);
I think you just want exists:
select tt.*
from test_table tt
where exists (select 1
from test_table tt2
where tt2.col1 = tt.col2
);
Using CROSS JOIN:
select t1.* from test_table t1 CROSS JOIN test_table t2
on t1.col1 = t2.col2
UNION
select t1.* from test_table t1 CROSS JOIN test_table t2
on t1.col2 = t2.col1
Based on your comments, I suspect you want either col1/col2 to exist at another row's either col1/col2
select tt.*
from test_table tt
where exists (select 1
from test_table tt2
where -- Ensure not same row
(tt2.col1 <> tt.col1 or tt2.col2 <> tt.col2)
and -- Ensure at least one match
(tt2.col1 = tt.col1 or tt2.col1 = tt.col2 or tt2.col2 = tt.col1 or tt2.col2 = tt.col2)
);
select t1.* from Test_Table t1 left join Test_Table t2 on t2.Col1=t1.Col2 where t2.Col2 is not null
union
select t1.* from Test_Table t1 left join Test_Table t2 on t2.Col2=t1.Col1 where t2.Col1 is not null
I have a complex stored procedure that is collecting data from many tables and inserting it into MyTable. It inserts over 1.5 M records.
What would be the most efficient way to create sequential ID number when populating MyTable
The structure of the table looks like this:
IF OBJECT_ID ('MyTable', 'U') IS NOT NULL
DROP TABLE MyTable;
SELECT *
INTO MyTable
FROM
(SELECT
col1, col2, col3
FROM
Table1
INNER JOIN
Table2 ON...
INNER JOIN
Table3 ON...
INNER JOIN
Table4 ON...
WHERE
Condition1,
Condition2) T
SELECT ID = IDENTITY(INT, 1, 1),* INTO MyTable FROM (
SELECT
col1,
col2,
col3
FROM Table1 INNER JOIN Table2 ON...
Table3 INNER JOIN Table4 ON...
WHERE Condition1,
Condition2
) T
ID = IDENTITY(INT, 1, 1) will create an identity ID that auto increments, i didnt test the code
I think simple row_number() is helpfull as below:
IF OBJECT_ID ('MyTable', 'U') IS NOT NULL
DROP TABLE MyTable;
SELECT * INTO MyTable FROM (
SELECT
RowNum = Row_Number() over (order by (Select NULL)) --Instead you can generate based on any column in the table
col1,
col2,
col3
FROM Table1 INNER JOIN Table2 ON...
Table3 INNER JOIN Table4 ON...
WHERE Condition1,
Condition2
) T
As Gabri demonstrated, you can use IDENTITY with a SELECT INTO statement. This will make that column and IDENTITY column. If you don't want it to be an IDENTITY column you can use ROW_NUMBER; this will work on any SQL 2005+ system.
SELECT ID = ROW_NUMBER() OVER (ORDER BY (SELECT NULL)), *
INTO MyTable FROM
(
SELECT
col1,
col2,
col3
FROM Table1 INNER JOIN Table2 ON...
Table3 INNER JOIN Table4 ON...
WHERE Condition1, Condition2
) T;