How to update a value from other tables in postgres - sql

currently I have 3 tables
Table 1:
tb1_id
values
1
4
Table 2:
tb1_id
tbl3_id
1
5
Table 3:
tb3_id
values
5
2
For some reason the values from table 1 are not the same in table 3 (as shown above), I need to update the values of the table 1 with the table 3, but I am not able to do so, so far this is my query:
UPDATE
table1 t1
SET
values = temp_tbl.values
FROM
(
SELECT t2.tb1_id, t3.values FROM table2 t2
JOIN
table3 t3 ON t2.tbl3_id = t3.tbl3_id
) temp_tbl
WHERE
t1.tbl1_id = temp_tbl.tbl1_id
AND
t1.values != temp_tbl.values;

OK so if I understood you correctly, you just need to make a slight correction to your code:
UPDATE
table1 t1
SET
values = temp_tbl.values
FROM
(
SELECT t2.tbl1_id, t3.values
FROM table2 t2
Inner JOIN table3 t3 ON t2.tbl3_id = t3.tbl3_id
) temp_tbl
WHERE
t1.tbl1_id = temp_tbl.tbl1_id
AND
t1.values != temp_tbl.values;
Here is DBFiddle link.
EDIT: This would also do:
with newData as (
select t1.tbl1_id, t3.Values
from Table1 t1
inner join Table2 t2 on t1.Tbl1_Id = t2.Tbl1_Id
inner join Table3 t3 on t2.Tbl3_Id = t3.Tbl3_Id
where t1.Values != t3.Values
)
UPDATE
table1
SET
values = newData.Values
FROM newData
where table1.tbl1_id = newData.tbl1_id;

this is how you can do it:
-- temporary tables
SELECT 1 TBL1_ID, 4 valuet1 INTO #t1
SELECT 1 TBL1_ID, 5 TBL3_Id INTO #t2
SELECT 5 TBL3_ID, 2 valuet3 INTO #t3
-- select with joins
select T1.*,T2.*, T3.*
from #t1 T1
INNER JOIN #t2 T2
ON T1.TBL1_ID = T2.TBL1_ID
INNER JOIN #t3 T3
ON T3.TBL3_ID = T2.TBL3_ID
-- update would be like this
update #t1 set valuet1 = T3.valuet3
from #t1 T1
INNER JOIN #t2 T2
ON T1.TBL1_ID = T2.TBL1_ID
INNER JOIN #t3 T3
ON T3.TBL3_ID = T2.TBL3_ID

Related

SQL select query to return only 1 row base on specific criteria from child table

I cannot work out to how return specific parent data row/s depending on what values exist in the child table.
There is two filters or some case statement where I want to apply which returns me the registration_id from table1 depending on the values in the child table.
Return the regestration_id when Table3 has type values of both 1 and 3. In this case, it should return registration_id of 123.
Return the regestration_id when Table3 has only type value of 1 and type of 3 does not exist. In this case, it should return registration_id of 321.
This is the SQL I have used to join the tables:
select registration_id from table1 t1
left join table2 t2 on t2.registration_id=t1.registration_id
left join table3 t3 on t3.x_person_id=t2.x_person_id;
You could use EXISTS:
select t1.registration_id
from table1 t1
inner join table2 t2
on t2.registration_id=t1.registration_id
WHERE EXISTS(
SELECT 1
FROM table3 t3
WHERE t3.type = 1
AND t3.x_person_id = t2.x_person_id
)
AND EXISTS(
SELECT 1
FROM table3 t3
WHERE t3.type = 3
AND t3.x_person_id = t2.x_person_id
);
and NOT EXISTS:
select t1.registration_id
from table1 t1
inner join table2 t2
on t2.registration_id=t1.registration_id
WHERE EXISTS(
SELECT 1
FROM table3 t3
WHERE t3.type = 1
AND t3.x_person_id = t2.x_person_id
)
AND NOT EXISTS(
SELECT 1
FROM table3 t3
WHERE t3.type = 3
AND t3.x_person_id = t2.x_person_id
);
If you want to do it in one EXISTS then:
select t1.registration_id
from table1 t1
inner join table2 t2
on t2.registration_id=t1.registration_id
WHERE EXISTS(
SELECT 1
FROM table3 t3
WHERE t3.type IN (1, 3)
AND t3.x_person_id = t2.x_person_id
HAVING COUNT(DISTINCT t3.type) = 2
)
and:
select t1.registration_id
from table1 t1
inner join table2 t2
on t2.registration_id=t1.registration_id
WHERE EXISTS(
SELECT 1
FROM table3 t3
WHERE t3.type IN (1, 3)
AND t3.x_person_id = t2.x_person_id
HAVING COUNT(CASE t3.type WHEN 1 THEN 1 END) > 0
AND COUNT(CASE t3.type WHEN 3 THEN 1 END) = 0
)

Skip all rows if one row id is present in another table

I have three tables with this relation:
T1.journo = T2.journo
T2.recid = T3.spid
T1
ticketno journo
1 A1
2 A2
T2
journo recid
A1 1
A1 2
A1 3
A2 4
A2 5
A2 6
T3
spid
2
I want only those entries of T1 where T2.recid is not present in T3.spid.
Below query will just omit the 2nd row of T2. But I want all the rows of T2 with journo=A1 omitted because one of the recid of A1 is present in T3.
select T1.* from T1 join T2 on T1.journo = T2.journo
where T2.recid not in (select spid from T3)
Desired Output:
ticketno journo
2 A2
Any tips?
To me, this sounds like not exists:
select t1.*
from t1
where not exists (select 1
from t2 join
t3
on t2.recid = t3.spid
where t2.journo = t1.journo
);
Should be able to use not in with a sub query.
declare #t1 table (ticketno int identity(1,1), journo varchar(2))
declare #t2 table (journo varchar(2), recid int identity(1,1))
declare #t3 table (spid int)
insert into #t1
values
('A1'),
('A2')
insert into #t2
values
('A1'),
('A1'),
('A1'),
('A2'),
('A2'),
('A2')
insert into #t3
values
(2)
select T1.* , T2.*
from #t1 T1
inner join #t2 T2 on T1.journo = T2.journo
where T2.journo not in (select t22.journo from #t2 t22 where t22.recid in (select * from #t3))
Or, not exists correlated
where not exists(select t22.journo from #t2 t22 where t22.recid in (select * from #t3) and t22.journo = T2.journo)
Join T2 on T3 with left a left join. group on the t1 variables then do a having check of COUNT(t3.spid) = 0.
Any nulls shouldn't be counted and so zero on the count is what your looking for.
SELECT t1.*
FROM #t1 t1
JOIN #t2 t2 ON t2.journo = t1.journo
LEFT JOIN #t3 t3 ON t3.spid = t2.recid
GROUP BY t1.ticketno, t1.journo
HAVING COUNT(t3.spid) = 0
SQL, the ugly but necessary part of our lives:
SELECT * FROM T1
INNER JOIN
(SELECT a1.journo
, SUM(spid_present) AS 'total_spids'
FROM
(SELECT T2.journo
, T2.ticketno
, CASE
WHEN t3.spid IS NOT NULL
THEN 1
ELSE 0
END AS 'spid_present'
FROM T2
LEFT JOIN T3
ON T2.recid = T3.spid) a1
GROUP BY a1.journo) a2
ON T1.journo = a2.journo
AND a2.total_spids = 0}
Using EXCEPT:
create table t1 (ticketno int, journo char(2))
insert into t1 values (1, 'A1'), (2, 'A2')
create table t2 (journo char(2), recid int)
insert into t2 values ('A1', 1), ('A1', 2), ('A1', 3), ('A2', 4), ('A2', 5), ('A2', 6)
create table t3 ([SPID] int)
insert into t3 values (2)
select t1.* from t1
except
select t1.*
from t1
inner join t2 on t2.journo = t1.journo
inner join t3 on t2.recid = t3.[SPID]
You can try the below SQL query.
select T.* from T1 , T2 a where T1.journo = a.journo and a.recid not exists (select 1 from T3, T2 where T2.recid= T3.spid and T2.recid =a.reci);
By my understanding, simple join
select t1.* from #t1 t1
join #t2 t2
on t1.journo <> t2.journo
join #t3 t3
on t2.recid = t3.spid

Can I add conditions to LEFT JOIN clauses that aren't part of the join?

It seems to me that both these queries will return the same results:
SELECT * FROM table1
LEFT JOIN table2 ON table1.key = table2.key AND table2.foo = 1
SELECT * FROM table1
LEFT JOIN table2 ON table1.key = table2.key
WHERE table2.foo = 1
Is that correct? If so, is there any meaningful difference between them?
They will NOT return the same results.
The first query will include records from table1, even if there is no matching table2 record where foo is 1.
The second query will not include records from table1 for which there is no matching table2 record with a foo value of 1.
This kind of pattern (LEFT JOIN t ON id=id and other='literal') is common. For example, in the system I work with most currently we have an address_master table that has a person_id column for the person matching the address and an addr_cde (address code) column telling what kind of address it is (home, work, vacation, etc). So it's common to see a join like this:
LEFT JOIN address_master a ON a.person_id = Person.Id AND a.addr_cde = 'Work'
If we moved the addr_cde = 'Work' expression to the WHERE clause, the query would not show us any person who doesn't have a work address on file, even if we wanted to see the other data for that person.
it's not correct
if we assume below sample data, the results is not same:
T1
KEY
---
1
2
T2
KEY Foo
--- ---
1 1
2 4
SELECT * FROM table1
LEFT JOIN table2 ON table1.key = table2.key AND table2.foo = 1
T1.KEY T2.KEY T2.Foo
------ ------ ------
1 1 1
2 NULL Null
SELECT * FROM table1
LEFT JOIN table2 ON table1.key = table2.key
WHERE table2.foo = 1
T1.KEY T2.KEY T2.Foo
------ ------ ------
1 1 1
The following shows how the 2 queries are different:
declare #t1 table(id int);
insert into #t1 values (1), (2);
declare #t2 table(id int, col int);
insert into #t2 values(1,1), (3,1);
First example--a LEFT join with the Where filter on the right table:
select *
from #t1 t1
left join #t2 t2
on t1.id = t2.id
where t2.col = 1;
A proper LEFT join which filters the right table in the ON clause:
select *
from #t1 t1
left join #t2 t2
on t1.id = t2.id
AND t2.col = 1;
An INNER JOIN. This gives the same result as the first example--the LEFT JOIN with the filter for the right table in the Where clause:
select *
from #t1 t1
join #t2 t2
on t1.id = t2.id
where t2.col = 1;

How to replace IN () with Conditional inner join?

Table1 (ID, Col1, col2, col3, col4)
Table2 (ID, Col5, col6)
-----------------SP-------------------
set #Ids = '1,2,3,4,5,6,7,8,9' // Input paremeter (can be NULL)
Create Table #Tabel2
(
Id int
)
Insert into #table2 select * from dbo.Split(#Ids, ',')
NOW #table2 has: 1 2 3 4 5 6 7 8 9
Scenario
Select t1.Col1,t1.col2,t1.col3
FROM Table1 as t1
INNER JOIN Table2 as t2 ON t1.Col1=t2.Col2
AND (#Ids is null OR t1.ID in (Select Id from #Table2))
Question
How to replace IN with conditional inner join?
Because you used alias t which was never defined in your query, it is not clear to me which table ID should be joined on. I took a guess and used t1.
Select t1.Col1,t1.col2,t1.col3
FROM Table1 as t1
INNER JOIN Table2 as t2 ON t1.Col1=t2.Col2
left outer join #Table2 ids on #Ids is null or t1.ID = ids.ID --maybe this should be t2.ID = ids.ID?
Unless I'm misunderstanding (it is friday afternoon after all) you want all rows from Table1/Table2, matched to #Table2 where possible, but everything if #Table2 is empty - this is simply an outer join.
SELECT t.Col1,
t.col2,
t.col3
FROM Table1 AS t1
INNER JOIN Table2 AS t2
ON t1.Col1 = t2.Col2
LEFT OUTER JOIN #Table2 t3
ON t2.ID = t3.ID
In SQL Server 2008, you can use CASE statements in your join clause, for example:
SELECT *
FROM table1
INNER JOIN table2 ON CASE WHEN table1.column1 = 'this' THEN null ELSE 'that' END = table2.column1

Need help in generating Query

I have a doubt in generating Query.
Which is best way in these two
Eg:1
DECLARE #SQLQuery varchar(MAX)
SET #SQLQuery='Select tab1.Name,tab2.Name From table1 INNER JOIN table2 ON table2.ID=table1.ID'
IF #Val=0
SET #SQLQuery=#SQLQuery+' where table1.ID>5'
ELSE
SET #SQLQuery=#SQLQuery+' where table2.ID>5'
Eg 2:
IF #Val=0
BEGIN
Select tab1.Name,tab2.Name
From table1
INNER JOIN table2
ON table2.ID=table1.ID
WHERE table1.ID>5
END
ELSE
BEGIN
Select tab1.Name,tab2.Name
From table1
INNER JOIN table2
ON table2.ID=table1.ID
WHERE table2.ID>5
END
Select tab1.Name,tab2.Name
From table1
INNER JOIN table2
ON table2.ID=table1.ID
WHERE (#Val=0 AND table1.ID>5) OR (#Val!=0 AND table2.ID>5)
IF #Val = 0
BEGIN
Select T1.Name From
(
Select Name From table1 Where Id > 5
)T1
INNER JOIN table2 T2 ON T2.ID = T1.ID
END
ELSE
BEGIN
Select T2.Name From
(
Select Name From table2 Where Id > 5
)T2
INNER JOIN table1 T1 ON T1.ID = T2.ID
END
In this way, We should first filter the values and then join between them.