Similar google emails check for duplicate - sql-server

Google (and maybe others) treat foo.bar#gmail.com and foobar#gmail.com as the same mail box.
Suppose I have a user email in my db:
foo.bar#gmail.com
And I want to check that a new user that tries to register with foobar#gmail.com will not be able to register since that email already exists.
The scenario could be the other way around where a user already registered with foobar#gmail.com and a new one tries to register with foo.bar#gmail.com. for my purposes the emails are equal, and must be "unique".
I have tried
declare #email nvarchar(255);
set #newEmail = 'foobar#gmail.com' -- or 'foo.bar#gmail.com'
select * from Users where REPLACE(Users.Email, '.', '') = REPLACE(#newEmail, '.', '')
but this seems not so efficient and might conflict with the domain part (gmail.com).
Is there a better way to do this?

I would use a computed column to remove any dots from the gmail addresses and then create a unique key on that column.
For example:
DECLARE #Test TABLE (
Email VARCHAR(50) PRIMARY KEY,
ShortEmail AS CONVERT(VARCHAR(50),CASE
WHEN Email LIKE '%#gmail.com' OR Email LIKE '%#googlemail.com'
THEN REPLACE(LEFT(Email,CHARINDEX('#',Email)),'.','')+SUBSTRING(Email,CHARINDEX('#',Email)+1,LEN(Email))
ELSE Email
END) UNIQUE
)
INSERT INTO #Test (Email) VALUES ('a.b#gmail.com'),('a.b#c.com'),('ab#c.com'),('ab.c#gmail.com'),('abc#gmail.com')

Related

Replacing multiple strings with the same string replacement

Been looking all over for this and I don't think nested replace is the answer. I have a list of email address that I need to keep unique, but I need to make them all fake for testing. So my idea was to just replace the '.com', '.net', '.org' and so on to '.mydomain.com'. But there are a LOT of endings in total.
I realized I could just remove the # and add '#mydomain.com' to the end, but now I also want to figure out how to solve this particular problem.
Instead of doing:
BEGIN TRANSACTION;
UPDATE Customer
SET Email=REPLACE(Email, '.com','.mydomain.com')
where email not like '%.mydomain.com%'
COMMIT TRANSACTION;
for each case '.com', '.net', '.org'........
is there a way to say, replace all of these ('.com', '.net', '.org') with '.mydomain.com' in one statement?
something like this.
BEGIN TRANSACTION;
UPDATE Customer
SET Email=REPLACE(Email, (in ('.com', '.net', '.org')),'.mydomain.com')
where email not like '%.mydomain.com%'
COMMIT TRANSACTION;
Following the KISS principle, just run 3 separate queries.
update Customer set email = replace(email, '.com', '.mydomain.com') where email not like '%.mydomain.com%';
update Customer set email = replace(email, '.net', '.mydomain.com') where email not like '%.mydomain.com%';
update Customer set email = replace(email, '.org', '.mydomain.com') where email not like '%.mydomain.com%';
I think something like this should work.
UPDATE Customer
SET Email (case
where CHARINDEX(Email, '.com') > 0 then REPLACE(Email, '.com','.mydomain.com')
where CHARINDEX(Email, '.net') > 0 then REPLACE(Email, '.net','.mydomain.com')
where CHARINDEX(Email, '.org') > 0 then REPLACE(Email, '.org','.mydomain.com')
end)
where email not like '%.mydomain.com%'
May CHARINDEX can be replaced by any function that verify if a string contain a substring.
You can use an UPDATE ... FROM to join a derived table of the TLDs you want to replace. (You can also join a "real" table with the TLDs if you have one.)
UPDATE c
SET c.email = replace(c.email, concat('.', tld.tld), '.mydomain.com')
FROM customer c
INNER JOIN (VALUES ('com'),
('org'),
('net')) tld (tld)
ON c.email LIKE concat('%.', tld.tld)
WHERE c.email NOT LIKE '%.mydomain.com';
db<>fiddle
It won't solve the problem though that, if a substring that matches a TLD is in the string somewhere else as at the end, this substring also gets replaced. But probably that's not an issue here.
Another solution is to have nested replace statements:
update Customer set email = replace(replace(email, '.com', '.mydomain.com'), '.net', '.mydomain.com')
You can go on to as many levels as you want. You can even generate the replace statement dynamically.
Another possible solution is to use a stored procedure.

How to insert username in VS2008(report edition)

I'm creating a new report (*.rdl), and there I want to add username who runs the script (insert).
I've tried on VS2008 through "built-in-fields" function which is "User ID", but it didn't work:
CREATE TABLE #Some_Table
(
Plan_date date null,
Plan_customer int null,
creator_id nvarchar(55) null
)
INSERT INTO Some_Table
(
[Plan_date] ,
[Plan_customer],
[creator_id]
)
SELECT
#p_plan_monthly,
#p_plan_clients,
#creator_id ="user id" --from built-in-fields
Expected result is: Column creator_id is filling with value of username from active directory who made insert through my report.
To reiterate my comment, as it's is incredibly important:
"You need to use a different account to access your data #whitefang. The sa account should never be used for something as mundane as a report. In truth it should never be used unless you really need sysadmin privileges, or you're doing something like recovering the server. You should have a service account that can do the respective tasks it needs to. If you can suffer injection through those reports, you're service is like an open book to whomever has access."
Now, onto your problem. I would add a further internal parameter on your report. Change the value of the parameter to have the default value of =User!UserID; this will be the ID of the user running the report (perhaps something like StackOverflow\Larnu).
Then map that report parameter to your dataset parameter #creator_id and change your INSERT statement to:
INSERT INTO Some_Table ([Plan_date],
[Plan_customer],
[creator_id])
VALUES (#p_plan_monthly, #p_plan_clients, #creator_id);
Q: "and there I want to add username who runs the script (insert)"
You can use these functions.
-- database user name
SELECT USER_NAME()
-- login identification name
SELECT SUSER_NAME()

How to update the SQL Server table based on different column value

I would like to update table called people from:
to
Could you please help?
You need to parse out the beginning of the email address to add it to the domain name. Do that by finding the CHARINDEX of the # symbol, then subtracting one. Use that value as the length parameter in a LEFT function call.
Once you have the name from the email address, CONCATenate it to the static value of your domainname\.
I included a WHERE clause that you may want to use if you have a large number of rows where the Username is already correct and you don't want to waste a bunch of writes replacing a string with a duplicate of that same string. You could leave the WHERE off if you prefer.
UPDATE People
SET Username = CONCAT('domainname\',LEFT([E-mailAddress],CHARINDEX('#',[E-mailAddress])-1))
WHERE
Username <> CONCAT('domainname\',LEFT([E-mailAddress],CHARINDEX('#',[E-mailAddress])-1));
If you are working on earlier versions (cause CONCAT() is for 2012+ versions) and also if you have NULLs in the UserName column, you can do like
CREATE TABLE T(
[E-MailAddress] VARCHAR(50),
UserName VARCHAR(45)
);
INSERT INTO T VALUES
('abc#domainname.com', 'abc'),
('zxc#fhlbdm.com', NULL),
('MNO#domainname.com', 'MNO'),
('pqr#domainname.com', 'pq'),
('tyu#domainname.com', 'domainname\tyu');
UPDATE T
SET UserName = 'domainname\' + LEFT([E-MailAddress], CHARINDEX('#', [E-MailAddress])-1)
WHERE 'domainname\' + LEFT([E-MailAddress] , CHARINDEX('#', [E-MailAddress])-1) <> UserName
OR
UserName IS NULL;
SELECT *
FROM T;

Oracle ROWTOCOL Function oddities

I have a requirement to pull data in a specific format and I'm struggling slightly with the ROWTOCOL function and was hoping a fresh pair of eyes might be able to help.
I'm using 10g Oracle DB (10.2) so LISTAGG which appears to do what I need to achieve is not an option.
I need to aggregate a number of usernames into a string delimited with a '$' but I also need to concatenate another column to to build up email addresses.
select
rowtocol('select username_id from username where user_id = '||s.user_id|| 'order by USERNAME_ID asc','#'||d.domain_name||'$')
from username s, domain d
where s.user_id = d.user_id
(I've simplified the query specific to just this function as the actual query is quite large and all works except for this particular function.)
in the DOMAIN Table I have a number of domains such as 'hotmail.com','gmail.com' etc
I need to concatenate the username, an '#' symbol followed by the domain and all delimited with a '$'
such as ......
joe.bloggs#gmail.com$joeblogs#gmail.com$joe_bloggs#gmail.com
I've battled with this and I've got close but in reverse?!.....
gmail.com$joe.bloggs#gmail.com$joeblogs#gmail.com$joe_bloggs
I've also noticed that if I play around with the delimiter (,'#'||d.domain_name||'$') it has a tendency to drop off the first character as can be seen above the preceding '#' has been dropped from the first email address.
Can anyone offer any suggestions as to how to get this working?
Many Thanks in advance!
Assuming you're using the rowtocol function from OTN, and have tables something like:
create table username (user_id number, username_id varchar2(20));
create table domain (user_id number, domain_name varchar2(20));
insert into username values (1, 'joe.bloggs');
insert into username values (1, 'joebloggs');
insert into username values (1, 'joe_bloggs');
insert into domain values (1, 'gmail.com');
Then your original query gets three rows back:
gmail.com$joe.bloggs
gmail.com$joe_bloggs#gmail.com$joebloggs
gmail.com$joe_bloggs#gmail.com$joebloggs
You're passing the data from each of your user IDs to a separate call to rowtocol, which isn't really what you want. You can get the result I think you're after by reversing it; pass the main query that joins the two tables as the select argument to the function, and have that passed query do the username/domain concatenation - that is a separate step to the string aggregation:
select
rowtocol('select s.username_id || ''#'' || d.domain_name from username s join domain d on d.user_id = s.user_id', '$')
from dual;
which gets a single result:
joe.bloggs#gmail.com$joe_bloggs#gmail.com$joebloggs#gmail.com
Whether that fits into your larger query, which you haven't shown, is a separate question. You might need to correlate it with the rest of your query.
There are other ways to string aggregation in Oracle, but this function is one way, and you already have it installed. I'd look at alternatives though, such as ThomasG's answer, which make it a bit clearer what's going on I think.
As Alex told you in comments, this ROWTOCOL isn't a standard function so if you don't show its code, there's nothing we can do to fix it.
However you can accomplish what you want in Oracle 10 using the XMLAGG built-in function.
try this :
SELECT
rtrim (xmlagg (xmlelement (e, s.user_id || '#' || d.domain_name || '$')).extract ('//text()'), '$') whatever
FROM username s
INNER JOIN domain d ON s.user_id = d.user_id

Schema Changes to Integrate Facebook and Google Login

I have Users table to store user details with password and the authentication for the Application is working good with this.
But we want to integrate Facebook and Google Login in our system so please advise the related schema modifications.
CREATE TABLE dbo.Users(
UserId int IDENTITY(1, 1) PRIMARY KEY,
UserTypeId int, -- Admin = 1, End User = 2. (We have a master table for this, but eliminating here for simplicity)
UserName nvarchar(16) NOT NULL UNIQUE,
UserPassword nvarchar(16),
FirstName nvarchar(64),
LastName nvarchar(64),
DateOfBirth date,
Gender char(1),
PhoneNumber nvarchar(16),
Email nvarchar(128) UNIQUE,
IsActive bit,
UpdateTime datetime default CURRENT_TIMESTAMP )
Here is what I am thinking:
1) Once the user authenticated from Facebook or Google then the application will have claims (emailId)
2) The application should validate the emailId existence in Users Table and if exists it will allow login.
Q1> So will this require any update for the existing Row in Users Table?
Q2> If the user record does not exists (based on emailId claim record) then I think we should add the new record in users table?
Q3> In case of Add: What will be the Username and Password values?
Q4> Can the user (the added record) do a normal login without Facebook login?
Thanks.
In order to accept OpenID logins, you will have to accept and store the users' OpenID-URLs. This URL identifies the user just like an email address does.
Q1: Depends: If you want to allow both OpenID-logins and normal login for the same user, you will have to add another column to the table. If you don't allow mixed logins, you could use your Email column to store the OpenID URL.
Q2: Yes, if you see a new OpenID-URL, handle it just like an unknown email address
Q3: You will have to ask the user to pick a username - I assume you do the same for your current users. If you want to allow both logins for the same user, you will have to ask the user to set a password - otherwise they can only login through their OpenID provider.
Q4: Only if you did ask for a username and a password (see Q3)
Please note that allowing the same user to login through OpenID and using conventional username/password introduces potential security problem: A user might not unserstand that you're asking them to set a password and enter their Facebook (or Google) password. Or they might just not care and use the same password everywhere. If they do so and your database does not encrypt the password properly, your database will store the Facebook names and unencrypted passwords... even if just 10% used the same password on your site - just imagine what they could do with that.

Resources