Right, I have some 21000 records where email addresses have numbers at the end ( . + 15 digit long number, example: xyz#gmail.com.201211200200027)
Now, the best solution I can think of is this:
Update TABLE
set EmailAddress = (
select substring (EmailAddress, 1, (len(EmailAddress) - 16))
from TABLE)
Where ISNUMERIC(RIGHT(Emailaddress, 15)) = 1
Above code doesn't work (I am no T-SQL expert so forgive me if this code looks stupid)
If I tell that code a specific email address then it works. Something like this:
Update TABLE
set EmailAddress = (
select substring (EmailAddress, 1, (len(EmailAddress) - 16))
from TABLE)
Where ISNUMERIC(RIGHT(Emailaddress, 15)) = 1
and Emailaddress is 'xyz#gmail.com.201211200200027'
So, How do I update these email addresses and remove last 16 characters?
Try this;
UPDATE yourTable
SET EmailAddress = LEFT(EmailAddress, LEN(EmailAddress) - 16 )
WHERE PATINDEX('%[^0-9]%', RIGHT(EmailAddress, 15)) = 0 AND LEN(EmailAddress) > 16
Related
How do you validate that a text string is a valid email address which will be accepted by the sp_send_dbmail function?
I've looked through other questions like this one, which yes works great, until a user copies their email address from outlook and comes through like Jane Doe <DoeJ#xdomain.com>, which fails to send via the system proc.
I also want users to be able to supply multiple emails in a single string separated by semicolons, which are accepted by sp_send_dbmail. Thanks!
You can try this (there are other ways),
--PARAM:START
DECLARE #EmailList varchar(max);
SET #EmailList = 'Jane Doe <DoeJ#xdomain.com>;info.support#mssqltips.com;.info#mssqltips.com;
info..#mssqltips.com;info#mssqltips.c;info#support#mssqltips.com;info.support#mssql_tips.com;
+info#mssqltips.com;info Support#mssqltips.com;info#mssql tips.com;NULL;22#mssqltips.com;#mssqltips.com';
--PARAM:END
--VALIDATION:START
DECLARE #EmailTable TABLE
(
Email varchar(max),
IsValid bit
);
INSERT INTO #EmailTable(Email, IsValid)
SELECT LTRIM(RTRIM(value))
,CASE WHEN LTRIM(RTRIM(value)) = '' THEN 0
WHEN LTRIM(RTRIM(value)) LIKE '% %' THEN 0
WHEN LTRIM(RTRIM(value)) LIKE ('%["(),:;<>\]%') THEN 0
WHEN SUBSTRING(LTRIM(RTRIM(value)),CHARINDEX('#',LTRIM(RTRIM(value))),LEN(LTRIM(RTRIM(value)))) LIKE ('%[!#$%&*+/=?^`_{|]%') THEN 0
WHEN (LEFT(LTRIM(RTRIM(value)),1) LIKE ('[-_.+]') OR RIGHT(LTRIM(RTRIM(value)),1) LIKE ('[-_.+]')) THEN 0
WHEN (LTRIM(RTRIM(value)) LIKE '%[%' or LTRIM(RTRIM(value)) LIKE '%]%') THEN 0
WHEN LTRIM(RTRIM(value)) LIKE '%#%#%' THEN 0
WHEN LTRIM(RTRIM(value)) NOT LIKE '_%#_%._%' THEN 0
ELSE 1
END
FROM STRING_SPLIT(#EmailList, ';');
--VALIDATION:END
--GET VALID EMAIL
DECLARE #ValidEmailList varchar(max);
SELECT #ValidEmailList = COALESCE(#ValidEmailList + ', ', '') + Email
FROM #EmailTable
WHERE IsValid = 1;
--DO SENDING OF EMAIL USING ValidEmailList
Source: Valid Email Address Check with TSQL
#tontonsevilla Great solution, I just modified it a bit to remove the intermediate table and replace any line breaks that may show up (as they did from copying your solution):
DECLARE #EmailList VARCHAR(MAX);
SET #EmailList
= 'Jane Doe <DoeJ#xdomain.com>; info.support#mssqltips.com;.info#mssqltips.com;
info..#mssqltips.com;info#mssqltips.c;info#support#mssqltips.com;info.support#mssql_tips.com;
+info#mssqltips.com;info Support#mssqltips.com;info#mssql tips.com;NULL;22#mssqltips.com;#mssqltips.com';
DECLARE #ValidEmailList VARCHAR(MAX);
SELECT #ValidEmailList = COALESCE(#ValidEmailList + ';', '') + [x].[Email]
FROM (
SELECT TRIM(REPLACE(REPLACE([value], CHAR(10), ''), CHAR(13), '')) [Email]
FROM STRING_SPLIT(#EmailList, ';')
WHERE LEN([value]) > 4
AND CHARINDEX(' ', TRIM([value])) = 0
AND TRIM([value])NOT LIKE ('%["(),:;<>\]%')
AND SUBSTRING(TRIM([value]), CHARINDEX('#', TRIM([value])), LEN(TRIM([value])))NOT LIKE ('%[!#$%&*+/=?^`_{|]%')
AND LEFT(TRIM([value]), 1)NOT LIKE ('[-_.+]')
AND RIGHT(TRIM([value]), 1)NOT LIKE ('[-_.+]')
AND TRIM([value])NOT LIKE '%[%'
AND TRIM([value])NOT LIKE '%]%'
AND TRIM([value])NOT LIKE '%#%#%'
AND TRIM([value]) LIKE '_%#_%._%'
) [x];
SELECT #ValidEmailList;
We have a column of varying string values like below. How to extract part of the string and return the desired result in Redshift?
Example
Remove last part that starts with an underscore and number (_1_MN, number can be 1-1000)
Remove leading part (Ed_)
Replace any remaining underscore with a space
String:
Ed_Westside Ind School District 94_Williams Elementary School_1_MN
Desired result:
Westside Ind School District 94 Williams Elementary School
MySQL
UPDATE products
SET col = SUBSTRING(col FROM 3)
WHERE col LIKE ('Ed_%')
UPDATE products
SET col = SUBSTRING(col FROM -5 )
WHERE col LIKE ('%_1_MN')
UPDATE products
SET col = REPLACE(col, '_', ' ')
While not very elegant, this worked.
REGEXP_REPLACE(LEFT(RIGHT(name, LEN(name) - 3), LEN(name) -8) , '_', ' ')
I Have: AAAA/DATA1/Data2;xyx;pqr
this data
I want only:DATA1 And Data2
If this is for a specific row, maybe use SUBSTR? Something like
SELECT
SUBSTR(column, 6, 5) AS col1
, SUBSTR(column, 13, 5) AS col2
FROM table
Here is something else you can do.. Although it gets pretty complicated, and this isn't the exact answer you are looking for but it will get you started. Hope this helps:
WITH test AS (
SELECT characters
FROM ( VALUES
( 'AAAA/DATA1/Data2;xyx;pqr'
) )
AS testing(characters)
)
SELECT
SUBSTR(characters, 1, LOCATE('/', characters) - 1) AS FIRST_PART
, SUBSTR(characters, LOCATE('/', characters) + 1) AS SECOND_PART
, SUBSTR(characters, LOCATE('/', characters, LOCATE('/', characters) + 1) + 1)
AS THIRD_PART
FROM test
;
DB2 does not have a single function for this, unfortunately. Check out this answer here: How to split a string value based on a delimiter in DB2
I have a column "pnum" in a "test" table.
I'd like to replace the leading "9" in pnum with "*" for every record.
testdb=# select * from test limit 5;
id name pnum
===========================================
1 jk 912312345
2 tt 9912333333
I would like the pnums to look like this:
id name pnum
===========================================
1 jk *12312345
2 tt *912333333
How would I do something like this in postgres?
EDIT 1:
I have tried something like this so far:
select id, name, '*' && substring(pnum FROM 2 FOR CHAR_LENGTH(pnum)-1 ) from test limit 3;
Also tried this:
select id, name, '*' || substring(pnum FROM 2 FOR CHAR_LENGTH(pnum)-1 ) from test limit 3;
Neither one has worked...
EDIT 2:
I figured it out:
select id, name, '*'::text || substring(pnum FROM 2 FOR CHAR_LENGTH(pnum)-1 ) from test limit 3;
See function regexp_replace(string text, pattern text, replacement text [, flags text]) String Functions and Operators
SELECT regexp_replace('9912333333', '^[9]', '*');
regexp_replace
----------------
*912333333
You can use Postgres' string manipulation functions for this. In your case "Substring" and "Char_Length"
'*' || Substring(<yourfield> FROM 2 FOR CHAR_LENGTH(<yourfield>)-1) as outputfield
Here's a simple query we do for ad hoc requests from our Marketing department on the leads we received in the last 90 days.
SELECT ID
,FIRST_NAME
,LAST_NAME
,ADDRESS_1
,ADDRESS_2
,CITY
,STATE
,ZIP
,HOME_PHONE
,MOBILE_PHONE
,EMAIL_ADDRESS
,ROW_ADDED_DTM
FROM WEB_LEADS
WHERE ROW_ADDED_DTM BETWEEN #START AND #END
They are asking for more derived columns to be added that show the number of previous occurences of ADDRESS_1 where the EMAIL_ADDRESS matches. But they want is for different date ranges.
So the derived columns would look like this:
,COUNT_ADDRESS_1_LAST_1_DAYS,
,COUNT_ADDRESS_1_LAST_7_DAYS
,COUNT_ADDRESS_1_LAST_14_DAYS
etc.
I've manually filled these derived columns using update statements when there was just a few. The above query is really just a sample of a much larger query with many more columns. The actual request has blossomed into 6 date ranges for 13 columns. I'm asking if there's a better way then using 78 additional update statements.
I think you will have a hard time writing a query that includes all of these 78 metrics per e-mail address without actually creating a query that hard-codes the different choices. However you can generate such a pivot query with dynamic SQL, which will save you some keystrokes and will adjust dynamically as you add more columns to the table.
The result you want to end up with will look something like this (but of course you won't want to type it):
;WITH y AS
(
SELECT
EMAIL_ADDRESS,
/* aggregation portion */
[ADDRESS_1] = COUNT(DISTINCT [ADDRESS_1]),
[ADDRESS_2] = COUNT(DISTINCT [ADDRESS_2]),
... other columns
/* end agg portion */
FROM dbo.WEB_LEADS AS wl
WHERE ROW_ADDED_DTM >= /* one of 6 past dates */
GROUP BY wl.EMAIL_ADDRESS
)
SELECT EMAIL_ADDRESS,
/* pivot portion */
COUNT_ADDRESS_1_LAST_1_DAYS = *count address 1 from 1 day ago*,
COUNT_ADDRESS_1_LAST_7_DAYS = *count address 1 from 7 days ago*,
... other date ranges ...
COUNT_ADDRESS_2_LAST_1_DAYS = *count address 2 from 1 day ago*,
COUNT_ADDRESS_2_LAST_7_DAYS = *count address 2 from 7 days ago*,
... other date ranges ...
... repeat for 11 more columns ...
/* end pivot portion */
FROM y
GROUP BY EMAIL_ADDRESS
ORDER BY EMAIL_ADDRESS;
This is a little involved, and it should all be run as one script, but I'm going to break it up into chunks to intersperse comments on how the above portions are populated without typing them. (And before long #Bluefeet will probably come along with a much better PIVOT alternative.) I'll enclose my interspersed comments in /* */ so that you can still copy the bulk of this answer into Management Studio and run it with the comments intact.
Code/comments to copy follows:
/*
First, let's build a table of dates that can be used both to derive labels for pivoting and to assist with aggregation. I've added the three ranges you've mentioned and guessed at a fourth, but hopefully it is clear how to add more:
*/
DECLARE #d DATE = SYSDATETIME();
CREATE TABLE #L(label NVARCHAR(15), d DATE);
INSERT #L(label, d) VALUES
(N'LAST_1_DAYS', DATEADD(DAY, -1, #d)),
(N'LAST_7_DAYS', DATEADD(DAY, -8, #d)),
(N'LAST_14_DAYS', DATEADD(DAY, -15, #d)),
(N'LAST_MONTH', DATEADD(MONTH, -1, #d));
/*
Next, let's build the portions of the query that are repeated per column name. First, the aggregation portion is just in the format col = COUNT(DISTINCT col). We're going to go to the catalog views to dynamically derive the list of column names (except ID, EMAIL_ADDRESS and ROW_ADDED_DTM) and stuff them into a #temp table for re-use.
*/
SELECT name INTO #N FROM sys.columns
WHERE [object_id] = OBJECT_ID(N'dbo.WEB_LEADS')
AND name NOT IN (N'ID', N'EMAIL_ADDRESS', N'ROW_ADDED_DTM');
DECLARE #agg NVARCHAR(MAX) = N'', #piv NVARCHAR(MAX) = N'';
SELECT #agg += ',
' + QUOTENAME(name) + ' = COUNT(DISTINCT '
+ QUOTENAME(name) + ')' FROM #N;
PRINT #agg;
/*
Next we'll build the "pivot" portion (even though I am angling for the poor man's pivot - a bunch of CASE expressions). For each column name we need a conditional against each range, so we can accomplish this by cross joining the list of column names against our labels table. (And we'll use this exact technique again in the query later to make the /* one of past 6 dates */ portion work.
*/
SELECT #piv += ',
COUNT_' + n.name + '_' + l.label
+ ' = MAX(CASE WHEN label = N''' + l.label
+ ''' THEN ' + QUOTENAME(n.name) + ' END)'
FROM #N as n CROSS JOIN #L AS l;
PRINT #piv;
/*
Now, with those two portions populated as we'd like them, we can build a dynamic SQL statement that fills out the rest:
*/
DECLARE #sql NVARCHAR(MAX) = N';WITH y AS
(
SELECT
EMAIL_ADDRESS, l.label' + #agg + '
FROM dbo.WEB_LEADS AS wl
CROSS JOIN #L AS l
WHERE wl.ROW_ADDED_DTM >= l.d
GROUP BY wl.EMAIL_ADDRESS, l.label
)
SELECT EMAIL_ADDRESS' + #piv + '
FROM y
GROUP BY EMAIL_ADDRESS
ORDER BY EMAIL_ADDRESS;';
PRINT #sql;
EXEC sp_executesql #sql;
GO
DROP TABLE #N, #L;
/*
Now again, this is a pretty complex piece of code, and perhaps it can be made easier with PIVOT. But I think even #Bluefeet will write a version of PIVOT that uses dynamic SQL because there is just way too much to hard-code here IMHO.
*/