when one column null then get data from other column - sql

hope you can help. Not showing the whole query because I don't think its required but want to try and get the query to see there is a null value in 'street' so then look in 'free address' and put the result in there. I'm guessing it involves a case expression or concat
Current Result
SELECT
IdNum
street
free address
from ID
IdNum street free address
1 stack over flow null
2 null stack exchange
3 downing street null
Required Result - note free address column doesn't need to be on display, just for purpose of demonstration.
IdNum street free address
1 stack over flow null
2 stack exchange stack exchange
3 downing street null
Many thanks for any help

The COALESCE() function does this:
SELECT IdNum,
COALESCE(street, free_address) as street,
free_address
FROM ID;
Note: ID is a strange name for a table and free address isn't a valid column name (because of the space).
COALESCE() is an ANSI standard function available in basically all databases.

You can use CASE, COALESCE or (in SQL-Server) ISNULL:
SELECT IdNum,
CASE WHEN street IS NULL THEN free_address ELSE street END as street,
free_address
FROM ID;
SELECT IdNum,
COALESCE(street, free_address) as street,
free_address
FROM ID;
SELECT IdNum,
ISNULL(street, free_address) as street,
free_address
FROM ID;

Depending on the database you're using you can use ISNULL, NVL, IFNULL or COALESCE.
Pick the right one here: SQL NULL Functions at w3schools

Use the COALESCE() function, which can replace a NULL value with an alternative you choose:
SELECT IdNum, COALESCE(street, `free address`) AS street, `free address`
FROM ID

You can use following if working with SQL Server
Select [IdNum],
Case
When [street] Is Null AND [free address] Is Not Null
Then [free address] else [street] END As 'street',
[free address]
from ID

Related

How to get the differences between two rows **and** the name of the field where the difference is, in BigQuery?

I have a table in BigQuery like this:
Name
Phone Number
Address
John
123456778564
1 Penny Lane
John
873452987424
1 Penny Lane
Mary
845704562848
87 5th Avenue
Mary
845704562848
54 Lincoln Rd.
Amy
342847327234
4 Ocean Drive Avenue
Amy
347907387469
98 Truman Rd.
I want to get a table with the differences between two consecutive rows and the name of the field where occurs the difference:
I mean this:
Name
Field
Before
After
John
Phone Number
123456778564
873452987424
Mary
Address
87 5th Avenue
54 Lincoln Rd.
Amy
Phone Number
342847327234
347907387469
Amy
Address
4 Ocean Drive Avenue
98 Truman Rd.
How can I do this ? I've looked on other posts but couldn't find something that corresponds to my need.
Thank you
Consider below BigQuery'ish solution
select Name, ['Phone Number', 'Address'][offset(offset)] Field,
prev_field as Before, field as After
from (
select timestamp, Name, offset, field,
lag(field) over (partition by Name, offset order by timestamp) as prev_field
from yourtable,
unnest([`Phone Number`, Address]) field with offset
)
where prev_field != field
if applied to sample data in your question - output is
As you can see here - no matter how many columns in your table that you need to compare - it is still just one query - no unions and such.
You just need to enumerate your columns in two places
['Phone Number', 'Address'][offset(offset)] Field
and
unnest([`Phone Number`, Address]) field with offset
Note: you can further refactor above using scripting's execute immediate to compose such lists within the query on the fly (check my other answers - I frequently use such technique in them)
One method is just use to use lag() and union all
select name, 'phone', prev_phone as before, phone as after
from (select name, phone,
lag(phone) over (partition by name order by timestamp) as prev_phone
from t
) t
where prev_phone <> phone
union all
select name, 'address', prev_address as before, address as afte4r
from (select name, address,
lag(address) over (partition by name order by timestamp) as prev_address
from t
) t
where prev_address <> address

Trying to find duplication in records where address is different only in the one field and only by a certain number

I have a table of listings that has NAP fields and I wanted to find duplication within it - specifically where everything is the same except the house number (within 2 or 3 digits).
My table looks something like this:
Name Housenumber Streetname Streettype City State Zip
1 36 Smith St Norwalk CT 6851
2 38 Smith St Norwalk CT 6851
3 1 Kennedy Ave Campbell CA 95008
4 4 Kennedy Ave Campbell CA 95008
I was wondering how to set up a qry to find records like these.
I've tried a few things but can't figure out how to do it - any help would be appreciated.
Thanks
Are you looking to find something that shows the amount of these rows you have like this?
SELECT
StreenName,
City,
State,
Zip,
COUNT(*)
FROM YourTable
group by StreenName, City, State, Zip
HAVING COUNT(*) >1
Or maybe trying to find all of the rows that have the same street, city, state, and zip?
SELECT
A.HouseNumber,
A.StreetName,
A.City,
A.State,
A.Zip
FROM YourTable as A
INNER JOIN YourTable as B
ON A.StreetName = B.StreetName
AND A.City = B.City
AND A.State = B.State
AND A.Zip = B.Zip
AND A.HouseNumber <> B.HouseNumber
Here is one way to do it. You'll need a unique ID for the table to run this, as you wouldn't want to select the exact same person if theyre the only one there. This'll just spit out all the results where there is at least one duplicate.
Edit: Woops, just realized in comments it says varchar for the street number...hmm. So you could just run a cast on it. The OP never said anything about house numbers in varchar or being letters and numbers in the original post. As for letters in the street number field, I've been a third party shipping provider for 2 yrs in the past and I have never seen one; with the exception of an apt., which would be a diff field. Its just as likely that someone put varchar there for some other reason(leading 0's), or for no reason. Of oourse there could be, but no way of knowing whats in the field without response from OP. To run cast to int its the same except this for each instance: Cast(mt.HouseNumber as int)
select *
from MyTable mt
where exists (select 1
from MyTable mt2
where mt.name = mt2.name
and mt.street = mt2.street
and mt.state = mt2.state
and mt.city = mt2.city
and mt2.HouseNumber between (mt.HouseNumber -3) and (mt.HouseNumber +3)
and mt.UID != mt2.UID
)
order by mt.state, mt.city, mt.street
;
Not sure how to run the -3 +3 if there are letters involed...unless you know excatly where they are and you can just simply cut them out then cast.

sql create a field from a field

I need to run a query that would pull information from a field that has 2 types of data .
Field is address and has 123 avenue as data and bb#yahoo.com.
I need to make 2 fields one for email and one STaddress from table customer and field address?
anyone can i assis..
its access and vb query
I thought of this
Select customer.address from customer where address like "#"
but still i need to display the the data of address field to 2 different fields...
Here is the query that fetches the two different fields:
select iif(field like '*#*', field, NULL) as email,
iif(field like '*#*, NULL, field) as address
from t
The usage of like in Access is a bit different from other databases.
I would suggest that you create a view with this logic. If you actually want to modify the table, you will have to add columns and populate them with logic like the above.
Based on this question and your duplicate question, I understand your table has a field which includes both the street address and email address and you want to split those into separate fields.
So your table includes this ...
YourField
------------------------------
1234 ave willie haha#yahoo.com
123 avenue bb#yahoo.com
And you want this ...
YourField street_address email_address
------------------------------ --------------- --------------
1234 ave willie haha#yahoo.com 1234 ave willie haha#yahoo.com
123 avenue bb#yahoo.com 123 avenue bb#yahoo.com
If that is correct, you can use the InstrRev() function to determine the position of the last space in YourField. Everything before the last space is the street address; everything after is the email address.
SELECT
y.YourField,
Left(y.YourField, InstrRev(y.YourField, ' ') -1) AS street_address,
Mid(y.YourField, InstrRev(y.YourField, ' ') +1) AS email_address
FROM YourTable AS y;
You may need to add a WHERE clause to ensure the query only tries to evaluate rows which include your expected YourField value patterns.
Try something like this:
select *,
(case locate('#', address) when 0 then null else address) as email,
(case locate('#', address) when 0 then address else null) as street
from table;
You'd probably need to adjust the name of "locate" function - I'm not sure if it is the same in access database.
If you have a street address and then an email address in the same field, and want to split them, then use this.
We'll call your original field Addy, and the new fields Street & Email.
SELECT Left(Addy, InStrRev(Addy, " ", InStr(Addy, "#")) - 1) AS Street, mid(Addy, InStrRev(Addy, " ", InStr(Addy, "#")) + 1) AS Email.
What this does is look for the #, then go backwards and look for the first space. The first function takes every left of that space and calls it Street, while the second function takes everything to the right.
The function is really 3 functions nested together. To really understand what it's doing, I'll dissect it.
I = InStr(Addy, "#")
J = InStrRev(Addy, " ", I)
Street = Left(Addy,J-1)

Logically merging 4 columns of the same information

I'm querying 3 different databases (4 total fields) for their "username" field given a particular machine name in our environment: SCCM, McAfee EPO, and ActiveDirectory.
The four columns are SCCM_TOP, SCCM_LAST, EPO, AD
Some of the tuples I get look like:
JOE, JOE, ADMINISTRATOR, JOE
or
JOE, SARAH, JOE, JOE
or
NULL, NULL, JOE, JOE
or
NULL, NULL, JOE, SARAH
The last example of which is the most difficult to code against.
I'm writing a CASE statement to help merge the information in an additive way to give one
final column of the "best guess". At the moment, I'm weighing the most valid username based on another column, which is "age of the record" from each database.
CASE
WHEN ePO_Age <= CT_AGE AND NOT ePO_UN IS NULL THEN ePO_UN
WHEN NOT (SCCM_AGE) IS NULL AND NOT (SCCM_LAST_UN) IS NULL THEN SCCM_LAST_UN
WHEN NOT (SCCM_AGE) IS NULL AND NOT (SCCM_TOP_UN) IS NULL THEN SCCM_TOP_UN
WHEN NOT (AD_UN) IS NULL THEN AD_UN
ELSE NULL
END AS BestName,
But there has to be a better way to combine these records into one. My next step is to weigh the "average age" and then pick the username from there, discarding "Administrator".
Any thoughts or tricks?
You could benefit a little from the COALESCE function to get the first NON-NULL value and do something like:
COALESCE(CASE WHEN ePO_Age<=CT_AGE THEN ePO_UN END,
CASE WHEN SCCM_AGE IS NOT NULL THEN COALESCE(SCCM_LAST_UN, SCCM_TOP_UN) END,
AD_UN) AS BestName
If you just want to get the most recent UserName that isn't null, try using UNION to combine the results from each table.
SELECT TOP 1 qry.UserName
FROM(
SELECT UserName, CreateDate
FROM UserNames_1
UNION ALL
SELECT UserName, CreateDate
FROM UserNames_2
UNION ALL
SELECT UserName, CreateDate
FROM UserNames_3
) AS qry
WHERE qry.UserName IS NOT NULL
ORDER BY qry.CreateDate DESC
Have a SQL Fiddle

Oracle null values

Can somebody please explain the functionality of the below query in oracle db and why is it not returning the last null row. And also please explain me not in functionality in case of null values.
Table Store_Information
store_name Sales Date
Los Angeles $1500 Jan-05-1999
San Diego $250 Jan-07-1999
San Francisco $300 Jan-08-1999
Boston $700 Jan-08-1999
(null) $600 Jan-10-1999
SELECT *
FROM scott.Store_Information
WHERE store_name IN (null)
STORE_NAME SALES DATE
-------------------- -------------------- -------------------------
0 rows selected
SELECT *
FROM scott.Store_Information
WHERE store_name IS null;
NULL can not be "compared" as other (real) values. Therefor you have to use IS NULL or IS NOT NULL.
Here is a series of blog posts regarding this topic: http://momjian.us/main/blogs/pgblog/2012.html#December_26_2012
If the value you are looking for is a null value, the query should be:
SELECT *
FROM scott.Store_Information
WHERE store_name IS NULL;
Oracle NULLS are special:
nothing is equal to null
nothing is NOT equal to null
Since in is equivalent to a = any, this applies to in also.
So, you cannot use NULL in an in or not in clause and expect proper results.
Null is a special value which doesn't follow normal conventions of string or numeric comparison. Evaluating null using these common methods will always evaluate to FALSE unless you use some of the special built in functions.
Select * from Store_Information
where nvl(store_name,'') in ('')
Select * from store_information
where coalesce(store_name, 'Missing') in ('Missing')
Select * from store_information
where store_name is null
If you want your query select field with null value you can :
solution 1 :
use where ... IS NULL ...
solution 2 :
or if you want absolutely use a IN you can use a NVL
eg :
SELECT *
FROM scott.Store_Information
WHERE NVL(store_name, 'NULL_STORE_NAME') IN ('NULL_STORE_NAME')
but in the second case you make the assumption that you can't have a store name named 'NULL_STORE_NAME'... so usually it's better to use solution 1 in my opinion...