I have a query that looks at one tables field and matches the second table's field. It looks to see if the fields don't match each other. If there's no match the second table's field must replace the first tables field. I have this working EXCEPT when there's a null value in either of the two tables field. I tried using isNull() on the first table and it does select values that aren't null but if I apply the same function to the second table I get nothing in return.
UPDATE [NAVAIR Deficiencies] INNER JOIN NAVAIR_Deficiencies_Temp ON [NAVAIR Deficiencies].[Unique Deficiency Code] = NAVAIR_Deficiencies_Temp.[Unique Deficiency Code] SET [NAVAIR Deficiencies].[Hull Q] = [NAVAIR_Deficiencies_Temp]![Hull Q], NAVAIR_Deficiencies_Temp.Changed = True
WHERE ((IsNull([NAVAIR Deficiencies]![Hull Q])<>[NAVAIR_Deficiencies_Temp]![Hull Q]));
You are experiencing the fact that null <> null.
You can work around this with IsNull(), if you are able to define a string value that never appears in both columns:
IsNull([NAVAIR Deficiencies]![Hull Q], '§§§§')
<> IsNull([NAVAIR_Deficiencies_Temp]![Hull Q], '§§§§')
This treats two null value as equals, and considers that a null value is not equal to any non-null value.
Or, you can enumerate all possible situations, using boolean logic
[NAVAIR Deficiencies]![Hull Q]) <> [NAVAIR_Deficiencies_Temp]![Hull Q]
or ([NAVAIR Deficiencies]![Hull Q] is null and [NAVAIR_Deficiencies_Temp]![Hull Q] is not null)
or ([NAVAIR Deficiencies]![Hull Q] is not null and [NAVAIR_Deficiencies_Temp]![Hull Q] is null)
It might be simpler expressed with a negation:
not (
[NAVAIR Deficiencies]![Hull Q]) = [NAVAIR_Deficiencies_Temp]![Hull Q]
or ([NAVAIR Deficiencies]![Hull Q] is null and [NAVAIR_Deficiencies_Temp]![Hull Q] is null)
)
Related
I used the following WHERE clause
WHERE (TYPE1 = :P3_ITEM1 OR :P3_ITEM1 IS NULL)
to filter my query on TYPE1 and it worked fine to display the records of same TYPE1 when page item P3_ITEM1 is not null.
Now I need to add two more filters for TYPE2 and TYPE3. Normally only one page item P3_ITEM1, P3_ITEM2, or P3_ITEM3 is not null, so I need to filter on whichever on is not null.
I tried
WHERE (TYPE1=:P3_ITEM1 OR :P3_ITEM1 IS NULL) OR
(TYPE2=:P3_ITEM2 OR :P3_ITEM2 IS NULL) OR
(TYPE3=:P3_ITEM3 OR :P3_ITEM3 IS NULL)
but it did not work.
I tried using CASE statement in my WHERE clause but no success so far. Can anyone help?
WHERE CASE
WHEN (:P3_ITEM1 IS NOT NULL) THEN (TYPE1=:P3_ITEM1)
WHEN (:P3_ITEM2 IS NOT NULL) THEN (TYPE2=:P3_ITEM2)
WHEN (:P3_ITEM3 IS NOT NULL) THEN (TYPE3=:P3_ITEM3)
You can simply use AND to combine the various filters. Each filter will evaluate to true if the parameter for it is NULL, so if all three are NULL you will get all records, but you can fill in a any, or even all three parameters to filter out unwanted records.
WHERE
(TYPE1 = :P3_ITEM1 OR :P3_ITEM1 IS NULL) AND
(TYPE2 = :P3_ITEM2 OR :P3_ITEM2 IS NULL) AND
(TYPE3 = :P3_ITEM3 OR :P3_ITEM3 IS NULL)
I am learning SQL so be gentle. If I have designated a specific role in my where clause it is only pulling those cases where that role is populated. How can I also include the NULL values or those roles that are blank?
Here is the where clause now:
WHERE (dbo.vcases.lawtype = 'My Cases') AND
(dbo.vcase_parties_people.role_sk = 4001) AND
**(v1.role_sk = 3940) AND
(v1.report_ind = 'Y') AND
(v2.role_sk = 3939) AND
(v2.report_ind = 'Y')** AND
(dbo.vcases.case_type NOT IN ('Case type 1', 'Case type 2'))
The COALESCE() expression in SQL is useful for substituting a default value when NULL is encountered for a given column or expression. When the query optimizer encounters a COALESCE() call, it will internally rewrite that expression to an equivalent CASE...WHEN expression. In your sample query, WHERE (COALESCE(v1.role_sk, 3940) = 3940) would operate (and optimize) the same as WHERE (CASE WHEN v1.role_sk IS NOT NULL THEN v1.role_sk ELSE 3940 END = 3940).
Since your example specifically involves a condition in the WHERE clause, you may want to use an OR operation, which could optimize better than a COALESCE() expression: WHERE (v1.role_sk = 3940 OR v1.role_sk IS NULL).
This is also assuming that any joins in your query aren't filtering out rows whose role_sk column is NULL.
You might edit your code as follows:
WHERE (dbo.vcases.lawtype = 'My Cases') AND
(dbo.vcase_parties_people.role_sk = 4001) AND
(v1.role_sk = 3940 OR v1.role_sk IS NULL) AND
(v1.report_ind = 'Y') AND
(v2.role_sk = 3939) AND
(v2.report_ind = 'Y') AND
(dbo.vcases.case_type NOT IN ('Case type 1', 'Case type 2'))
The use of the Coalesce function has been suggested but a good rule of thumb in SQL is to avoid the use of functions in the WHERE clause because it reduces the efficiency of the table's indexes. Functions in WHERE clause often cause Index-Scans instead of the more efficient Index-Seeks.
I have a difficulty because when comparing two fields in a subquery, although the fields are identical i.e. they both have NULL values, the comparison returns a FALSE result
Therfore NULL = NULL is returning FALSE
Now I know that NULLs are supposed to be compared with the IS operator, however when I compare two fields how am I supposed to know they contain a null? I need to compare two fields for identical data both if the values are NULL or not.
Consider this SQL:
SELECT
*
FROM
fts.fts_customers_data_50360001
WHERE
fts.fts_customers_data_50360001.record_type = 15
AND
fts.fts_customers_data_50360001.mid = 103650360001
AND NOT EXISTS
(
SELECT
fts.temp_fees_50360001.record_type
FROM
fts.temp_fees_50360001
WHERE
fts.temp_fees_50360001.record_type = fts.fts_customers_data_50360001.record_type
AND
fts.temp_fees_50360001.merch_id = fts.fts_customers_data_50360001.mid
AND
fts.temp_fees_50360001.fee_curr = fts.fts_customers_data_50360001.currency
AND
fts.temp_fees_50360001.card_scheme = fts.fts_customers_data_50360001.card_scheme
AND
fts.temp_fees_50360001.tran_type = fts.fts_customers_data_50360001.fee_type
AND
fts.temp_fees_50360001.area = fts.fts_customers_data_50360001.region
AND
fts.temp_fees_50360001.srvc_type = fts.fts_customers_data_50360001.card_type
);
In the query above,
fts.temp_fees_50360001.card_scheme = fts.fts_customers_data_50360001.card_scheme
both have NULL values inside but the comparison returns false .. too bad
ANY IDEAS WOULD BE MUCH APPRECIATED
As the others have pointed out, NULL cannot be compared with NULL.
In Postgres you can shorten your expressions by using the operator IS DISTINCT FROM which is a null-safe replacement for <>. In your case you'd need to use IS NOT DISTINCT FROM to compare for equality (looks a bit the wrong way round but unfortunately there is no corresponding IS EQUAL TO defined in the SQL standard).
From the manual:
Ordinary comparison operators yield null (signifying "unknown"), not true or false, when either input is null. For example, 7 = NULL yields null, as does 7 <> NULL. When this behavior is not suitable, use the IS [ NOT ] DISTINCT FROM constructs:
So, instead of
(fts.temp_fees_50360001.record_type = fts.fts_customers_data_50360001.record_type
OR (fts.temp_fees_50360001.record_type IS NULL
AND fts.fts_customers_data_50360001.record_type IS NULL)
)
you can use:
(fts.temp_fees_50360001.record_type IS NOT DISTINCT FROM fts.fts_customers_data_50360001.record_type)
to handle NULL values automatically. The condition looks a bit strange if you want to compare for equality but it still is quite short.
First of all, use aliases for your tables, your query will be MUCH more readable:
select *
from fts.fts_customers_data_50360001 as d
where
d.record_type = 15 and
d.mid = 103650360001 and
not exists
(
select *
from fts.temp_fees_50360001 as f
where
f.record_type = d.record_type and
f.merch_id = d.mid and
f.fee_curr = d.currency and
f.card_scheme = d.card_scheme and
f.tran_type = d.fee_type and
f.area = d.region and
f.srvc_type = d.card_type
)
As for your question, there's several ways to do this, for example, you can use syntax like this:
...
(
f.card_scheme is null and d.card_scheme is null or
f.card_scheme = d.card_scheme
)
...
Or use coalesce with some value that couldn't be stored in your column:
...
coalesce(f.card_scheme, -1) = coalesce(d.card_scheme, -1)
...
Recently I also like using exists with intersect for this type of comparisons:
...
exists (select f.card_scheme, f.tran_type intersect select d.card_scheme, d.tran_type)
...
Just a side note - you have to be careful when writing queries like this and check query plans to be sure your indexes are used.
In SQL, null is never equal to null. The only way to get a true result for a comparison with null is via the special tests:
IS NULL
IS NOT NULL
In your case, you must cater specifically for the "two nulls" case being considered equal:
AND (fts.temp_fees_50360001.card_scheme = fts.fts_customers_data_50360001.card_scheme
OR (fts.temp_fees_50360001.card_scheme IS NULL
AND fts.fts_customers_data_50360001.card_scheme IS NULL)
)
There's no getting around dealing with it (although there are a few variations).
The following inner SELECT works (but I give no guarantee regarding performance):
SELECT
fts.temp_fees_50360001.record_type
FROM
fts.temp_fees_50360001
WHERE
(fts.temp_fees_50360001.record_type = fts.fts_customers_data_50360001.record_type
OR (fts.temp_fees_50360001.record_type IS NULL AND fts.fts_customers_data_50360001.record_type IS NULL))
AND
(fts.temp_fees_50360001.merch_id = fts.fts_customers_data_50360001.mid
OR (fts.temp_fees_50360001.merch_id IS NULL AND fts.fts_customers_data_50360001.mid IS NULL))
AND
(fts.temp_fees_50360001.fee_curr = fts.fts_customers_data_50360001.currency
OR (fts.temp_fees_50360001.fee_curr IS NULL AND fts.fts_customers_data_50360001.currency IS NULL))
AND
(fts.temp_fees_50360001.card_scheme = fts.fts_customers_data_50360001.card_scheme
OR (fts.temp_fees_50360001.card_scheme IS NULL AND fts.fts_customers_data_50360001.card_scheme IS NULL))
AND
(fts.temp_fees_50360001.tran_type = fts.fts_customers_data_50360001.fee_type
OR (fts.temp_fees_50360001.tran_type IS NULL AND fts.fts_customers_data_50360001.fee_type IS NULL))
AND
(fts.temp_fees_50360001.area = fts.fts_customers_data_50360001.region
OR (fts.temp_fees_50360001.area IS NULL AND fts.fts_customers_data_50360001.region IS NULL))
AND
(fts.temp_fees_50360001.srvc_type = fts.fts_customers_data_50360001.card_type
OR (fts.temp_fees_50360001.srvc_type IS NULL AND fts.fts_customers_data_50360001.card_type))
Any reason why the below statement doesn't return any results? If I leave out the where I get all the records and can clearly see that VarcharFields don't match in a number of cases which are the ones I'm trying to find. I've tried swapping ACC and CON in the where and also using <> instead of !=.
SELECT Con.VarcharField, ACC.VarcharField
FROM
dbo.Contact AS CON
INNER JOIN Account as ACC ON ACC.AccountId = CON.ContactID
WHERE ACC.VarcharField != CON.VarcharField
UPDATE
The problem is down to null values in the table. Any way around NULL comparisons?
You can check if either side is NULL and other is not.
SELECT Con.VarcharField, ACC.VarcharField
FROM
dbo.Contact AS CON
INNER JOIN Account as ACC ON ACC.AccountId = CON.ContactID
WHERE (ACC.VarcharField IS NULL AND CON.VarcharField IS NOT NULL)
OR (ACC.VarcharField IS NOT NULL AND CON.VarcharField IS NULL)
OR ACC.VarcharField != CON.VarcharField
SQLFiddle DEMO
For comparisons with string fields that might be NULL, I prefer the IsNull() function. Careful. Depends on what your definition of "no value" is, and whether they should match or not match.
WHERE IsNULL(ACC.VarcharField, '') != IsNull(CON.VarcharField, '')
I have one master table with all the IDs to each child table. The SQL statement looks like this...
SELECT Class.Descript
, Regulation.Descript AS Reg
, Compgroup.Descript AS Grouping
, Category.Descript AS Cat
, Exempt.Descript AS Exempt
, Reason.Descript AS Reasons
, COALESCE(ComponentRuleSet.NormalType, ComponentRuleSet.Supertype, '') AS Type
FROM ComponentRuleSet
LEFT OUTER JOIN Reason
ON ComponentRuleSet.ComponentCategoryID = Reason.ComponentCategoryID
LEFT OUTER JOIN Class
ON ComponentRuleSet.ComponentClassID = Class.ComponentClassID
LEFT OUTER JOIN Regulation
ON ComponentRuleSet.RegulationID = Regulation.RegulationID
LEFT OUTER JOIN Compgroup
ON ComponentRuleSet.ComplianceGroupID = Compgroup.ComplianceGroupID
LEFT OUTER JOIN Category
ON ComponentRuleSet.ComponentCategoryID = Category.ComponentCategoryId
LEFT OUTER JOIN Exempt
ON ComponentRuleSet.ExemptID = Exempt.ComponentExemptionID
WHERE (ComponentRuleSet.ComponentID = 38048)
The problem is that there are two fields in the ComponentRuleSet table called NormalType and Supertype. If either of those fields have a value, I need to display it in a column called Type. Yet, if neither have a value I need to display a Blank value in the Type column.
Any ideas?
---EDIT
Is my placement of COALESCE correct in the edited query? It is still returning errors.
--UPDATE
IMPORTANT: The type of both fields are boolean, I need to return the column name of the column that holds a TRUE value, and place that value in the TYPE column.
Use COALESCE for this field:
COALESCE(ComponentRuleSet.NormalType, ComponentRuleSet.Supertype, '') AS Type
COALESCE:
Returns the first nonnull expression among its arguments.
Following your comments as to the actual requirement, CASE is probably a better option:
CASE WHEN ComponentRuleSet.NormalType = 1 THEN 'NormalType'
WHEN ComponentRuleSet.Supertype = 1 THEN 'SuperType'
ELSE ''
END AS Type
Seeing your comments, perhaps a CASE expression will work:
select ...
, CASE WHEN ComponentRuleSet.NormalType is not null then 'NormalType'
WHEN ComponentRuleSet.Supertype is not null then 'SuperType'
ELSE ''
end as Type
UPDATE Since boolean values are just 1 for true and 0 for false, try this:
select ...
, CASE WHEN ComponentRuleSet.NormalType = 1 then 'NormalType'
WHEN ComponentRuleSet.Supertype = 1 then 'SuperType'
ELSE ''
end as Type