Postgres no results from linked tables where linked values are null - sql

I have this query:
update CA_San_Francisco as p
set geo = u.geo
from parcels_union u
where u.street_number = p.street_number
and u.street_name = p.street_name
and u.street_type = p.street_type
and u.street_direction = p.street_direction
and u.street_unit = p.street_unit
However it does not update any rows where both fields are null. In other words, if there is no value in street_direction for both tables, I get no result even though they are both the same - both null values.
I get that something can't be = Null. So how do I get all of the results?
Thanks, Brad

You could check if the field is NULL and if it is then change it to something you can check for.
For instance, you can change your Where clause to the following
where coalesce(u.street_number,'') = coalesce(p.street_number,'')
and coalesce(u.street_name,'') = coalesce(p.street_name,'')
and coalesce(u.street_type,'') = coalesce(p.street_type,'')
and coalesce(u.street_direction,'') = coalesce(p.street_direction,'')
and coalesce(u.street_unit,'') = coalesce(p.street_unit,'')
But if there are multiple rows that have NULL in these columns then you will get unexpected assignments in your update...

Related

Find matching rows in database table using SQL where no matching key is present

I have an old table with legacy data and approx 10,000 rows and a new table with about 500 rows. The columns are the same in both tables. I need to compare a few columns in the new table with the old one and report on data that is duplicated in the new table.
I've researched articles with similar issues, attempted table joins and where exists / where not exists clauses but I just can't get the SQL right. I have included my latest version.
One issue causing trouble for me, I think, is that there is no "Key" as such like a userid or similar unique identifier in either table.
What I want to do is find the data in the "new" table where all rows except for the "reference_number" (doesn't matter if it does or does not) is duplicated, i.e. exists already in the "old" table.
I have this so far...
select
old.reference_number
new.reference_number
new.component
new.privileges
new.protocol
new.authority
new.score
new.means
new.difficulty
new.hierarchy
new.interaction
new.scope
new.conf
new.integrity
new.availability
new.version
from old, new
where
old.component = new.component
old.privileges = new.privileges
old.protocol = new.protocol
old.authority = new.authority
old.score = new.score
old.means = new.means
old.difficulty = new.difficulty
old.hierarchy = new.hierarchy
old.interaction = new.interaction
old.scope = new.scope
old.conf = new.conf
old.integrity = new.integrity
old.availability = new.availability
old.version = new.version
I have tried this here but it doesn't seem to pull out ALL of the data for some reason.
It is evident that actually there are MORE rows in the old table that are duplicated in the new table but I'm only getting a small number of rows returned from the query.
Can anyone spot why that might be, is there another way I should be approaching this?
If it matters, this is Postgresql.
Thanks for any help given.
The following should do what you want:
select distinct o.reference_number,
n.reference_number,
n.component,
n.privileges,
n.protocol,
n.authority,
n.score,
n.means,
n.difficulty,
n.hierarchy,
n.interaction,
n.scope,
n.conf,
n.integrity,
n.availability,
n.version
from new n
inner join old o
on o.component = n.component and
o.privileges = n.privileges and
o.protocol = n.protocol and
o.authority = n.authority and
o.score = n.score and
o.means = n.means and
o.difficulty = n.difficulty and
o.hierarchy = n.hierarchy and
o.interaction = n.interaction and
o.scope = n.scope and
o.conf = n.conf and
o.integrity = n.integrity and
o.availability = n.availability and
o.version = n.version
You should use left join and then select only rows with new values is null. sql should be something like this:
select
old.reference_number
new.reference_number
new.component
new.privileges
new.protocol
new.authority
new.score
new.means
new.difficulty
new.hierarchy
new.interaction
new.scope
new.conf
new.integrity
new.availability
new.version
from old
left join new
on
old.component = new.component
old.privileges = new.privileges
old.protocol = new.protocol
old.authority = new.authority
old.score = new.score
old.means = new.means
old.difficulty = new.difficulty
old.hierarchy = new.hierarchy
old.interaction = new.interaction
old.scope = new.scope
old.conf = new.conf
old.integrity = new.integrity
old.availability = new.availability
old.version = new.version
where new.component is null

sql query is not working properly

i am trying to get non matching records from two table by comparing some columns which are common in both tables.i am using sql query to get the result. my first table is snd_marketvisits this table have properties like id ,pjpCode , section code, popCode .pop_name and landmark similary my 2nd table have pjpcode , section code, popcode popname are common and there are some other fields.i want to get the names of the pop which are not in second table but present in snd_marketvisit table by comparing popcode, sectioncode and pjpcode in both tables.
SELECT *
FROM snd_marketvisits sm
LEFT JOIN snd_marketvisit_pops sp ON
sm.distributorCode = sp.distributor AND
sm.pjpCode = sp.pjp AND
sm.sectionCode = sp.sectionCode AND
sm.popCode = sp.popCode
WHERE
sm.sectionCode = '00016' AND
sm.pjpCode = '0001' AND
sm.distributorCode = '00190A'
It depends on the database, as far as I know, but if you ask for NULL inside your yoined fields you should get only the rows without a match.
SELECT *
FROM snd_marketvisits sm
LEFT JOIN snd_marketvisit_pops sp ON
sm.distributorCode = sp.distributor AND
sm.pjpCode = sp.pjp AND
sm.sectionCode = sp.sectionCode AND
sm.popCode = sp.popCode
WHERE
sm.sectionCode = '00016' AND
sm.pjpCode = '0001' AND
sm.distributorCode = '00190A'
AND sp.distributor IS NULL

Update table with multiple joins

I am not really a SQL guy so any help would be appreciated. I am trying to update a table when fields match on one column and do not on another:
UPDATE dleads
SET mag_name = magazines.mag_name
FROM magazines
WHERE dleads.umc = magazines.umc and
dleads.mag_name <> magazines.mag_name
I can get the SELECT to work, but not the UPDATE.
Your query is not robust in handling NULL values.
You could use this instead:
UPDATE dleads SET mag_name = magazines.mag_name FROM magazines WHERE dleads.umc = magazines.umc AND COALESCE(dleads.mag_name, '') <> COALESCE(magazines.mag_name, '');
Your query looks like it's doing exactly what you describe:
UPDATE dleads d
SET mag_name = m.mag_name
FROM magazines m
WHERE d.umc = m.umc
AND d.mag_name <> m.mag_name;
The most common thing being overlooked here would be NULL values. If mag_name can be NULL in either table, and you want to update anyway, use the NULL-safe IS DISTINCT FROM:
UPDATE dleads d
SET mag_name = m.mag_name
FROM magazines m
WHERE d.umc = m.umc
AND d.mag_name IS DISTINCT FROM m.mag_name;
Aside: You mention "multiple joins" in the title, but I only see a single join in your query.

Query with multiple EXISTS returing too many rows

Original table has 1466303 records in it, I have inserted 1108441 of those records in to a separate table. What I would like to know is what data is left over? So I have made a query using multiple exists to find the data that was left:
SELECT SG_customer,
PHONE,
SG_Name,
SG_Secondary_Address,
SG_Primary_Address,
SG_City,
SG_State,
SG_Zip,
SG_Email
FROM FMJ_DB_VPI_EXPANDED_DATA X
WHERE NOT EXISTS (SELECT 1
FROM FMJScore
WHERE SGID = X.SG_Customer
AND Phone = X.Phone
AND Name = X.SG_Name
AND SecondAddress = X.SG_Secondary_Address
AND Address = X.SG_Primary_Address
AND City = X.SG_City
AND State = X.SG_State
AND Zip = X.SG_Zip
AND Email = X.SG_Email)
Running this returns back 144391 records, there should be a difference of 357862, I don't understand why its returning back so many records.
I assume you want null to be treated equal to null, I also assume that '' is not used as a value, if it is replace it with something that does not normally occur:
SELECT SG_customer,
PHONE,
SG_Name,
SG_Secondary_Address,
SG_Primary_Address,
SG_City,
SG_State,
SG_Zip,
SG_Email
FROM FMJ_DB_VPI_EXPANDED_DATA X
WHERE NOT EXISTS (SELECT 1
FROM FMJScore
WHERE coalesce(SGID,'') = coalesce(X.SG_Customer,'')
AND coalesce(Phone,'') = coalesce(X.Phone,'')
AND coalesce(Name,'') = coalesce(X.SG_Name,'')
AND coalesce(SecondAddress,'') = coalesce(X.SG_Secondary_Address,'')
AND coalesce(Address,'') = coalesce(X.SG_Primary_Address,'')
AND coalesce(City,'') = coalesce(X.SG_City,'')
AND coalesce(State,'') = coalesce(X.SG_State,'')
AND coalesce(Zip,'') = coalesce(X.SG_Zip,'')
AND coalesce(Email,'') = coalesce(X.SG_Email,''))
The optimizer might not be able to use indexes efficiently due to the function call

Gettin a value from a table and using in the same query

SELECT (h.horario), h.codigo
FROM horarios as h
JOIN horario_turma as h_t
ON(h.codigo != h_t.cd_horario)
WHERE h_t.cd_turma = 'HTJ009'
AND h_t.cd_dia = 2
AND h.cd_turno = 1
I'm trying to figure out if there's a possibility to get the h.cd_turnovalue from another table and use in the same query, beacuse this value is gonna be variable. So, I'd have to get this value from a query, then pass the value to PHP and do another query with this value. Is there a way to do that in the same query?
There's a table called turmas(codigo, cd_turno). I'll have the codigovalue, in this case HTJ009, and I'd like to select the cd_turno value.
Query used to get the value:
SELECT cd_turno FROM turmas WHERE codigo='HTJ009'
You can use a subquery, like so:
SELECT (h.horario), h.codigo
FROM horarios as h
JOIN horario_turma as h_t
ON(h.codigo != h_t.cd_horario)
WHERE h_t.cd_turma = 'HTJ009'
AND h_t.cd_dia = 2
AND h.cd_turno = (SELECT cd_turno FROM turmas WHERE codigo='HTJ009')
In this case, remember that it is important for the subquery to return only one result, otherwise you'll encounter an error. If you do see such an error, you may have to tweak the subquery to ensure only one result is returned.
Check this out for Postgres subquery documentation
SELECT (h.horario), h.codigo
FROM horarios as h
JOIN horario_turma as h_t
ON(h.codigo = h_t.cd_horario)
WHERE h_t.cd_turma = 'HTJ009'
AND h_t.cd_dia = 2
AND h.cd_turno = 1 and h_t.cd_horario is null