I have a column in table1 that contains names separated with commas, like a,b,c
names
result
a,d,e
a,c,e,f
c,d,f,g
Another column with a single name in table2, like a or b or c
line
name
origin
1
a
US
2
b
UK
3
c
UK
4
d
AUS
5
e
CAN
6
f
UK
7
g
UK
And I want to update table1.result if any names from table1.names are in table2.name & origin = UK.
Tried this, but getting error;
update table1 as t1
set result =
(select name from table2 where origin='UK') = any(string_to_array(t1.names, ','))
Use exists(...) if the result you want is boolean:
update table1 as t1
set result = exists(
select name
from table2
where origin = 'UK'
and name = any(string_to_array(t1.names, ','))
);
Test it in db<>fiddle.
If you want to get the names, use string_agg():
update table1 as t1
set result = (
select string_agg(name, ',')
from table2
where origin = 'UK'
and name = any(string_to_array(t1.names, ','))
);
Db<>fiddle.
Related
I have two tables (as the following), I need to update table1's columns with Table2's values based on what language it is in table2.
Something like this (but its not valid syntax):
UPDATE Table1
If table2.language='EN'
SET description_EN = Table2.Description
Else
SET description_FR=table2.description
FROM table1
left outer join table2 on table1.id=table2.id
Table1:
id description_EN Description_FR
1 null null
2 null null
3 null null
Table 2:
id Language Description
1 EN description in English 1
1 FR description in French 1
2 EN description in English 2
2 FR description in French 2
3 EN description in English 3
3 FR description in French 3
Use a CASE with each column, returning the joined description if the language matches, or self (ie no change) if not the correct language:
UPDATE Table1 SET
description_EN = CASE WHEN table2.language = 'EN' THEN Table2.Description else description_EN END,
description_FR = CASE WHEN table2.language = 'FR' THEN Table2.Description else description_FR END
FROM table1
JOIN table2 on table1.id = table2.id
This joins every language to the row, but only makes a change when appropriate.
You can do this with a CASE statement:
Update T1
Set description_EN = Case When T2.Language = 'EN'
Then T2.Description
Else T1.description_EN
End,
description_FR = Case When T2.Language <> 'EN'
Then T2.Description
Else T1.description_FR
End
From Table1 T1
Left Join Table2 T2 On T1.Id = T2.Id
This will check to see if the Language is EN and update that value, otherwise, it will set it equal to itself.
Likewise for the FR one.
First when I started this project seemed very simple. Two tables, field tbl1_USERMASTERID in Table 1 should be update from field tbl2_USERMASTERID Table 2. After I looked deeply in Table 2, there is no unique ID that I can use as a key to join these two tables. Only way to match the records from Table 1 and Table 2 is based on FIRST_NAME, LAST_NAME AND DOB. So I have to find records in Table 1 where:
tbl1_FIRST_NAME equals tbl2_FIRST_NAME
AND
tbl1_LAST_NAME equals tbl2_LAST_NAME
AND
tbl1_DOB equals tbl2_DOB
and then update USERMASTERID field. I was afraid that this can cause some duplicates and some users will end up with USERMASTERID that does not belong to them. So if I find more than one record based on first,last name and dob those records would not be updated. I would like just to skip and leave them blank. That way I wouldn't populate invalid USERMASTERID. I'm not sure what is the best way to approach this problem, should I use SQL or ColdFusion (my server side language)? Also how to detect more than one matching record?
Here is what I have so far:
UPDATE Table1 AS tbl1
LEFT OUTER JOIN Table2 AS tbl2
ON tbl1.dob = tbl2.dob
AND tbl1.fname = tbl2.fname
AND tbl1.lname = tbl2.lname
SET tbl1.usermasterid = tbl2.usermasterid
WHERE LTRIM(RTRIM(tbl1.usermasterid)) = ''
Here is query where I tried to detect duplicates:
SELECT DISTINCT
tbl1.FName,
tbl1.LName,
tbl1.dob,
COUNT(*) AS count
FROM Table1 AS tbl1
LEFT OUTER JOIN Table2 AS tbl2
ON tbl1.dob = tbl2.dob
AND tbl1.FName = tbl2.first
AND tbl1.LName = tbl2.last
WHERE LTRIM(RTRIM(tbl1.usermasterid)) = ''
AND LTRIM(RTRIM(tbl1.first)) <> ''
AND LTRIM(RTRIM(tbl1.last)) <> ''
AND LTRIM(RTRIM(tbl1.dob)) <> ''
GROUP BY tbl1.FName,tbl1.LName,tbl1.dob
Some data after I tested query above:
First Last DOB Count
John Cook 2008-07-11 2
Kate Witt 2013-06-05 1
Deb Ruis 2016-01-22 1
Mike Bennet 2007-01-15 1
Kristy Cruz 1997-10-20 1
Colin Jones 2011-10-13 1
Kevin Smith 2010-02-24 1
Corey Bruce 2008-04-11 1
Shawn Maiers 2016-08-28 1
Alenn Fitchner 1998-05-17 1
If anyone have idea how I can prevent/skip updating duplicate records or how to improve this query please let me know. Thank you.
You could check for and avoid duplicate matches using with common_table_expression (Transact-SQL)
along with row_number()., like so:
with cte as (
select
t.fname
, t.lname
, t.dob
, t.usermasterid
, NewUserMasterId = t2.usermasterid
, rn = row_number() over (partition by t.fname, t.lname, t.dob order by t2.usermasterid)
from table1 as t
inner join table2 as t2 on t.dob = t2.dob
and t.fname = t2.fname
and t.lname = t2.lname
and ltrim(rtrim(t.usermasterid)) = ''
)
--/* confirm these are the rows you want updated
select *
from cte as t
where t.NewUserMasterId != ''
and not exists (
select 1
from cte as i
where t.dob = i.dob
and t.fname = i.fname
and t.lname = i.lname
and i.rn>1
);
--*/
/* update those where only 1 usermasterid matches this record
update t
set t.usermasterid = t.NewUserMasterId
from cte as t
where t.NewUserMasterId != ''
and not exists (
select 1
from cte as i
where t.dob = i.dob
and t.fname = i.fname
and t.lname = i.lname
and i.rn>1
);
--*/
I use the cte to extract out the sub query for readability. Per the documentation, a common table expression (cte):
Specifies a temporary named result set, known as a common table expression (CTE). This is derived from a simple query and defined within the execution scope of a single SELECT, INSERT, UPDATE, or DELETE statement.
Using row_number() to assign a number for each row, starting at 1 for each partition of t.fname, t.lname, t.dob. Having those numbered allows us to check for the existence of duplicates with the not exists() clause with ... and i.rn>1
You could use a CTE to filter out the duplicates from Table1 before joining:
; with CTE as (select *
, count(ID) over (partition by LastName, FirstName, DoB) as IDs
from Table1)
update a
set a.ID = b.ID
from Table2 a
left join CTE b
on a.FirstName = b.FirstName
and a.LastName = b.LastName
and a.Dob = b.Dob
and b.IDs = 1
This will work provided there are no exact duplicates (same demographics and same ID) in table 1. If there are exact duplicates, they will also be excluded from the join, but you can filter them out before the CTE to avoid this.
Please try below SQL:
UPDATE Table1 AS tbl1
INNER JOIN Table2 AS tbl2
ON tbl1.dob = tbl2.dob
AND tbl1.fname = tbl2.fname
AND tbl1.lname = tbl2.lname
LEFT JOIN Table2 AS tbl3
ON tbl3.dob = tbl2.dob
AND tbl3.fname = tbl2.fname
AND tbl3.lname = tbl2.lname
AND tbl3.usermasterid <> tbl2.usermasterid
SET tbl1.usermasterid = tbl2.usermasterid
WHERE LTRIM(RTRIM(tbl1.usermasterid)) = ''
AND tbl3.usermasterid is null
I have a problem when running queries with a 'case when'. so I want to create a variable to hold the value of the results of the query 'select' to other tables. like the example below. please help me to get the results I want. thank you.
SELECT
a.field1, a.field2,
a.field3 =
CASE
WHEN a.field1 = 'alfa'
THEN
WHEN
-- I want to declare variable to check get value from another table with query select and condition 'WHERE' with variable declare
var varTest = (SELECT TOP 1 b.field1 FROM Table2 as b WHERE b.field2=a.field2) Then
if varTest = 'actif' then
SELECT (c.field4 * C.field5) as hasil FROM Table2 as c WHERE c.field1=varTest)
ELSE
a.field3
END
FROM
Table1 a(NOLOCK)
WHERE
a.field1 = 'alfa'
This is sample data :
field1 | field2 | field3 | > Table1
alfa idAlfa 0
beta idBeta 0
carlie idCarlie 0
field1 | field2 | field4 | field5 | > Table2
actif idAlfa 80 5
pasif idBeta 50 5
other idCarlie 10 5
Result :
field1 | field2 | field3
alfa idAlfa 400
beta idBeta 250
carlie idCarlie 50
It looks to me like this is what you intended. Hard to be entirely sure. It's also possible that this isn't the most efficient query as it's generally a good idea to avoid subqueries inside case expressions.
a.field3 =
CASE WHEN a.field1 = 'alfa' THEN
CASE WHEN (
SELECT TOP 1 b.field1 FROM Table2 as b
WHERE b.field2 = a.field
) = 'actif'
THEN (
SELECT c.field4 * C.field5 as hasil FROM Table2 as c
WHERE c.field1 = 'actif'
)
ELSE a.field3
END
ELSE null
END
You don't need a variable of any type to accomplish this.
A simple JOIN and CASE will get the active (actif) record, calculate your field4 * field5 result (hasil) or use 0 for all passive (pasif) or other records like so:
SELECT
a.field1,
a.field2,
CASE b.field1 -- check id...
WHEN 'actif'
THEN b.field4 * b.field5 -- if 'actif' record, calculate result
ELSE
a.field3 -- not the 'actif' record, use default value
END AS hasil
FROM Table1 AS a -- join the two tables by id name
LEFT JOIN Table2 AS b
ON a.field2 = b.field2;
If you're using SQL Server 2012, you can condense this CASE statement by using IIF:
SELECT
a.field1,
a.field2,
IIF(b.field1 = 'actif', b.field3 * b.field4, a.field3) AS hasil
FROM Table1 AS a
LEFT JOIN Table2 AS b
ON a.field2 = b.field2;
The results using your sample data from these queries are:
field1 | field2 | hasil
alfa idAlfa 400
beta idBeta 0
charlie idCharlie 0
For future reference, the IF syntax you showed in your sample SQL is invalid. That is used in flow control statements that affect how SQL is executed; usually seen in stored procedures. IF can't be used in expressions. Instead, use CASE or IIF statements.
I want to create a SQL statement to select values from one table based on the values from another. I would like to know how to do so in SQL, but knowing in PostgreSQL would be nice as well.
EX:
TableA
ID | Label | Value
1 Test A
TableB
ID | Name | Label
1 TestN Test
I think the query would looks something like this:
SELECT Name FROM TableB WHERE Label = SELECT Label FROM TableA WHERE Value = 'A';
That one throws errors though. Thoughts?
You're close... try this:
SELECT Name FROM TableB WHERE Label IN ( SELECT Label FROM TableA WHERE Value = 'A' );
EDIT: Started to add the INNER JOIN option but it is listed in another answer below.
Why don't you do a INNER JOIN?
SELECT DISTINCT B.Name
FROM TableB B
INNER JOIN TableA A ON B.Label = A.Label
WHERE A.Value = 'A'
use IN not equals:
select Name
from TableB
where Label in ( SELECT Label FROM TableA WHERE Value = 'A' );
I'm not a big fan of "IN" clauses in production code. others will disagree, I get that.
exists and not exists....
SELECT Name FROM TableB tabB WHERE
exists ( select null from TableA innerAAlias WHERE innerAAlias.Value = 'A' /* filter */ and innerAAlias.Label = tabB.Label /* relationship to the outside query */);
Using TSQL --> EXISTS...
SELECT b.name
FROM Table B AS b
WHERE EXISTS
(SELECT *
FROM TableA a
WHERE b.label = a.label
AND a.value = 'A');
I have the following table setup
Acc Currency Alias
1 NULL A
1 USD B
1 EUR C
I want to extract the alias by giving the input as Acc. The Currency and Acc are joined to another table.
It should work as follows -
If acc = 1 and currency is USD then B, if EUR then C, if null then A
Can someone help with this please ?
Did you actually try to write any SQL yourself?
SELECT ...
FROM otherTable ot
(INNER) JOIN thisTable tt
ON ot.Acc = tt.Acc AND ot.Currency = tt.Currency
...
Matching on NULL explicitly
SELECT *
FROM othertbl o
JOIN thistbl t on o.acc = t.acc
and (o.currency = t.currency or o.currency is null AND t.currency is null)
Or in your case, using the NULL currency from thistbl as a fallback
SELECT ...
FROM othertbl o
JOIN thistbl t on o.acc = t.acc and o.currency = t.currency
UNION ALL
SELECT ...
FROM othertbl o
JOIN thistbl t on o.acc = t.acc and t.currency IS NULL
WHERE NOT EXISTS (select *
from thistbl t2
where o.acc = t2.acc and o.currency = t2.currency)