Update Select Join with NULL values - sql

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)

Related

SQL Server Return Null if exists

In SQL Server 2008 I am looking to create a query that will return a NULL in an aggregate if one exists, otherwise I'm looking for the maximum. This is a simplified example...
I have the following data:
CO Loc Term_Dt
1 A 7/15/2013
1 B
1 C 10/30/2000
2 A 8/10/2008
2 B 6/1/2015
2 C 4/30/2010
The result I'm looking for is:
CO Term_Dt
1 NULL
2 6/1/2015
because technically the Company is still open if at least one location has not yet been terminated.
Thanks
Just use aggregation and a case statement:
select co,
(case when count(term_dt) = count(*) then max(term_dt)
end) as term_dt
from table t
group by co;
count(<column>) counts the number of non-NULL values. If this doesn't match all the rows, then at least one is NULL. No else is needed for the case, because the default is NULL.
Generate a sub set of data with companies having null term dates and left join your super set to it. Any records in 2nd table which are not null you want to display as null so use a case statement.
This works because our outer table (A) returns
CO TERM_DT
1 7/15/2013
2 6/1/2015
But then our LEFT join on our inline view also adds B.Co...
CO TERM_DT B.CO
1 7/15/2013 1
2 6/1/2015 NULL
So you can see by saying we want to display NULL when B.CO is not null instead of the max(TERM_DT) will yield the desired results. This is accomplished using a case statement.
SELECT A.Co,
Case when B.CO is not null then Max(A.Term_DT) else NULL end as Term_DT
FROM tableName A
LEFT JOIN (SELECT Distinct CO from tableName where Term_dt is null) B
on A.Co = B.CO
GROUP BY CO

Oracle SQL join with counts returning null

I'm having a problem with the following query in Oracle SQL:
SELECT t.diif, t.mlf_response, v.total
FROM t_temp_rows t
LEFT OUTER JOIN
(SELECT a.diif, s.mlf_response, COUNT(a.customer_terid) total
FROM ter_details a
INNER JOIN lieu_details s ON a.lieu_id = s.lieu_id
WHERE a.customer_name = 'CUSTOMER_A' AND mlf_response IS NOT NULL
GROUP BY a.diif, s.mlf_response) v ON v.diif = t.diif AND v.mlf_response = t.mlf_response;
t_temp_rows contains all possible combinations for diif and mlf_response, regardless of whether they actually return counts in the subquery or not. I am hoping to get a count for every row in t_temp_rows, including 0 for rows with no count (I will add the NVL once it actually works).
If I run the query, rather than returning the counts in 'total' where there is a value and null elsewhere, I get null for every row.
Expected:
diif mlf_response total
---- ------------ -----
ABCD YES 12
ABCD NO 32
ABCE YES 54
ABCE NO 01
ABCF YES null
ABCF NO null
Actual:
diif mlf_response total
---- ------------ -----
ABCD YES null
ABCD NO null
ABCE YES null
ABCE NO null
ABCF YES null
ABCF NO null
What have I done wrong?
You need to add a.customer_name = 'CUSTOMER_A' to the left outer join because by adding it to the where, you are making it an inner join.
SELECT t.diif, t.mlf_response, v.total
FROM t_temp_rows t
LEFT OUTER JOIN
(SELECT a.diif, s.mlf_response, COUNT(a.customer_terid) total
FROM ter_details a ON a.customer_name = 'CUSTOMER_A'
LEFT OUTER JOIN lieu_details s ON a.lieu_id = s.lieu_id
WHERE mlf_response IS NOT NULL
GROUP BY a.diif, s.mlf_response) v ON v.diif = t.diif AND v.mlf_response = t.mlf_response;

Why Ansi_nulls does not work?

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.

Optional filter on a left join column

I'm having issues wrapping my head around how to write a procedure that includes an optional filter on a left join.
I have two tables, Issues, and Customer_Location. Not all issues have been linked to a customer location. So I am fine with this as a starting point:
SELECT
I.Issue_Number,
C.Customer_Location_Code
FROM Issues I
LEFT JOIN Customer_Location C
ON C.Customer_Location_Key = I.Customer_Location_Key
Issue_Number | Customer_Location_Code
1 | Chicago
2 | NULL
3 | Chicago
4 | New York
And this works, it gives me all the issues. But I want to add an optional parameter for the customer location code that if left null would return all 4 issues, but if set to say 1 for Chicago, only issue 1 and 3 would return.
I've tried this
DECLARE #customer_location_key INT
SET #customer_location_key = 1
SELECT
I.Issue_Number,
C.Customer_Location_Code
FROM Issues I
LEFT JOIN Customer_Location C
ON C.Customer_Location_Key = I.Customer_Location_Key
AND C.Customer_Location_Key = #customer_location_key
But I get the following results
Issue_Number | Customer_Location_Code
1 | Chicago
2 | NULL
3 | Chicago
4 | NULL
For some reason I seem to be having a brain fart right now and just can't seem to get my head around what SHOULD be something rather simple
Adding a where clause similar to below should do it.
DECLARE #customer_location_key INT
SET #customer_location_key = 1
SELECT
I.Issue_Number,
C.Customer_Location_Code
FROM Issues I
LEFT JOIN Customer_Location C
ON C.Customer_Location_Key = I.Customer_Location_Key
where (#customer_location_key is null or C.Customer_Location_Key = #customer_location_key)
Use the where clause instead
DECLARE #customer_location_key INT
SET #customer_location_key = 1
SELECT
I.Issue_Number,
C.Customer_Location_Code
FROM Issues I
LEFT JOIN Customer_Location C
ON C.Customer_Location_Key = I.Customer_Location_Key
WHERE
(#customer_location_key is null OR C.Customer_Location_Key = #customer_location_key)
The reason that your query does not work as you expect is that first the 2 ON conditions are examined and then, because of the LEFT JOIN, all rows of table Issue that haven't been matched are added as well (with NULLs in the columns of table Customer_Location_Code).
DECLARE #customer_location_key INT
SET #customer_location_key = 1
SELECT
I.Issue_Number,
C.Customer_Location_Code
FROM Issues I
LEFT JOIN Customer_Location C
ON C.Customer_Location_Key = I.Customer_Location_Key
WHERE ( #customer_location_key IS NULL )
OR ( C.Customer_Location_Key = #customer_location_key )

update each row in a procedure

I have the following data in a table TABLE1
DOCUMENT ------ FIELD1
12345
23456
34567
45678
98765
i have the following data in a view VIEW1
DOCUMENT ---- BUS
12345 ------------ 5
23456 ------------ 6
34567 ------------ 8
45678 ------------ 12
98765 ------------ 14
What i would like to do is update each row
if (table1.document = view1.document)
then
table1.field1 = view1.bus
Any insight will help.
Thank you.
That can be done using plain SQL, no procedures required:
UPDATE table1 SET field1 = (SELECT bus FROM view1 WHERE table1.document = view1.document)
Or, if your database allows it:
UPDATE (select table1.field1, view1.bus FROM table1 JOIN view1 ON table1.document = view1.document) SET table1.field1 = view1.bus
As Dan said, but in MS SQL Server I find this styling easier to read:
UPDATE U
SET U.field1 = V.bus
FROM table1 AS U
JOIN view1 AS V
ON V.document = U.document
Note that if VIEW1 could have multiple rows for a given TABLE1 row [DOCUMENT] value then the [BUS] value choosen to update TABLE1 will be random, within the matching set. (If this is the case the query could be modified to choose MAX / MIN / etc.)
I would refine this query to NOT update any rows that already matched the BUS value, which will make it faster if it is rerun and thus some values already exist in TABLE1
UPDATE U
SET U.field1 = V.bus
FROM table1 AS U
JOIN view1 AS V
ON V.document = U.document
WHERE U.field1 = V.bus
OR (U.field1 IS NOT NULL AND V.bus IS NULL)
OR (U.field1 IS NULL AND V.bus IS NOT NULL)
you can leave out the NULL / NOT NULL tests if the field is defined as not allowing NULLs.