Incorrect Where Statement - sql

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, '')

Related

PostgreSQL conditional where clause

In my Ruby on Rails app I'm using blazer(https://github.com/ankane/blazer) and I have the following sql query:
SELECT *
FROM survey_results sr
LEFT JOIN clients c ON c.id = sr.client_id
WHERE sr.client_id = {client_id}
This query works really well. But I need to add conditional logic to check if client_id variable is present. If yes then I filter by this variable, if not then I not launching this where clause. How can I do it in PostgreSQL?
Check if its null OR your condition like this:
WHERE {client_id} IS NULL OR sr.client_id = {client_id}
The WHERE clause evaluate as follow: If the variable is empty, then the WHERE clause evaluate to true, and therefore - no filter. If not, it continue to the next condition of the OR
If anyone faced with the psql operator does not exist: bigint = bytea issue, here is my workaround:
WHERE ({client_id} < 0 AND sr.client_id > {client_id}) OR sr.client_id = {client_id}
Please consider that, client_id generally cannot be negative so you can use that information for eleminating the operation cast issue.
My solution:
I use spring data jpa, native query.
Here is my repository interface signature.
#Query(... where (case when 0 in :itemIds then true else i.id in :itemIds end) ...)
List<Item> getItems(#Param("itemIds) List<Long> itemIds)
Prior calling this method, I check if itemIds is null. If yes, I set value to 0L:
if(itemIds == null) {
itemIds = new ArrayList<Long>();
itemIds.add(0L);
}
itemRepo.getItems(itemIds);
My IDs starts from 1 so there is no case when ID = 0.

In SQL , how do I JOIN a column that is usually null so that the data is still retrieved?

I want to incorporate a new column into a working SQL query.
However, it causes the whole query return nothing at all(because the column is mostly null in the database) .
Here's my pared-down code so far :
SELECT DISTINCT submittedRow.PERFORMED_DATE as "submitted",
supervisorRow.PERFORMED_DATE as "superv",
/* coalesce(sodRow.PERFORMED_DATE, TO_DATE('2000/07/07', 'YYYY/MM/DD') ) */ null AS "SOD"
hhs_umx_resp_activity submittedRow
join hhs_umx_resp_activity supervisorRow ON supervisorRow.reg_request_id = configRow.reg_request_id
/* join hhs_umx_resp_activity sodRow ON sodRow.reg_request_id = approvedRow.reg_request_id */
left join HHS_UMX_REG_REQUESTS hurr on hurr.reg_request_id = hur.reg_request_id
WHERE
and supervisorRow.ACTIVITY_RESULT_CODE = 'ASP'
AND submittedRow.activity_result_code = 'SBT'
/* AND sodRow.activity_result_code = 'ASD'*/
and hur.REG_REQUEST_ID IN ('262097')
The column that is mostly null, which I want to add in, is sodRow ( that's why the code AND sodRow.activity_result_code = 'ASD' is commented ).
Whenever I put back the extra join for sodRow , it just nulls out everything and I get no results at all. But I want it to work like a NVL or COALESCE, where it only displays that column if it exists, and otherwise just shows everything else.
I tried to create a view first in the code, then to do UNION on it. But it seems like view are only for PL/SQL code.
I also tried the outer joins, but this doesn't work.
I think the problem may be in the WHERE condition of my join code. I did like Dmitri suggest belwo :
AND nvl(sodRow.activity_result_code, 'ASD') = 'ASD'
AND nvl(configRow.activity_result_code, 'ACL') = 'ACL'
or also alternatively :
problem is that it won't return any rows. I.E If we're looking for 'ACL' then the previous check of 'ASD' becomes true and will render the next check useless.
I think I'm just having trouble visualizing how the joins work here
, thanks !
May be you can try left outer join
left outer join hhs_umx_resp_activity sodRow ON sodRow.reg_request_id = approvedRow.reg_request_id
and nvl
AND nvl(sodRow.activity_result_code, 'ASD') = 'ASD'
it will return records with null in sodRow.activity_result_code or 'ASD' in it

SQL: field = other_field returns false even if they are identical (NULL values)

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))

Conditional Sql in Daisy chained Query

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

Where clause in sql

My sql query is as follows
IF #StatusId = 10
BEGIN
SELECT
*
FROM
Risk AS R
INNER JOIN Statuses AS St ON R.Status_Id=St.Status_Id
WHERE
R.MitigationOwner = COALESCE(#MitigationOwner,R.MitigationOwner)
AND R.RiskFactor = COALESCE(#RiskFactor,R.RiskFactor)
AND R.RiskArea = COALESCE(#RiskArea,R.RiskArea)
AND R.AddedWhen BETWEEN
COALESCE(CONVERT(DATETIME, #StartDate+'00:00:00',120),R.AddedWhen) AND
COALESCE(CONVERT(DATETIME,#EndDate+'23:59:59',120),R.AddedWhen)
END
When I pass only status Id and all other variables are null, then records with NULL MitigationOwner or ModifiedDate are not displayed..
What is wrong in this query?
Use the form:
...
(R.MitigationOwner = #MitigationOwner OR #MitigationOwner IS NULL)
...
This is optimised in SQL Server. COALESCE isn't.
Edit: This does the same as Paul Williams' answer but his answer allows explicit "NULL = NULL" matches. m ylogic is simpler because NULL never equals NULL.
I believe that by ModifiedDate you meant R.AddedWhen
try this:
SELECT
*
FROM
Risk AS R
INNER JOIN Statuses AS St ON R.Status_Id=St.Status_Id
WHERE
(R.MitigationOwner = COALESCE(#MitigationOwner,R.MitigationOwner) OR R.MitigationOwner IS NULL)
AND R.RiskFactor = COALESCE(#RiskFactor,R.RiskFactor)
AND R.RiskArea = COALESCE(#RiskArea,R.RiskArea)
AND (R.AddedWhen BETWEEN
COALESCE(CONVERT(DATETIME, #StartDate+'00:00:00',120),R.AddedWhen) AND
COALESCE(CONVERT(DATETIME,#EndDate+'23:59:59',120),R.AddedWhen) OR R.AddedWhen IS NULL)
If R.MitigationOwner can be null, then your comparison clause:
WHERE
R.MitigationOwner = COALESCE(#MitigationOwner,R.MitigationOwner)
Must be rewritten to handle NULL values:
WHERE
((R.MitigationOwner IS NULL AND #MitigationOwner IS NULL)
OR (R.MitigationOwner = #MitigationOwner))
See this article on Wikipedia about NULL.