Trying to write a SQL expression that drops a collection of rows - sql

I've indexed my email inbox and have a table of email_addresses, thread_id, subject, to, from...etc
I would like to "group" (but group by doesn't work) the rows by email address, and then eliminate that collection of rows if any row inside that collection contains a certain email address inside the to field.
I've tried:
select *
from emails
where emails.[to] != "test#email_address.com"
But that just eliminates individual rows, and not the collection of rows that share an email address.
Unfortunately using group by loses all information beyond the top level row and the database no longer can check to see if there are other rows with that email address in the to field.
Any thoughts?

You need a group by on email_address and a conditional check for any of the to email specified.
select email_address
from emails
group by email_address
having count(case when emails.[to] = 'test#email_address.com' then 1 end) = 0
If you need the entire row information for such email_addresses use
select * from emails where email_address in (
select email_address
from emails
group by email_address
having count(case when emails.[to] = 'test#email_address.com' then 1 end) = 0)

Related

Consolidate union result

I am selecting email address from two source tables via a union query. Normally, I would leverage union's behavior of filtering out duplicate values, but in this case, each source table may or may not have a value for each person, and I have to give "priority" to the email address from the first source table when it exists.
When I encounter a situation where the same email address exists in both sources, I would like to to omit the line from source 2 where the email matches that from source 1, as shown below. Assuming CURRENT DATA, how can I make a new selection from CURRENT DATA to arrive at DESIRED RESULT?
CURRENT DATA
PERSONID
EMAILADDRESS
SOURCE
7538583
email#example
1
7538583
email#example
2
7538583
person#somecompany
2
DESIRED RESULT
PERSONID
EMAILADDRESS
SOURCE
7538583
email#example
1
7538583
person#somecompany
2
You can use a subquery in the second part of the union:
select personid,
emailaddress,
1 as source
from table1
union
select personid,
emailaddress,
2 as source
from table2
where not exists (select 1 from table1 where table1.personid = table2.personid);

Oracle - Need advice on multiple counts, on table with large amounts of data

Table with large data, does anyone know how to optimize the count statement?
Eg: table Booking(id, email, mobile,....) (about 30 fields).
Function GetBookingCount(p_email, p_mobile) return number
Select count(id)
from Booking
Where email = p_email
or mobile = p_mobile
Function GetBookingStatus3Count(p_email, p_mobile) return number
Select count(id)
from Booking
Where (email = p_email or mobile = p_mobile)
and status = 3;
Final select:
Select GetBookingCount(email, mobile) as BookingCount
, GetBookingStatus3Count(email, mobile) as BookingStatus3Count
, ...
From Booking
where ....
solution1: Set the field column index what in where clause to count as email column, mobile, status column.
solution2: create a new table with few columns to count.
new table: Booking_Stats(id, email, mobile, status).
Thanks for any suggestion.
select count(*) count_all, count( case when status=3 then 1 else null end ) count_status_3
from Booking
where email = p_email and mobile = p_mobile
//NOTE: Query is written from head, not tested
You would consider creating an index on (email,mobile) or on (email,mobile,status) depending how many lines for given (email,mobile) you get and would you pay the cost of update of the index for status change (if allowed). In case of many updates of status for the same line, you might prefer indexing only (email,mobile) [read/write cost trade off].
Email is likely very discriminant (one value filters out most of the columns). If that is not the case, consider changing order to (mobile,email) if mobile column is better candidate.
It seems likely all those GetBookingBlahBlah() functions are not helpful and in fact quiet injurious to performance.
You haven't posted a complete set of requirements (what is meant by ...?), so it's difficult to be certain, but it seems likely that a solution along these lines would be more performative:
with bk as (
select *
from booking
where email = p_email
or mobile = p_mobile
)
select count(*) as BookingCount
, count(case when bk.status = 3 then 1 end) as BookingStatus3Count
, ...
from bk
The idea is to query the base table once, getting all the data necessary to calculate all the counts, and crunching the aggregates on the smallest result set possible.
An index on booking(email,mobile) might be useful but probably not. A better solution would be to have different queries for each of p_email and p_mobile, with single column indexes supporting each query.
The booking table should have an index on email, mobile and status. You should use this select:
WITH B1 AS
(
SELECT ID,
COUNT(ID) CNT1,
STATUS
FROM BOOKING
WHERE EMAIL = P_EMAIL
AND MOBILE = P_MOBILE
)
SELECT CNT1,
COUNT(ID) CNT2
FROM B1
WHERE STATUS = 3;

Using wildcards in HAVING

Im trying to get a list of all the countries that have atleast 2 customers with yahoo email.
So far I came up with this:
SELECT Country
FROM Customer
GROUP BY Country
HAVING COUNT(Email LIKE '%yahoo%')>= 2
This doesnt work though. Probably because I cant use LIKE in HAVING clause. I tried to use it in where clause, but I cant use aggregate functions there. Do you know how to make this work? Assume standard sql. Thx
use conditional aggregation
SELECT Country
FROM Customer
GROUP BY Country
HAVING SUM(case when Email like '%yahoo%' then 1 else 0 end )>= 2
Or just put the limit in your where clause... This way the limit is imposed before the count possibly having a performance boost; since it only has to evaluate the emails that are like '%yahoo%' instead or all emails when counting; but since the where clause has to do the evaluation 1st anyway. I'm not sure which would be faster w/o testing.
SELECT Country
FROM Customer
WHERE email like '%yahoo%'
GROUP BY Country
HAVING count(Email)>= 2
though like %val% is unable to use any index so; maybe not. but if it was like %yahoo.com' you'd see one. (if index is on email)
Use a CTE to build your aggregated list of filtered countries.
SETUP TEST DATA
IF OBJECT_ID('tempdb.dbo.#td', 'U') IS NOT NULL
DROP TABLE #td;
CREATE TABLE #td ( country varchar(10), email varchar(20) ) ;
INSERT INTO #td ( country, email )
VALUES
('US','bob#builder.com')
, ('GB','bob#yahoo.com')
, ('US','bill#yahoo.com')
, ('US','ted#yahoo.com')
, ('FR','joe#friday.com')
, ('GR','jim#gmail.com')
, ('NZ','mrmaori#yahoo.com')
, ('NZ','kiwi#yahoo.com')
, ('US','rufus#yahoo.com')
;
QUERY
WITH CTE AS(
SELECT country, count(*) AS countryCount
FROM #td
WHERE email LIKE '%yahoo%'
GROUP BY country
)
SELECT CTE.country
FROM CTE
WHERE CTE.countryCount >= 2
;
This will give you NZ and US as the only 2 countries. US has 3 yahoo and 1 non-yahoo. NZ has 2 yahoo. GB has only 1 yahoo and is excluded.

SQL command to clear specific text

Trying to run a SQL command that reads * from my database but I need it to seek specific text in the email field and return a null if it doesn't equal. Example, I'm trying to filter out all emails in our database that are not internal email addresses, so it would need to filter out any that don't have our company name in it.
I was able to filter this with a LIKE command, but it just simply ignores the rest of the fields in the results. I know access has the IIf(InStr command, so I'm hoping there is something similar in SQL
Not sure I fully understand, but something like this may work for you.
USE Server
SELECT
firstName AS EmployeeFirstname
, lastName AS EmployeeLastname
, title AS EmployeeTitle
, id AS EmployeeID
,
Case
When emailAddress Like '%#mycompany.com'
Then emailAddress
Else Null
End AS EmployeeEmailAddress
FROM db.Information
WHERE ISNUMERIC(id)<> 0
AND empStatus = 'A'
So what this will do is give you the rows regardless of what email they have (still taking into account your other selections of ISNUMERIC(id)<> 0 AND empStatus = 'A'). But in those rows, if the email is your company they would display and if not the field would be Null. Obviously change the “mycompany.com” it the Like to whatever string you actually need to search for,
If you want to exclude all records where the company is not in the email address, add
where
emailAddress not like '%companyname%'
If you want to blank out the non-company email addresses, you can use case
Select
case when emailaddress not like '%company%' then null else emailaddress end

Selecting all uppercased-value rows of a table in SQL Navigator

I have a table with an email address column. Some email addresses in the table contain uppercase letters. I would like to fetch all the rows with uppercase emails (in order to set them to lowercase). How do I select all the rows where the email address contains uppercase letters?
I believe Oracle is case sensitive by default? If so, then this should work:
SELECT *
FROM table_name
WHERE LOWER(email) <> email
If this works then you can simply update them with
UPDATE table_name
SET email = LOWER(email)
WHERE LOWER(email) <> email