I have a problem that's really confounding me. I half-expect one of you to point out some really dumb mistake that I'm overlooking but I'm really just not seeing it.
I have a table that our production processes have been feeding for something like a year and we just got some crazy tables from our client against which we are trying to match data. In the following queries, tableA is my table and tableB is the table we've just imported.
The basic problem is that
select *
from tableA
where convert(nvarchar(30),accountNum) not in (
select CisAC
from tableB
)
isn't returning any records when I believe it should be. I think that it should find any records in tableA where the accountNum matches the CisAC field in tableB. Right? CisAC is an nvarchar(30) and our accountNum field is a bigint.
To point out why I think an empty return set is wrong:
select * from tableA where convert(nvarchar(30),accountNum) = '336906210032'
returns one record but
select * from tableB where CisAC = '336906210032'
does not.
So, what gives? (And thanks for your time!)
My suspicion would be null values in tableB causing the IN to fail
I would try
select *
from tableA
left join tableB
on convert(nvarchar(30),tableA.accountNum) = tableB.CisAC
where tableB.CisAc is null
You query is correct. It's returning the expected results.
See here for the SQL Fiddle: http://sqlfiddle.com/#!6/dfb5d/1
What is probably happening is that the data you have in tableB is not matching the data in tableA.
Edit:
As #Andomar answered, if tableB has a null value, the query will fail. See here:
http://sqlfiddle.com/#!6/05bb1/1
This is probably the classic not in mistake. If table B contains any null value,
where convert(nvarchar(30),accountNum) not in (
select CisAC
from tableB
)
will never succeed. You can write it out like:
where convert(nvarchar(30),accountNum) <> null and convert(nvarchar(30),accountNum) <> ...
Since any comparison to null evaluates to unknown, this condition is never true.
Replacing the query with a join like the podiluska's answer suggests should do the trick.
Related
I ran into a problem today that I couldn't quite understand, so I was hoping for some outside knowledge. I was trying to find the number of items in a table where their id isn't referenced in another. I ran two different queries and seem to have conflicting results.
select count(*)
from TableA
where ID not in (select aID from TableB)
returns 0
select count(*)
from TableA a
left join TableB b on b.aID = a.ID
where b.aID is null
returns a few thousand.
All IDs in both TableA and TableB are unique. An ID from TableA never shows up in the aID column from TableB more than once. To me, it seems like I am querying the same thing but receiving different results. Where am I going wrong?
Do not use not in with a subquery. If any value in the subquery is NULL, then all rows are filtered out. These are the rules of how NULL is defined in SQL. The LEFT JOIN is correct.
The reason is that NULL means an unknown value. Almost any comparison with NULL returns NULL, which is treated as false. So, the only possibilities with NOT IN with NULL are that an element matches what you are looking for -- and the expression returns false -- or an element is NULL -- and the expression returns NULL which is treated as false.
I usually advise replacing the NOT IN with NOT EXISTS:
select count(*)
from TableA a
where not exists (select 1 from TableB b where b.aID = a.ID);
The LEFT JOIN performs correctly and usually has good performance.
We should always use the EXISTS operator if the columns involved are nullables. Also,Exist is faster than In clause.
Using IN/Not IN operator might produce an inferior plan and also can lead to misleading results if a null value is inserted in the table just like in you case.
I have a view which returns me some nulls values for the columns b.emissor and B.indexador. In case of null, I need to find this values first in table TB_CAD_RF and, if still nulls, I need to query TB_CAD_RF_2.
I try the logic below but its not working. Also tried to think something with case statements but cant figure it out.
Anyone could help me please?
select A.NM_ATIVO, B.EMISSOR, B.INDEXADOR from VW_POSICAO as A
LEFT JOIN
TB_CAD_RF B on A.NM_ATIVO = B.CODIGO
where a.NM_EMISSOR is null
as C LEFT JOIN (
select C.EMISSOR, C.INDEXADOR from TB_CAD_RF_2 as D ON B.NM_ATIVO = C.CODIGO where C.EMISSOR is null)
This pattern:
SELECT
COALESCE( first.choice, second.choice, third.choice) as a
FROM
first
LEFT JOIN second on first.id = second.id
LEFT JOIN third on second.id = third.id
Coalesce returns the first non null passed into it, scanning from left to right
Here is one way. Always join both and coalesce the fields in the order of desired results.
select A.NM_ATIVO,
EMISSOR = COALESCE(A.EMISSOR,B.EMISSOR),
INDEXADOR=COALESCE(A.INDEXADOR,B.INDEXADOR)
from VW_POSICAO A
LEFT JOIN TB_CAD_RF B on A.NM_ATIVO = B.CODIGO
LEFT JOIN TB_CAD_RF_2 D ON A.NM_ATIVO =D.CODIGO
Case when ISNULL((select * from table1) , (select * from table2) ) else select...
ISNULL is like an IIF statement, but if query field returns a null value, it tries the alternate query or you can set an alternate value.
Syntax may be a bit off, haven't written this query in a while, but it should put you on the right path. Google sql ISNULL
I would like to update columns in Table A based on values in Table B. Using below format, but getting syntax error.
update TableA
set
TableA.MOdule_id =TableB.MOdule_id
from TableA
inner join
TableB
on TableA.end_Slot_id =TableB.Slot_Id
where TableA.Slot_Id = 'AAA';
It would be great help, if anyone can help on this.
A quick search for "informix sql update" returns two reference manual pages that describe the syntax for the UPDATE command. Neither one indicates support for the nonstandard FROM clause.
Standard SQL uses a correlated subquery for the purpose. Your query should look something like
update TableA
set MOdule_id =
(select TableB.MOdule_id
from TableB
on TableA.end_Slot_id = Slot_Id)
where Slot_Id = 'AAA'
and exists (
select 1
from TableB
on TableA.end_Slot_id = Slot_Id
and TableA.Slot_Id = 'AAA'
);
The EXISTS clause ensures that only rows that exist in B are applied to A. Without it, any missing rows would be updated to NULL.
I have a web application that was using a very complex database view to retrieve some data which appeared to be very slow, taking up to 3 minutes to complete only . After a thorough investigation I've found what was the cause of the problem.
In my code I was using the following condition in the WHERE clause to retrieve only the LAST element of a joined table:
SELECT ...
FROM MY_TABLE
JOIN TABLE_JOIN_XX tableA on ....
..lots of other joins ...
WHERE
tableA.id =
(SELECT MAX (id) FROM TABLE_JOIN_XX tableB WHERE tableA.id_parent = tableB.id_parent)
I have then changed the condition in the following way:
tableA.id >= ALL
(SELECT id FROM TABLE_JOIN_XX tableB WHERE tableA.id_parent = tableB.id_parent)
and now the query takes only a couple of seconds.
Now I'm wondering why there is this huge difference in execution time between using the MAX operator and the ALL operator. I am quite surprised indeed. I am no DBA and not very expert in query optimization, but maybe there is something that I don't know and that I should take in consideration while developing my queries for database access.
Or maybe is something related to a problem in that specific Oracle instance and not to the query? I've never noticed this problem in other instances of the same database.
Looking at the explain plan I've noticed that in the second case (and not in the first one) Oracle replaces the ALL operator with a NOT EXISTS:
not exists
(select 0 from TABLE_JOIN_XX tableA
where tableA.id_parent=:b1 and LNNVL (id<=:b2))
Any suggestion?
Many thanks.
Your query seems malformed. This is your statement:
WHERE tableA.id = (SELECT MAX(id) FROM TABLE_JOIN_XX tableB WHERE tableA.id = tableB.id)
You are doing a correlated subquery on the column id. Then you are choosing the maximum value. The subquery can only return tableA.id or NULL, so this is equivalent to:
WHERE EXISTS (SELECT 1 FROM TABLE_JOIN_XX tableB WHERE tableA.id = tableB.id)
Perhaps Oracle is getting a bit confused. In any case, by using MAX(), you are saying that all the values need to be processed, so Oracle is probably doing that. In fact, it only needs to find one row with a value.
An index on TABLE_JOIN_XX(id) should help this query even more.
I have two tables both has id columns, but TableA.id is char, and TableB.id is int. now I want to join two tables, but the problem is there are some string in A.id can't be converted to int. Here is the query I wrote
SELECT
case
when Column1 is null
then (select Surname from TableB
where TableA.id = TableB.id
)
else Column1
end
FROM TableA
GO
the sub select query returns a bunch of records, so my question is that is it possible to run that subquery with the current TableB.id? I am not sure if i explained this clearly, how the subquery get the TableB.id's value of the main query. Thanks
I'm not sure I'm following you, but it sounds like the crux of the problem is that you are trying to join on ID, but they are different field types. Perhaps something like:
SELECT
COALESCE(TableA.Column1, TableB.Surname)
FROM
TableA
LEFT OUTER JOIN TableB On
TableA.ID = Cast(TableB.ID AS Char(64))
I was just taking a guess at the CHAR size, but I assume that's ample. Also I'm not sure what DB you are working on so the syntax may need a bit tweaked.
There is a feature that can do that. It's called a Correlated Subquery, although I'm not sure they work inside case statements.