I am a newbie to both stackoverflow and SQL, so I do hope for your understanding ! Recently I have faced many SQL issues and I do hope some help could be provided to aid me. This is because I have tried sourcing for information, some did answer to my problems, but gave me more problems after that.
Firstly, I have seen a recent post by user javascriptstress in his replacement of values in a column. In my issue, I was working on credit card details in SQL whereby I had to censor the digits on the user's credit card values, which will show a result of xxxxxxxxxxxx2345 instead of '2734948533562345' for Visa card. However by using SUBSTRING and LEN I am unable to get the values hidden. Due to the fact that not all credit cards have 16 digits, I have faced the problem of only providing the last 4 digits of the credit card number. It sure is possible if i code each credit card number one by one, but what if I have to hide the first 12 numbers for many credit cards? Is there a more convenient way of settling this ?
Help is greatly appreciated!
Ps. I'm kind of new to technology, I'm sorry for any problems caused :(
If you're querying:
SELECT REPLICATE('x', LEN(ccnumber) - 4) + RIGHT(ccnumber, 4))
FROM ...
REPLICATE repeats the string n times.
RIGHT takes the n rightmost characters from the string.
For SQL 2012 onward I'd recommend the safer CONCAT to assemble the string:
SELECT
CONCAT(
REPLICATE('x', LEN(ccnumber) - 4),
RIGHT(ccnumber, 4))
FROM ...
CONCAT concatenates two strings; the + operator also does this but CONCAT will never treat the values as numbers and try to add them.
You can dynamically determine where to cut the string based on it's length, then use REPLICATE to pad by the correct amount.
DECLARE #cc VARCHAR(16) = '1234123412341234'
DECLARE #len INT
SELECT #len = LEN(#cc)
DECLARE #ss VARCHAR(4)
SELECT #ss = SUBSTRING(#cc, LEN(#cc)-3, 4)
SELECT REPLICATE('X', #len-4) + #ss
Output:
XXXXXXXXXXXX1234
This is obviously not a PCI-compliant way of dealing with credit card data.
You could chain these statements together to use them in a larger SELECT statement. You could even define a scalar valued function that lets you call it without the hassle.
A slightly cleaner version of this (without the variable declarations I put in for sake of example):
SELECT REPLICATE('X', LEN(#cc)-4) + SUBSTRING(#cc, LEN(#cc)-3, 4)
But I would suggest using Mr. Gibbs version as it using the RIGHT function to simplify it even more.
Related
I have to truncate the first couple of digits out of a Guid on a table. Is it possible to do it only using a SQL script? Or I have to do it programatically?
Thanks!
To answer the direct question at hand (and assume the column's name is foo):
foo is uniqueidentifier:
SELECT substring(convert(nvarchar(50), foo), 3)
foo is simply a string:
SELECT substring(foo, 3)
3 is just an arbitrary starting offset to remove the first "few" characters.
With that said, this sounds like of like an XY problem. If you're running into an issue where you feel you need to truncate the first few characters, it would be important to list that information in your question as well as what you've described sounds like an odd request. However, you're also entitled to have odd requests.
The previous answer was perfectly good. Another option is to use the wonderful RIGHT function. Assuming the Guid is a a uniqueidentifier, then it has 36 characters in it. Just use RIGHT(theguid, 34), e.g.
declare #temp as uniqueidentifier = newid();
select right(#temp, 34);
I have a string column where I need to find the substring until the first '-' is found.
Example column ELOT-IGS-2. I need to get "2" as output.
These columns come from a table so I cannot declare the variable as a fixed string.
I tried LOCATE, SUBSTRING_INDEX but none are build in functions.
I also tried RIGHT(ID_BETSLIP,CHARINDEX('-',ID_BETSLIP)-1) but this does not work when I have 2 times "-"
Does anyone have an idea?
select RIGHT(<your Field>, CHARINDEX('-',REVERSE(<your Field>))-1)
DECLARE #t varchar(20) = 'ELOT-IGS-2'
select REVERSE(SUBSTRING(reverse(#t),0,CHARINDEX ('-',REVERSE(#t))))
Simplest would be
select SUBSTRING(reverse(ELOT-IGS-2),0,charindex('-',reverse(ELOT-IGS-2)))
Based on #mohan111's solution you can add REVERSE in order to get what you need
DECLARE #t varchar(20) = 'ELOT-IGS-2'
select REVERSE(SUBSTRING(reverse(#t),0,CHARINDEX ('-',REVERSE(#t))))
You should have done this yourself, once you got #mohan111's solution! For your own improvement you can not ask for everything :-( Once you got a solution that is almost what you need, it is time to try to improve it yourself. Please check this MSDN page, and every time that you need to parse a string, START HERE :-) Try to go over the functions and maybe you will find the solution.
The REVERSE query and most string parsing function are not good solution in SQL Server, and in most cases you are better to do this using SQLCLR function.
I need to split a string value that has no delimiter. I work in banking and I am selecting a GL account number and need to separate the account number from the account branch number. The issue is both values are passed as one long string, 10 digits for the account number and 4 for the account branch. For example 01234567891234 needs to be changed to 0123456789.1234.
Every thing I find says to use CHARINDEX or SUBSTRING. From my understand both require a character to search for. If anyone can provide another function and some example code that would be great. Thanks.
You can do something simple like
left(str, 10) + '.' + right(str, 4)
if you know it'll always be a 14 character string
You could also use STUFF function as below:
declare #accNo varchar(14) = '01234567891234'
select stuff(#accNo,11,0,'.')
SQL Fiddle
Just ran into a major headache when concatenating several #varchar(max) variables together to build an email based on several different queries.
For efficiencies sake, I was using several varchars to build the email at once, rather than going through roughly the same query two or three or more times to build it using only one varchar.
This worked, right up until my varchars got to longer than 8000 characters. Then the concatenation of them all into one varchar (which I could shove into the #body parameter of msdb.dbo.sp_send_dbmail) returned "", and even LEN() wouldn't actually give me a length.
Anyhow, I've gotten around this by doing roughly the same queries several times and building the email with only one varchar(max).
TL;DR
I'm not happy with the solution. How could I have appended these varchar(max) variables to each other?
One thing I've hit in the past which may or may not help here: SQL seems to "forget" what datatype its working with when you concatenate varchar(max). Instead of maintaining the MAX, it devolves to conventional varcharnitude, meaning truncation at 8000 characters or so. To get around this, we use the following trick:
Start with
SET #MyMaxVarchar = #aVarcharMaxValue + #SomeString + #SomeOtherString + #etc
and revise like so:
SET #MyMaxVarchar = cast(#aVarcharMaxValue as varchar(max)) + #SomeString + #SomeOtherString + #etc
Again, this may not help with your particular problem, but remembering it might save you major headaches down the road some day.
This may not have happened in your case, but there's a "gotcha" embedded in SQL Management Studio involving VARCHAR(MAX): SQL Studio will only output so many characters in the results grid. You can test this:
SELECT #MyLongVar, LEN(#MyLongVar)
You may find that the length of the actual data returned (most text editors can give you this) is less than the length of the data stored in the variable.
The fix is in Tools | Options | Query Results | SQL Server | Results to Grid; increase Maximum Characters Retrieved | Non XML data to some very large number. Unfortunately the maximum is 65,535, which may not be enough.
If your problem does not involve outputting the variable's value in SQL Studio, please disregard.
I have found that MS SQL silently does NOTHING when attempting to concatentate a string to a NULL value. therefore this solution always works for me:
UPDATE myTable
SET isNull(myCol, '') += 'my text'
WHERE myColumnID = 9999
We faced a very strange issue (really strange for such mature product):
how to get number of characters in Unicode string using Transact-SQL statements.
The key problem of this issue that the len() TSQL function returns number of chars, excluding trailing blanks. The other variant is to use datalength (which return number of bytes) and divide by 2, so get numbers of Unicode chars. But Unicode chars can be surrogate pairs so it won't work either.
We have 2 variants of solution: the first is to use len(replace()) and the second is add a single symbol and then subtract 1 from result. But IMO both variants are rather ugly.
declare #txt nvarchar(10)
set #txt = 'stack '
select #txt as variable,
len(#txt) as lenBehaviour,
DATALENGTH(#txt)/2 as datalengthBehaviour,
len(replace(#txt,' ','O')) as ReplaceBehaviour,
len(#txt+'.')-1 as addAndMinusBehaviour
Any other ideas how to count chars in string with trailing spaces?
I can't leave a comment so I will have to leave an answer (or shutup).
My vote would be for the addAndMinusBehaviour
I haven't got a good third alternative, there maybe some obscure whitespace rules to fiddle with in the options / SET / Collation assignment but don't know more detail off the top of my head.
but really addAndMinusBehaviour is probably the eaiest to implement, fastest to execute and if you document it, farily maintainable as well.
CREATE FUNCTION [dbo].[ufn_CountChar] ( #pInput VARCHAR(1000), #pSearchChar CHAR(1) )
RETURNS INT
BEGIN
RETURN (LEN(#pInput) - LEN(REPLACE(#pInput, #pSearchChar, '')))
END
GO
My understanding is that DATALENGTH(#txt)/2 should always give you the number of characters. SQL Server stores Unicode characters in UCS-2 which does not support surrogate pairs.
http://msdn.microsoft.com/en-us/library/ms186939.aspx
http://en.wikipedia.org/wiki/UCS2