Why Ansi_nulls does not work? - sql

Assume that I have 2 tables named aTable1, aTable2
aTable1 has userID set to identity and contains the following data:
userID email FirstName LastName
1 NULL C CC
2 NULL D DD
3 a#yahoo.com A AA
4 b#yahoo.com B BB
5 e#yahoo.com E EE
6 f#yahoo.com NULL NULL
7 g#yahoo.com NULL NULL
aTable2 contains the following data:
userID email FirstName LastName Title
3 a#yahoo.com A AA student
4 b#yahoo.com B BB student
5 e#yahoo.com E EE student
NULL NULL C CC dean
NULL NULL D DD advisor
NULL f#yahoo.com NULL NULL student2
NULL g#yahoo.com NULL NULL student3
I want to update aTable2.userID based on aTable1, but knowing that 2 tables have null values in it, so i do like this:
set ANSI_NULLS off
update aTable2
set aTable2.userID = a.userID
from aTable a, aTable2 b
where a.FirstName = b.FirstName and a.LastName = b.LastName and a.email = b.email
However, what this update does not update all the userID, in fact, it only updates those that have email not equal to null, but I already set ANSI_NULLS to off.
What did I do wrong?

It is documented that it won't work:
SET ANSI_NULLS ON affects a comparison only if one of the operands of the comparison is either a variable that is NULL or a literal NULL. If both sides of the comparison are columns or compound expressions, the setting does not affect the comparison.

To get your update query to work, you can try something like this:
UPDATE a2
SET
userId = a.UserId
FROM
aTable2 a2
JOIN aTable1 a ON
ISNULL(a.Email,'NULL') = ISNULL(a2.Email,'NULL') AND
ISNULL(a.FirstName,'NULL') = ISNULL(a2.FirstName,'NULL') AND
ISNULL(a.LastName,'NULL') = ISNULL(a2.LastName,'NULL')
When the values are NULL, I've arbitrarily set the value to 'NULL' -- use some distinct value that will not appear in your data to ensure you won't receive false positives.
I've also seen other solutions using OR criteria in the JOIN and checking both values for NULL:
((a.Email = a2.Email) OR (a.Email IS NULL AND a2.Email IS NULL)) ...
Good luck.

Related

Join two tables on multiple conditions Using Oracle SQL

I have a 2 Tables with below structures
Table 1-- Containing Values like this.
OTHER_CODE
CAPACITY_CODE
Result
A
1
A
5
A
9
A
(null)
B
2
B
6
B
2
Table_2- With Values Like
OTHER_CODE
CAPACITY_CODE
Result
A
1
A
A
5
B
A
(null)
C
A
ELSE
D
B
ALL
E
(null)
ALL
F
I need to Join Table_1 with Table_2 on basis of columns OTHERCODE and CAPACITYCODE and update values in Column Result of Table**1 **using a Merge statement.
I need to handle and match Values based on ELSE and ALL values too.
Check for Direct Match
Check if ALL or ELSE condition
The Final TABLE_1 must look like
OTHER_CODE
CAPACITY_CODE
Result
Explanation
A
1
A
Direct Join
A
5
B
Direct Join
A
9
D
Satsifying ELSE condition
A
(null)
C
Direct join with NVL handling
B
2
E
As Value for CapacityCode in TableB is ALL
B
6
E
As Value for CapacityCode in TableB is ALL
B
2
E
As Value for CapacityCode in TableB is ALL
I Tried Joining both the tables but the was unable to satisfy Else and ALL conditions. Hope if someone can help me on this.
There are Several **Result ** Columns like , Result 1 ,2 in both tables which needs to be updated using the same logic.
Thanks in Advance.
here is a fiddle to work on https://dbfiddle.uk/FMKdWzQT
I got the query working. by using a case statement and assigning a number so I could use max then I just remove the number.
SELECT a.other_code,
a.capacity_code,
(
SELECT SUBSTR(max(
CASE WHEN b.other_code = a.other_code AND a.capacity_code = b.capacity_code THEN concat('3',b.myresult)
WHEN b.other_code = a.other_code AND a.capacity_code is null and b.capacity_code is null THEN concat('2',b.myresult)
WHEN b.other_code = a.other_code AND b.capacity_code in ('ELSE', 'ALL') THEN concat('1',b.myresult)
else null end),2)
FROM table2 b ) as myresult
FROM table1 a
however I can not get the update to work. I tried a merge it is give me the unstable row error and I tried an update select but that is giving me single row subquery error so maybe someone else can take a look at the fiddle. here was my attempt at the update.
UPDATE table1
SET myresult = (
SELECT myresult
FROM (
SELECT a.other_code,
a.capacity_code,
(
SELECT SUBSTR(max(
CASE WHEN b.other_code = a.other_code AND a.capacity_code = b.capacity_code THEN concat('3',b.myresult)
WHEN b.other_code = a.other_code AND a.capacity_code is null and b.capacity_code is null THEN concat('2',b.myresult)
WHEN b.other_code = a.other_code AND b.capacity_code in ('ELSE', 'ALL') THEN concat('1',b.myresult)
else null end),2)
FROM table2 b ) as myresult
FROM table1 a
)t2
WHERE table1.other_code = t2.other_code and nvl(table1.capacity_code,'x') = nvl(t2.capacity_code,'x')
);

Translation of a character to another SQL Server

I want to translate a character from A - B but also in the same query I want to translate B - C if is found on a list. Let's say we have word "Apple" that gets translated to "Orange" but "Orange" it is also on the list and it gets translated to "Coconut", so the final result would be "Coconut". Is this possible ?. I do not want to use a cursor but i just can't find the answer..
update tableA
set Value = b.TargetValue
from tableA a
join
tableB b on b.SourceValue = a.Value
from my TableA i have let's say a list of fruits for this example i just have the fruit "Apple" on tableA but in tableB i have a translation for that word to "Orange", but also in the same tableB i have a translation for "Orange" to "Coconut" so i would expect to have as final result "Coconut". Does that help? it's my first time sorry if i didn't explain well.
EDIT
I have created a function for this. Hope it helps someone else with the same problem.
CREATE FUNCTION [dbo].[FunctionName]
(
#sourceValue varchar(11)
)
RETURNS varchar(11)
AS
BEGIN
declare #targetId varchar(11) = (select TargetID from tableWithValues where
SourceID = #sourceValue)
if #targetId is not null and #targetId <> #sourceValue
begin
set #targetId = dbo.FunctionName(#targetId)
end
else
begin
return #sourceValue
end
return #targetId
end
I would suggest you get a final dataset by joining both fruit tables, so when you get your final fruit just join that dataset(cte or temp table) with the table you want to update.
Hope this approach helps you solve the problem.
I don't think that there is general solution for this, but there is a work-around if there are reasonable limits to the number of substitutions.
For example, the A => B => C you describe has two levels of substitution. If the max number of levels is e.g. 5 you can code like this:
update tableA
set Value = case when b5.TargetValue is not null then b5.targetValue
else when b4.TargetValue is not null then b4.TargetValue
else when b3.TargetValue is not null then b3.TargetValue
else when b2.TargetValue is not null then b2.TargetValue
else when b1.TargetValue is not null then b1.TargetValue
else b0.TargetValue end case
from tableA a
join
tableB b0 on b0.SourceValue = a.Value
left outer join tableB b1 -- outer join for no sub
on b1.SourceValue = b0.TargetValue
left outer join tableB b1
on b2.SourceValue = b1.TargetValue
left outer join tableB b1
on b3.SourceValue = b2.TargetValue
left outer join tableB b1
on b4.SourceValue = b3.TargetValue
left outer join tableB b1
on b5.SourceValue = b4.TargetValue
Here, 5 levels are supported: A =>B =>C =>D =>E =>F. If you have a situation where 6 levels are needed (e.g F => G) then it won't happen, and the result will be F.
Note that the order of the when bx.TargetValue is not null statements is important.

how to update a column with multiple values except particular values

tUser table is having values
UserID UserName Email isActive
---------------------------------------------
1 abc abc#gmail.com 1
2 abc abc#gmail.com 1
3 abc abc#gmail.com 1
4 abc abc#gmail.com 1
22 cd cd#gmail.com 1
23 cd cd#gmail.com 1
24 ef ef#gmail.com 1
25 ef ef#gmail.com 1
The values are duplicate of UserName abc.
I have a query to update isActive column of UserName 'abc'.
UPDATE dbo.tUser
SET isActive = 0
FROM Duplicates d,dbo.tUser
WHERE d.UserId =dbo.tUser.UserId
and d.RN>1
But it is updating the first column of UserName 'abc'. I need to keep a particular userID '4' as 1 and other values to update with 0. How can i do it?
If i need to include 4,23 and 25. How can i do it?
i tried with
;WITH Duplicates AS
(
SELECT [UserId],[UserName],[Email],
RN = ROW_NUMBER()OVER(PARTITION BY[UserName],[Email] ORDER BY [UserName],[Email])
from dbo.tUser
)
UPDATE U
SET isActive = (case when U.UserId IN (4,23,25) THEN 1 ELSE 0 END)
FROM Duplicates d
JOIN dbo.tUser U
ON d.UserId =U.UserId
and d.RN>1
But it is not working
If I understand the question correctly, you can just use a CASE expression:
UPDATE u
SET isActive = (CASE WHEN u.UserId = 4 THEN 1 ELSE 0 END)
FROM Duplicates d JOIN
dbo.tUser u
ON d.UserId = u.UserId
WHERE d.RN > 1;
Note: Learn to use proper explicit JOIN syntax. Simple rule: Never use commas in the FROM clause.
First of all what is d.RN? What is the structure of the Duplicates table? Is it possible that Duplicates.UserId may contain an Id that is similar to tUser.UserId yet refer to a totally different record?
The following script will work for you (however it's not fully tested as I don't have an IDE and SQLFiddler seem to be down:
UPDATE u
SET u.IsActive = 0
FROM dbo.tUser u
LEFT JOIN (SELECT UserId, RANK() OVER (Partition [UserName], [Email] ORDER BY [UserName], [Email]) AS RNK) d
ON d.UserId = tUser.UserId
WHERE d.RNK > 1

Delete and Merge Records in SQL Server

I have a table as following.
id | firstname| lastname | email | homephone
-------------------------------------------------------
1 | aaa | bbb | xxx#yyy.com | 12344444
2 | aaa | bbb | null | null
3 | ccc | ddd | zzz#fff.com | null
4 | ccc | ddd | null | 34343322
The issue is I want to keep only 1 record since these are considered as duplicates and merge the nulls so that the table appears as follows
1 aaa | bbb | xxx#yyy.com | 12344444
3 ccc | ddd | zzz#fff.com | 3433322
So far I have managed to get the duplicates using the following the code
Select
max(a.id) as original id, b.id as DuplicateId,
a.firstname, b.firstname as dup_fname,
a.lastname, b.lastname as dup_lname,
a.email, b.email
From
tbl_xxx a
join
tbl_xxx b on a.firstname = b.firstname
and a.lastname = b.lastname
and a.email is null
and a.homephone is null
and b.email is null
and b.homephone is null
and v.id < v2.id
Group by
b.id, a.firstname, b.firstname, a.lastname,
b.lastname, a.homephone, b.homephone
My merge query looks like this
update tbl_xxx
SET
email = email ,
phone = phone
where
firstname = firstname
and lastname = lastname
and email is null
and phone is null
Eventually I will get distinct rows.
Is my approach correct? kindly suggest how can I make my query more efficient
update tbl_tmpdupes3 SET
email = email ,
phone = phone ,
where
firstname=firstname
and lastname=lastname
and email is null
and homephone is null
will do absolutely nothing, since the query is not comparing the table against itself, but each row against itself. Using an update won't work either, you'll still have duplicates. What you want is to remove the duplicate data entirely, AFTER doing an update comparing the table to itself. So, basically we run one query that ensures all information in duplicates that is not null is copied to the originals, then we delete the higher value pk.
One way of tackling the problem update one column at a time:
update tbl_xxx SET tbl_xxx.email = tmp.email
FROM (SELECT tbl_xxx.firstname,tbl_xxx.lastname,tbl_xxx.email FROM tbl_xxx
WHERE NOT tbl_xxx.email IS NULL LIMIT 1)
AS tmp ON tmp.firstname = tbl_xxx.firstname AND tmp.lastname = tbl_xxx.lastname
WHERE tbl_xxx.email IS NULL;
update tbl_xxx SET tbl_xxx.phone = tmp.phone
FROM (SELECT tbl_xxx.firstname,tbl_xxx.lastname,tbl_xxx.phone FROM tbl_xxx
WHERE NOT tbl_xxx.phone IS NULL LIMIT 1)
AS tmp ON tmp.firstname = tbl_xxx.firstname AND tmp.lastname = tbl_xxx.lastname
WHERE tbl_xxx.phone is NULL;
The query finds the values of each column for first name and last name, and copies over first value it finds into null fields. So, if the original data was missing, it will add it. It may not be 100% correct if two different people in the DB have the same name, you'll have to take that into consideration.
That said, follow it up with this query, which should only delete the higher-pk row that is identical.
DELETE FROM tbl_xxx WHERE tbl_xxx.id IN (
SELECT max(id) FROM tbl_xxx
GROUP BY tbl_xxx.firstname,tbl_xxx.lastname,tbl_xxx.phone,tbl_xxx.email
HAVING count(tbl_xxx.id) > 1));
Edit: if there are potentially multiple duplicates, you could do:
DELETE FROM tbl_xxx WHERE tbl_xxx.id NOT IN (
SELECT min(id) FROM tbl_xxx
GROUP BY tbl_xxx.firstname,tbl_xxx.lastname,tbl_xxx.phone,tbl_xxx.email);
you can use Merge statement for this. Try this sample.
create table temptable (id int, firstname varchar(50), lastname varchar(50), email varchar(50), homephone varchar(50))
insert into temptable values
(1,'aaa' , 'bbb', 'xxx#yyy.com', 1234444),
(2,'aaa' , 'bbb', null, null),
(3,'ccc' , 'ddd', 'abc#ddey.com', null),
(4,'ccc' , 'ddd', null, 34343322 )
select * from temptable
;with cte as
(
select firstname, lastname
,(select top 1 id from temptable b where b.firstname = a.firstname and b.lastname = a.lastname and ( b.email is not null or b.homephone is not null)) tid
,(select top 1 email from temptable b where b.firstname = a.firstname and b.lastname = a.lastname and b.email is not null ) email
,(select top 1 homephone from temptable b where b.firstname = a.firstname and b.lastname = a.lastname and b.homephone is not null ) homephone
from temptable a
group by firstname , lastname
)
--select * from cte
merge temptable as a
using cte as b
on ( a.id = b.tid )
when matched
then
update set a.email = b.email , a.homephone = b.homephone
when not matched by source then
delete ;
select * from temptable
drop table temptable

Update Select Join with NULL values

I have two Tables STR_IndentDetail and PUR_POIndent
STR_IndentDetail:
IndentID ItemID POQty D1 D2 D3 RD
--------- ------- ------ ---- --- --- ---
2 1 NULL 10 20 30 NULL
2 6 NULL 20 40 60 45
PUR_POIndent:
POID IndentID ItemID Quantity D1 D2 D3 RD
------ ---------- ------ ---------- ---- --- --- ---
2 2 1 55 10 20 30 NULL
2 2 6 100 20 40 60 45
I want to Update STR_IndentDetail table POQty with PUR_POIndent table Quantity.
I have written two Update Statement based on INNER JOIN and LEFT OUTER. But both the Queries Update only one row which has values in the Columns D1, D2, D3 and RD.
The row which contains the Column RD with NULL value is not getting UPDATE. How to write the Update Statement for this case. Below are my two Update Statements.
Based On Inner Join:
UPDATE STR_IndentDetail
SET
POQty = PUR_POIndent.Quantity
FROM
PUR_POIndent
WHERE
PUR_POIndent.IndentID = STR_IndentDetail.IndentID AND
PUR_POIndent.ItemID = STR_IndentDetail.ItemID AND
PUR_POIndent.D1 = STR_IndentDetail.D1 AND
PUR_POIndent.D2 = STR_IndentDetail.D2 AND
PUR_POIndent.D3 = STR_IndentDetail.D3 AND
PUR_POIndent.RD = STR_IndentDetail.RD
AND PUR_POIndent.POID = 2
Based On Left Join:
UPDATE STR_IndentDetail
SET
POQty = PUR_POIndent.Quantity
FROM
STR_IndentDetail LEFT OUTER JOIN PUR_POIndent ON
PUR_POIndent.IndentID = STR_IndentDetail.IndentID AND
PUR_POIndent.ItemID = STR_IndentDetail.ItemID AND
PUR_POIndent.D1 = STR_IndentDetail.D1 AND
PUR_POIndent.D2 = STR_IndentDetail.D2 AND
PUR_POIndent.D3 = STR_IndentDetail.D3 AND
PUR_POIndent.RD = STR_IndentDetail.RD WHERE
PUR_POIndent.POID = 2
Both the Queries ignores the row whose RD value is NULL.
I want to update both the rows. How to do this? Any Suggestions please.
You can't compare NULL values with =. Change the condition to use ISNULL and pass a value that isn't present in your table.
example
ISNULL(PUR_POIndent.RD, -999) = ISNULL(STR_IndentDetail.RD, -999)
NULL Comparison Search Conditions
Care must be taken when comparing null
values. The behavior of the comparison
depends on the setting of the SET
ANSI_NULLS option.
When SET ANSI_NULLS is ON, a
comparison in which one or more of the
expressions is NULL does not yield
either TRUE or FALSE; it yields
UNKNOWN. This is because a value that
is unknown cannot be compared
logically against any other value.
This occurs if either an expression is
compared to the literal NULL, or if
two expressions are compared and one
of them evaluates to NULL. For
example, the following comparison
always yields UNKNOWN when ANSI_NULLS
is ON:
or
PUR_POIndent.RD=STR_IndentDetail.RD OR
(PUR_POIndent.RD IS NULL AND STR_IndentDetail.RD IS NULL)