AND/OR where clause logic confusion - sql

So I have this table for customers with Main and Mobile phones. I either have a valid number or a blank space or a value of NULL.
CustName MainPhone MobilePhone
Joe 800-111-1234 321-123-1234
Jack 321-321-1237
Jill
Jimmy 321-123-1234
James NULL 432-322-2222
So I have 5 records in total and I want to filter out CustNames that have a blank on both Main and Mobile. So I checked first to see how many I had and used this WHERE CLAUSE:
Select *
From MyTable
Where (MainPhone = '' and MobilePhone = '')
and yes this returned one record only, in this case Jill which has no numbers in either fields.
Now if I want to list everyone except the records that have a blankspace on both MainPhone and MobilePhone what would the WHERE CLAUSE look like? I've tried a few variations and I'm not getting the proper results.
The Final resultset should be like this
CustName MainPhone MobilePhone
Joe 800-111-1234 321-123-1234
Jack 321-321-1237
Jimmy 321-123-1234
James NULL 432-322-2222
Thanks

Check this query
Select *
From mytable
Where (MainPhone != '' AND MainPhone IS NOT NULL) OR (MobilePhone != '' AND MobilePhone IS NOT NULL)
fiddle for the same
http://sqlfiddle.com/#!6/5e668/2

Select *
From MyTable
Where (ISNULL(MainPhone, '') = '' and ISNULL(MobilePhone, '') = '')

Related

Conditionally mapping column names to row values

Assume that we have a table where we have one field for zip code and the rest are binary fields (1 or NULL) with names corresponding to various places. For example, imagining the table has 201 fields with the first field titled "zip code" containing zip codes and the latter being 200 binary value fields titled with city names: Chicago, New York, Houston, etc.
Assume that row one contains zip code 11373. While one could use coalesce to find the first non-null value and return "New York" another value like "Elmhurst" may also be true.
zip_code new_york chicago elmhurst dover maspeth
10001 1 NULL NULL NULL NULL
07801 NULL NULL NULL 1 NULL
11373 1 NULL 1 NULL 1
The goal is to map the column names to each respective zip code and get an output like so:
zip_code city
10001 new_york
07801 dover
11373 new_york
11373 elmhurst
11373 maspeth
Any help is much appreciated.
This is a great use case for SQL UNPIVOT:
SELECT unpvt.*
FROM
#x UNPIVOT (v FOR statename IN (new_york, chicago,elmhurst, dover, maspeth)) AS unpvt
One method uses union all:
select zip_code, 'New York' as city from t where new_york = 1
union all
select zip_code, 'Chicago' as city from t where chicago = 1
union all
. . .

SQL Server: how to update rows with additional information

I have a situation in which a table has information like:
First Name | Last Name | Email
-----------+-----------+-----------------
John Doe jd#email.com
Jane Dont jnd#email.com
And I have a user who wants their email added on to both row's emails to looks like:
First Name | Last Name | Email
-----------+-----------+-----------------------------
John Doe jd#email.com;a#email.com
Jane Dont jnd#email.com;a#email.com
Thank you in advance for any help.
To add a#email.com to all rows in your table:
UPDATE Table
SET Email = Email + ';a#email.com'
To update certain rows:
UPDATE t
SET t.Email = t.Email + ';a#email.com'
FROM Table t
WHERE t.FirstName = 'John'
Note: the above query will update all records with the first name of John
Edit ******** Per #destination-data comment:
If you are also trying to add the new email to columns that have NULL value
SET Email = ISNULL(Email, '') + ';a#email.com'
"...Because null plus anything is null." This technique will change the value from NULL to an empty string plus the new value.

when one column null then get data from other column

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

Using a Table-Valued Function to Turn a Single Row into Many Within Select

Simple enough question I think.
I have a dataset, quite large with a bit of free-text name data. I need to to link this to our employee table.
There's a whole set of different ways people have entered the 'owner' in to this fields (John Smith, J.Smith, John Smith (JSMITH), Company:John Smith/Client: John Smith, ect.)
Most of these are fine, but the problem I have is with the ones where multiple names have been entered. For example; "John Smith / Joe Bloggs".
I have a pre-created Table-Valued function which takes in a string and a delimiter, then returns a table with the results of the split.
dbo.Split('John Smith / Joe Bloggs')
id val
1 John Smith
2 Joe Bloggs
The issue I have is that I need these results to come back for each row within an existing dataset. So for example, my query selecting the Owner, RefNumber and OSProjectCode fro my 'ProjectActions' table containing the following data:
RefNumber OSProjectCode Owner
1 1234 Bill Baggins
2 1234 John Smith / Joe Bloggs
would come out looking like this:
RefNumber OSProjectCode Owner
1 1234 Bill Baggins
2 1234 John Smith
2 1234 Joe Bloggs
What I've tried to far is attempt to join on the results of the function - but unsurprisingly it wont let me send in the column from ProjectsActions into the function like that.
SELECT a.val AS [Owner], pa.[RefNumber], pa.[OSProjectCode]
FROM dbo.ProjectsActions pa
INNER JOIN dbo.Split(pa.[Owner], '/') a
Msg 4104, Level 16, State 1, Line 1
The multi-part identifier "pa.Owner" could not be bound.
The only way I can think of doing this, which seems a little too bulky and messy, is the below:
;with base as(
SELECT
pa.RefNumber
, pa.OSProjectCode
, (SELECT val FROM dbo.Eval(pa.Owner) WHERE id = 1) AS [First]
, (SELECT val FROM dbo.Eval(pa.Owner) WHERE id = 2) AS [Second]
FROM ProjectsActions pa
)
SELECT
a.RefNumber
, a.OSProjectCode
, a.First AS [Owner]
FROM base a WHERE a.First IS NOT NULL
UNION ALL
SELECT
b.RefNumber
, b.OSProjectCode
, b.Second AS [Owner]
FROM base b WHERE a.First IS NOT NULL
Surely there's a better way? Something more similar to my first attempt - joining to the results within each row?
Any feedback or ideas would be much appreciated.
Cheers,
Scott.
EDIT:
FYI if anyone comes accross this with a similar issue, but are missing the 'split' part - I use a function found elsewhere on stackoverflow. https://stackoverflow.com/a/14600765/1700309
You need to use an APPLY as your join.
SELECT
a.val AS [Owner],
pa.[RefNumber],
pa.[OSProjectCode]
FROM dbo.ProjectsActions pa
CROSS APPLY dbo.Split(pa.[Owner], '/') a
The CROSS APPLY acts like an INNER JOIN passing the row-level value into your table-valued function. If you expect split function returns NULL if it can't split the value (NULL, empty, etc), you can use OUTER APPLY so that the NULL won't drop that row out of your result set. You can also add a COALESCE to fall back to the [owner].
SELECT
COALESCE(a.val, pa.[Owner]) AS [Owner],
pa.[RefNumber],
pa.[OSProjectCode]
FROM dbo.ProjectsActions pa
OUTER APPLY dbo.Split(pa.[Owner], '/') a

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