Update values from multiple selected rows - sql

I have 2 tables. Both have the same amount of rows.
Sample data:
Table1{
Id, IdTable2Row
}
Table2 {
Id, RedChicken -- LOL
}
Each row of Table1 (column IdTable2Row) should get the id of 1 row of table 2 (irrelevant which one).
Table1.IdTable2Row is null in every row before the operation.
How can I do something like this?
UPDATE Table1 SET IdTable2Row = (SELECT Id FROM [Table2])

update T1
set idtablerow = t2.id
from Table1 T1
inner join Table2 T2
on T1.something = T2.something
In your case, with no common column:
with T1 as
(
select Table1.*, row_number() over (order by anycolumn) rn
from Table1
)
update T1
set idtablerow = t2.id
from T1
inner join
(
select x1.*, row_number() over (order by id) rn
from Table2 x1
) T2
on t1.rn = t2.rn
Should work

If I understand correctly you need to match rows 1 to 1. Here is a solution I come up with:
declare #Table1 table(
Id INT,
IdTable2Row INT NULL
)
declare #Table2 table(
Id INT, RedChicken varchar(10) -- LOL
)
INSERT INTO #Table1
VALUES
(
1,NULL
),(
2,NULL
),(
3,NULL
);
INSERT INTO #Table2
VALUES
(
10,'s'
),(
20,'a'
),(
30,'b'
);
SELECT *
FROM #Table1 ;
SELECT *
FROM #Table2;
WITH cte1 AS
(
SELECT
ROW_NUMBER() over(ORDER by Id) AS rown
,Id
,IdTable2Row
FROM #Table1
),
cte2 AS
(
SELECT ROW_NUMBER() over(ORDER by Id) AS rown
,Id
,RedChicken
FROM #Table2
)
UPDATE t
SET IdTable2Row = c2.Id
FROM #Table1 t
JOIN cte1 c1 ON c1.Id = t.Id
JOIN cte2 c2 ON c1.rown = c2.rown
SELECT *
FROM #Table1

IN SQL SERVER if there is common column then you can join the table and update
update a set a.IdTable2Row=b.Id from
Table1 a ,Table2 b
where a.column=b.column

Related

Sub-query producing multiple rows error - Need multiple rows to be selected - SQL

I have a scenario. Below are my 3 tables:
create table #cdes(client_id int,identifier int)
insert #cdes values(9908,789654123)
create table #temp1
(
client_id int,
identifier int,
pp_id int,
ch_id int,
code varchar(20),
program varchar(20),
startdate date,
enddate date,
ssc varchar(50)
)
insert into #temp1
values (9908,789654123,1567,1566,'OP','xASMT','1/1/2019','1/4/2019','A201901044F010134NNN01D 151 143 093 ')
-------------------------------------------
create table #temp2
(
client_id int,
identifier int,
pp_id int,
ch_id int,
code varchar(20),
program varchar(20),
startdate date,
enddate date,
ssc varchar(20)
)
insert into #temp2
values(9908,789654123,1574,1573,'OP','SU1','1/1/2019','1/4/2019',NULL)
I have a case condition in my final select query as my query revolves around multiple conditions.Most case conditions throw only one row as output however, I want to report multiple lines for a specific scenario.
My desired output:
My query:
select
d.client_id,
case when d.client_id = 9908
then
(
select CONCAT(t1.code,t1.startdate,t1.enddate,t1.ssc)
from #temp1 t1
left join #temp2 t2 on t1.client_id = t2.client_id and t1.identifier = t2.identifier
union all
select CONCAT(t2.code,t2.startdate,t2.enddate,t2.ssc)
from #temp1 t1
left join #temp2 t2 on t1.client_id = t2.client_id and t1.identifier = t2.identifier)
end
from #cdes d
left join #temp1 t1 on d.client_id = t1.client_id
left join #temp2 t2 on d.client_id = t2.client_id
The problem is Unionall is producing myltiple rows that I am finding difficult to accommodate in my select statement. Any help?!
This case condition is fake. I have included for just a sample.
You already have the subquery so just add the condition after where:
select t.* from (
select t1.client_id client_id, t1.identifier identifier, CONCAT(t1.code,t1.startdate,t1.enddate,t1.ssc) ssc_concatenated
from #temp1 t1
union all
select t2.client_id client_id, t2.identifier identifier, CONCAT(t2.code,t2.startdate,t2.enddate,t2.ssc) ssc_concatenated
from #temp2 t2) t
where t.client_id in (select client_id from #cdes)
or
where t.client_id = 9908
Or you can add the condition directly in each part of the subquery:
select t.* from (
select t1.client_id client_id, t1.identifier identifier, CONCAT(t1.code,t1.startdate,t1.enddate,t1.ssc) ssc_concatenated
from #temp1 t1
where t1.client_id = 9908
union all
select t2.client_id client_id, t2.identifier identifier, CONCAT(t2.code,t2.startdate,t2.enddate,t2.ssc) ssc_concatenated
from #temp2 t2
where t2.client_id = 9908
Don't put a UNION ALL query in your subquery. make your entire query a UNION ALL query.
Instead of:
SELECT ColA, ColB, (
SELECT CalculationX FROM MyTable
UNION ALL
SELECT CalculationY FROM MyTable
) AS ColC
FROM MyTable
You need something like this:
SELECT ColA, ColB, CalculationX AS ColC FROM MyTable
UNION ALL
SELECT ColA, ColB, CalculationY AS ColC FROM MyTable

SQL. Joining records from 3 or more tables based on dates

My tables look like this(just an example):
table1:
TIME |data1
1.01.2018|aaa
2.01.2018|bbb
table2:
TIME |data2
1.01.2018|abcd
2.01.2018|cd
table3:
TIME |data3
1.01.2018|
2.01.2018|d
Now what i would like to do is take the data from table2 and put it in the table1 where there are missing records. If there is no record in all tables for that date, then the data in data column is NULL. The data copied to table1 needs to be the same date as in the table2. and if there is no same date in table1 as it is in table2, that date is created.
So far i have tried with this code, but the data copied is not valid. If there is a missing day in some of the tables, that missing day is created in time column, but the data in data column is incorect.
SELECT DISTINCT table1.time,table1.data,table2.time,table2.data,table3.time,table3.data
FROM table1
LEFT JOIN table2 ON table1.time=table2.time
LEFT JOIN table3 ON table1.time=table3.time
EDIT
This is how the output should look like:
For example, there was no data in table3 for data3 for that specific date, so the cell is empty.
TIME |data1|data2|data3|
1.01.2018|aaa |abcd | |
2.01.2018|bbb | cd | d |
You need a full join instead of a left join. (you didn't specify the backend. Here the sample is with MS SQL) ie:
SELECT
coalesce(table1."time",table2."time", table3."time") as "time",
table1.data1,table2.data2,table3.data3
FROM table1
full JOIN table2 ON table1."time"=table2."time"
full JOIN table3 ON table1."time"=table3."time" ;
Output:
Time data1 data2 data3
1.01.2018 aaa abcd (null)
2.01.2018 bbb cd d
EDIT: The distinct in your code suggests you want only one row per day. Then it is not clear which column value should be used. Assuming any would do, you can do aggregation like this:
SELECT
coalesce(table1."time",table2."time", table3."time") as "time",
max(table1.data1) as data1,
max(table2.data2) as data2,
max(table3.data3) as data3
FROM table1
full JOIN table2 ON table1."time"=table2."time"
full JOIN table3 ON table1."time"=table3."time"
group by coalesce(table1."time",table2."time", table3."time");
Start the process with
SELECT [DISTINCT] TIME FROM TABLE1
UNION [DISTINCT]
SELECT [DISTINCT] TIME FROM TABLE2
UNION [DISTINCT]
SELECT [DISTINCT] TIME FROM TABLE3
And then LEFT JOIN the three tables to that.
Try this:
with cte as (Select time from table1 union Select time from table2 union Select time from table3)
SELECT cte.time,table1.data as data1,table2.data as data2,table3.data as data3
FROM cte
LEFT JOIN table1 ON table1.time=cte.time
LEFT JOIN table2 ON cte.time=table2.time
LEFT JOIN table3 ON cte.time=table3.time
Apply simple left join after union on.
DECLARE #t1 table
(
TIMEDate1 DATE
,Data1 VARCHAR(50)
)
DECLARE #t2 table
(
TIMEDate2 DATE
,Data2 VARCHAR(50)
)
DECLARE #t3 table
(
TIMEDate3 DATE
,Data3 VARCHAR(50)
)
insert #t1 (TIMEDate1,Data1 ) select getdate(),'aaa'
insert #t1 (TIMEDate1,Data1 ) select getdate()+1,'bbb'
insert #t2 (TIMEDate2,Data2 ) select getdate(),'abcd'
insert #t2 (TIMEDate2,Data2 ) select getdate()+1,'cd'
insert #t3 (TIMEDate3,Data3 ) select getdate(),''
insert #t3 (TIMEDate3,Data3 ) select getdate()+1,'d'
SELECT t.TIMEDate,t1.Data1,t2.Data2,t3.Data3
FROM (
SELECT distinct TIMEDate1 as TIMEDate FROM #t1
UNION
SELECT distinct TIMEDate2 as TIMEDate FROM #t2
UNION
SELECT distinct TIMEDate3 as TIMEDate FROM #t3
) t
left JOIN #t1 t1 ON t1.TIMEDate1 = t.TIMEDate
left JOIN #t2 t2 ON t2.TIMEDate2 = t.TIMEDate
left JOIN #t3 t3 ON t3.TIMEDate3 = t.TIMEDate
--order by t1.TIMEDate1 asc
The SQL below is just an alternative for inserting the missing dates into Table1.
--
-- insert those into Table1 that are in Table2 but not in Table1
--
insert into Table1 ("time", data1)
select "time", data2
from Table2 as t2
where not exists
(
select 1
from Table1 as t1
where t1."time" = t2."time"
);
--
-- insert those into Table1 that are in Table3 but not in Table1
--
insert into Table1 ("time", data1)
select "time", data3
from Table3 as t3
where not exists
(
select 1
from Table1 as t1
where t1."time" = t3."time"
);
Then add the dates that are still missing in Table1 after all that.
Below is an example for MS SQL Server :
;with RCTE_DATERANGE as
(
select min([time]) as dt, max([time]) as max_dt
from Table1
union all
select dateadd(day, 1, dt), max_dt
from RCTE_DATERANGE where dt < max_dt
)
insert into Table1 ([time])
select dt
from RCTE_DATERANGE AS rcte
where not exists
(
select 1
from Table1 as t1
where t1.[time] = rcte.dt
);
-- Just checking
;with RCTE_DATERANGE as
(
select min([time]) as dt, max([time]) as max_dt
from Table1
union all
select dateadd(day, 1, dt), max_dt
from RCTE_DATERANGE where dt < max_dt
)
select rcte.dt, t1.[time] as time1, t2.[time] as time2, t3.[time] as [time3], t1.data1, t2.data2, t3.data3
from RCTE_DATERANGE AS rcte
full join Table1 t1 on t1.[time] = rcte.dt
full join Table2 t2 on t2.[time] = rcte.dt
full join Table3 t3 on t3.[time] = rcte.dt;

Query for earliest datetime and corresponding number field

I'm attempting to update a table with a dollar amount based on the earliest datetime field from another table. For example:
Table 1
ID|INITIAL_ANNUAL_RATE_AMT|
1 | NULL (I want to update this to 25.02)
Table 2
ID|ANNUAL_RATE_AMT|STARTING_DATE|
1 |25.01 |1/1/2014
1 |25.02 |1/1/2013
I've got a query like this that retreives the earliest date from table 2 and the corresponding objects ID:
select ID,
MIN(t2.STARTING_DATE) as EARLIEST_START_DATE
from t2
group by t2.ID
But how can I leverage this into an update statement that sets the INITIAL_ANNUAL_RATE_AMT in table 1 to the earliest corresponding value in table 2?
Something like this (which currently fails):
update t1
set t1.Initial_Annual_Rate__c = t3.ANNUAL_RATE_AMT
from t1, t2
left join
(select t2.ID
MIN(t2.STARTING_DATE) as EARLIEST_START_DATE
from t2
group by t2.DEAL_ID)
as t3 ON (t3.DEAL_ID = t1.DEAL_ID)
One way is to use a CTE
;WITH C AS(
SELECT t.ID, EARLIEST_START_DATE, ANNUAL_RATE_AMT FROM(
select ID,
MIN(t2.STARTING_DATE) as EARLIEST_START_DATE
from #Table2 AS t2
group by t2.ID) t
INNER JOIN #Table2 AS t2 ON t2.ID = t.ID AND t.EARLIEST_START_DATE = t2.STARTING_DATE
)
UPDATE t1
SET INITIAL_ANNUAL_RATE_AMT = C.ANNUAL_RATE_AMT
FROM #Table1 AS t1
INNER JOIN C ON C.ID = t1.ID
SQLFIDDLE
Another method, using a window function to get the first row in each ID partitioned set:
-- Setup test data
declare #table1 table (ID int, INITIAL_ANNUAL_RATE_AMT decimal(9,2))
declare #table2 table (ID int, ANNUAL_RATE_AMT decimal(9,2), STARTING_DATE date)
INSERT INTO #table1 (ID, INITIAL_ANNUAL_RATE_AMT)
SELECT 1, NULL
INSERT INTO #table2 (ID, ANNUAL_RATE_AMT, STARTING_DATE)
SELECT 1,25.01,'1/1/2014'
UNION SELECT 1,25.02,'1/1/2013'
-- Do the update
;with table2WithIDRowNumbers as (
select ID, ANNUAL_RATE_AMT, STARTING_DATE, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY STARTING_DATE) as rowNumber
FROM #table2
)
UPDATE t1
SET INITIAL_ANNUAL_RATE_AMT=t2.ANNUAL_RATE_AMT
FROM table2WithIDRowNumbers t2
INNER JOIN #table1 t1 ON t1.ID=t2.ID
where t2.rowNumber=1
-- Show the result
SELECT * from #table1

MS SQL Server : update with less amount of rows in source table

What is the best way to update Table1 with all values from Table2 if Table2 has less rows than Table1? This considering that Table2 has no key that can be joined to Table1 for update.
TABLE1 TABLE2 RESULT TABLE1
id value value id value
----------------------------------------------------
1 NULL 4 1 4
2 NULL 6 2 6
3 NULL 8 3 8
4 NULL 4 4
5 NULL 5 6
6 NULL 6 8
7 NULL 7 4
Hope I make sense.
Thanks in advance.
EDIT: Pardon, did not specify its Microsoft SQL Server 2012. :/
EXAMPLE for SOLUTION:
DECLARE #t1 TABLE(id int, avalue int)
DECLARE #t2 TABLE(id INT, avalue int)
-- Generate 20 rows in #t1 table
INSERT
INTO #t1 (id)
SELECT Number
FROM dbo.Numbers
WHERE Number BETWEEN 1 AND 20
-- Generate 5 rows and value #t2 table
INSERT
INTO #t2 (id,avalue)
SELECT Number,
Number
FROM dbo.Numbers
WHERE Number BETWEEN 1 AND 5
-- The goal is to take all rows from #t2
-- and repeatively insert them in order into #t1
UPDATE t1
SET t1.avalue = t2.avalue
FROM #t1 t1
JOIN ( SELECT t2.*, COUNT(*) OVER () AS cnt
FROM #t2 t2
) AS t2
ON (t1.id - 1) % t2.cnt = t2.id - 1;
SELECT *
FROM #t1
Interesting problem. This first solution is for MySQL (I originally read the question as being about that database). After this solution is the one for SQL Server.
You need to generate a join key. Let me assume that id is really sequential. Then you can use modulo arithmetic to do the match:
update table1 t1
(select (#rn := #rn + 1) as seqnum, value
from table2 cross join
(select #rn := -1) vars
) t2 cross join
(select count(*) as cnt from table2) cnt
on mod((t1.id - 1), cnt.cnt) = t2.seqnum
set t1.value = t2.value;
If the id in table1 is not sequential, you can use a variable for that as well. It just further complicates the query:
update table1 t1 join
(select #rn1 := #rn + 1) as seqnum, id
from table1 t1 cross join
(select #rn1 := 0) vars
order by id
) t1s
on t1.id = t1s.id join
(select (#rn := #rn + 1) as seqnum, value
from table2 cross join
(select #rn := -1) vars
) t2 cross join
(select count(*) as cnt from table2) cnt
on mod((t1s.seqnum - 1), cnt.cnt) = t2.seqnum
set t1.value = t2.value;
EDIT:
You can readily do the same thing in SQL Server. It is actually easier:
update table1 t1
set t1.value = t2.value;
from table1 t1 join
(select t2.*, count(*) over () as cnt
from table2 t2
) t2
on (t1.id - 1) % t2.cnt = (t2.id - 1);
This formulation depends on the ids being sequential with no gaps. It is easy enough to loosen this restriction, but the query gets a wee bit more complicated.
Try this query.
DECLARE #Table1 AS TABLE
(
ID INT,
Value INT
)
DECLARE #Table2 AS TABLE
(
Value INT
)
INSERT INTO #Table1
SELECT 1, NULL UNION
SELECT 2, NULL UNION
SELECT 3, NULL UNION
SELECT 4, NULL UNION
SELECT 5, NULL UNION
SELECT 6, NULL UNION
SELECT 7, NULL
INSERT INTO #Table2
SELECT 4 UNION
SELECT 6 UNION
SELECT 8
DECLARE #nCOUNT as INT
SET #nCOUNT = (SELECT COUNT(*) FROM #Table2)
UPDATE TB1 SET TB1.Value = TB2.Value FROM #Table1 AS TB1
INNER JOIN
(SELECT T1.ID, T2.Value FROM
(SELECT *, CASE WHEN (ROW_NUMBER() OVER(ORDER BY ID) % #nCOUNT) = 0
THEN #nCOUNT
ELSE (ROW_NUMBER() OVER(ORDER BY ID) % #nCOUNT)
END AS ROID
FROM #Table1) AS T1
LEFT JOIN (SELECT VALUE, ROW_NUMBER() OVER(ORDER BY Value) AS ID FROM #Table2) AS T2 ON T2.ID = T1.ROID) AS TB2
ON TB1.ID = TB2.ID
SELECT * FROM #Table1

SELECT inner joined columns where only one column can not have duplicate record

I want to select inner joined tables, and if there is a duplicate record in 'column D', do not display entire inner joined row.
Table 1
a b
1 car
1 boat
1 man
Table 2
c d
1 dog *dog is a duplicate, so only display it once.
1 dog
1 cat
Here is my inner joined sql select statement so far:
SELECT DISTINCT
a b c d FROM
table1 INNER JOIN
table2 ON table1.a = table2.c
WHERE <duplicate> NOT ALREADY IN RESULT
Result should be:
1 car 1 dog
*1 boat 1 dog* <--dog is a duplicate so should not be displayed
1 man 1 cat
It sounds like you want some arbitrary pairs drawn from the two tables, as long as the second column does not have any repeated values. Whether you get car/dog or boat/dog is unspecified, you just don't want to get both.
declare #Table1 table ( id1 Int, value1 VarChar(8) )
insert into #Table1 ( id1, value1 ) values ( 1, 'car' )
insert into #Table1 ( id1, value1 ) values ( 1, 'boat' )
insert into #Table1 ( id1, value1 ) values ( 1, 'man' )
declare #Table2 table ( id2 Int, value2 VarChar(8) )
insert into #Table2 ( id2, value2 ) values ( 1, 'dog' )
insert into #Table2 ( id2, value2 ) values ( 1, 'dog' )
insert into #Table2 ( id2, value2 ) values ( 1, 'cat' )
-- All combinations.
select value1, value2, Row_Number() over ( order by value2 ) as 'RowNumber'
from #Table1 as L inner join #Table2 as R on L.id1 = R.id2
-- Some combinations in which values in the second column do not recur.
select value1, value2
from ( select value1, value2, Row_Number() over ( order by value2 ) as 'RowNumber'
from #Table1 as L inner join #Table2 as R on L.id1 = R.id2 ) as Blue
where RowNumber = ( select min( RowNumber ) from
( select value1, value2, Row_Number() over ( order by value2 ) as 'RowNumber'
from #Table1 as L inner join #Table2 as R on L.id1 = R.id2 ) as Grey where value2 = Blue.value2 )
I do believe this is what he is looking for, thx for the hasty minus. Notice i only changed the test data since it seemed wrong.
declare #t1 table(a int, b varchar(5))
declare #t2 table(c int, d varchar(5))
insert #t1
select 1, 'car' union all--*
select 2, 'boat' union all--*
select 3, 'man'
insert #t2
select 1, 'dog' union all--*
select 2, 'dog' union all--*
select 2, 'dog' union all--*
select 3, 'cat'
SELECT
a, b, c, d FROM
#t1 t1 INNER JOIN
#t2 t2 ON t1.a = t2.c
GROUP BY a,b,c,d
HAVING COUNT(*) = 1
Added "all" to my unions thanks to JNK's sharp eye
SELECT DISTINCT
table1.a, table1.b, tab2.c, tab2.d
FROM
table1
INNER JOIN
(SELECT table2.c, table2.d AS tab2) ON table1.a = tab2.c
GROUP BY tab2.d