Related
Using tsql I want to count a numeric chars in string. For example i've got 'kick0my234ass' string and i wanna count how many (4 in that example) numbers are in that string. I can't use regex, just plain tslq.
You COULD do this I suppose:
declare #c varchar(30)
set #c = 'kick0my234ass'
select #c, len(replace(#c,' ','')) - len(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(#c,'0',''),'1',''),'2',''),'3',''),'4',''),'5',''),'6',''),'7',''),'8',''),'9',''),' ',''))
You'll first have to split the character string in its individual characters, evaluate which are numeric, and finally count those that are. This will do the trick:
DECLARE #test TABLE (Example NVARCHAR(255))
INSERT #test
VALUES ('kick0my234ass')
SELECT COUNT(1)
FROM #test AS T
INNER JOIN master..spt_values v
ON v.type = 'P'
AND v.number < len(T.Example)
WHERE SUBSTRING(T.Example, v.number + 1, 1) LIKE '[0-9]'
You could try this solution with regular expressions (if you'd allow them):
it uses recursive CTE, at every recursive step, one digit is removed from given string and the condition is to stop, when there are no digits in string. The rows are also numbered with consecutive ids, so the last id is the amount of removed digits from string.
declare #str varchar(100) = 'kick0my123ass';
with cte as (
select 1 [id], stuff(#str,PATINDEX('%[0-9]%', #str),1,'') [col]
union all
select [id] + 1, stuff([col],PATINDEX('%[0-9]%', [col]),1,'') from cte
where col like '%[0-9]%'
)
--this will give you number of digits in string
select top 1 id from cte order by id desc
Use a WHILE loop to each each character is a numeric or not.
Query
declare #text as varchar(max) = 'kick0my234ass';
declare #len as int;
select #len = len(#text);
if(#len > 0)
begin
declare #i as int = 1;
declare #count as int = 0;
while(#i <= #len)
begin
if(substring(#text, #i, 1) like '[0-9]')
set #count += 1;
set #i += 1;
end
print 'Count of Numerics in ' + #text + ' : ' + cast(#count as varchar(100));
end
else
print 'Empty string';
If simplicity & performance are important I suggest a purely set-based solution. Grab a copy of DigitsOnlyEE which will remove all non-numeric characters. Then use LEN against the output.
DECLARE #string varchar(100) = '123xxx45ff678';
SELECT string = #string, digitsOnly, DigitCount = LEN(digitsOnly)
FROM dbo.DigitsOnlyEE(#string);
Results
string digitsOnly DigitCount
------------------ ----------- ------------
123xxx45ff678 12345678 8
using a Tally Table created by an rCTE:
CREATE TABLE #Sample (S varchar(100));
INSERT INTO #Sample
VALUES ('kick0my234 ass');
GO
WITH Tally AS(
SELECT 1 AS N
UNION ALL
SELECT N + 1
FROM Tally
WHERE N + 1 <= 100)
SELECT S.S, SUM(CASE WHEN SUBSTRING(S,T.N, 1) LIKE '[0-9]' THEN 1 ELSE 0 END) AS Numbers
FROM #Sample S
JOIN Tally T ON LEN(S.S) >= T.N
GROUP BY S.S;
For future reference, also post your owns attempts please. We aren't here (really) to do your work for you.
I am migrating sensitive data to a database, and I need to hide details of the text. We would like to keep the volume and length of the text, but change the meaning.
For example:
"James has been well received, and should be helped when ever he finds it hard to speak"
should change to:
"jhdfy dfw aslk dfe kjdfkjd, kjf kjdsf df iotryy erhr lsdj jf ytwe it kjdf tr kjsdd"
Is there a way to update all rows, set the column text to this random type text? Really only want to change charactors (a-z, A-Z), and keep the rest.
One option is to use a bunch of nested replaces . . . but that would probably hit on the maximum number of nested functions.
You could write a painful query using outer apply:
select
from t outer apply
(select replace(t.col, 'a', 'z') as col1) outer apply
(select replace(col1, 'b', 'y') ) outer apply
. . .
However, you might want to write your own function. In other databases, this is called translate() (after the Unix command). If you Google SQL Server translate, I think you'll find examples on the web.
One way is to split the string character by character and replace each row with a random string. And then concatenate them back to get the desired output
DECLARE #str VARCHAR(MAX) = 'James has been well received, and should be helped when ever he finds it hard to speak'
;WITH Cte(orig, random) AS(
SELECT
SUBSTRING(t.a, v.number + 1, 1),
CASE
WHEN SUBSTRING(t.a, v.number + 1, 1) LIKE '[a-z]'
THEN CHAR(ABS(CHECKSUM(NEWID())) % 25 + 97)
ELSE SUBSTRING(t.a, v.number + 1, 1)
END
FROM (SELECT #str) t(a)
CROSS JOIN master..spt_values v
WHERE
v.number < LEN(t.a)
AND v.type = 'P'
)
SELECT
OrignalString = #str,
RandomString = (
SELECT '' + random
FROM Cte FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'
)
TRY IT HERE
OK this is possible using a user defined function (UDF) and a view.
SQL Server does not allow random number generation in a UDF but does allow it in a view. Ref: http://blog.sqlauthority.com/2012/11/20/sql-server-using-rand-in-user-defined-functions-udf/
So here is the solution
CREATE VIEW [dbo].[rndView]
AS
SELECT RAND() rndResult
GO
CREATE FUNCTION [dbo].[RandFn]()
RETURNS float
AS
BEGIN
DECLARE #rndValue float
SELECT #rndValue = rndResult
FROM rndView
RETURN #rndValue
END
GO
CREATE FUNCTION [dbo].[randomstring] ( #stringToParse VARCHAR(MAX))
RETURNS
varchar(max)
AS
BEGIN
/*
A = 65
Z = 90
a = 97
z = 112
declare #stringToParse VARCHAR(MAX) = 'James has been well received, and should be helped when ever he finds it hard to speak'
Select [dbo].[randomstring] ( #stringToParse )
go
Update SpecialTable
Set SpecialString = [dbo].[randomstring] (SpecialString)
go
*/
declare #StringToreturn varchar(max) = ''
declare #charCounter int = 1
declare #len int = len(#stringToParse)
declare #thisRand int
declare #UpperA int = 65
declare #UpperZ int = 90
declare #LowerA int = 97
declare #LowerZ int = 112
declare #thisChar char(1)
declare #Random_Number float
declare #randomChar char(1)
WHILE #charCounter < #len
BEGIN
SELECT #thisChar = SUBSTRING(#stringToParse, #charCounter, 1)
set #randomChar = #thisChar
--print #randomChar
SELECT #Random_Number = dbo.RandFn()
--print #Random_Number
--only swap if a-z or A-Z
if ASCII(#thisChar) >= #UpperA and ASCII(#thisChar) <= #UpperZ begin
--upper case
set #thisRand = #UpperA + (#Random_Number * convert(float, (#UpperZ-#UpperA)))
set #randomChar = CHAR(#thisRand)
--print #thisRand
end
if ASCII(#thisChar) >= #LowerA and ASCII(#thisChar) <= #LowerZ begin
--upper case
set #thisRand = #LowerA + (#Random_Number * convert(float, (#LowerZ-#LowerA)))
set #randomChar = CHAR(#thisRand)
end
--print #thisRand
--print #randomChar
set #StringToreturn = #StringToreturn + #randomChar
SET #charCounter = #charCounter + 1
END
--Select * from #returnList
return #StringToreturn
END
GO
I am trying to create a while loop in SQL and it seems kind of complex. Here's what I need it to achieve:
Iterate through a single VARCHAR string (ex. '123')
If the nth character is in an even position in the string (ex. 2nd, 4th .... letter in the string), it must be added(SUM) to a base variable (Let's assume #z)
If the nth character is in an odd position in the string (ex. 1st, 3rd .... letter in the string), it must be multiplied by 2. If this newly generated value (Let's assume #y) is less than 10, it must be added(SUM) to the base variable (Still the same assumed #z). If #y is greater than 10, we need to subtract 9 from #y before adding(SUM) it to #z
After iterating through the entire string, this should return a numeric value generated by the above process.
Here is what I've done so far, but I'm stuck now (Needless to say, this code does not work yet, but I think I'm heading in the right direction):
DECLARE #x varchar(20) = '12345'
DECLARE #p int = len(#x)
WHILE #p > 0
SELECT #x =
stuff(#x, #p, 1,
case when CONVERT(INT,substring(#x, #p, 1)) % 2 = 0 then CONVERT(INT, #x) + CONVERT(INT,substring(#x, #p, 1))
end), #p -= 1
RETURN #x;
PS. The input will always be 100% numeric values, but it is formatted as VARCHAR when I recieve it.
UPDATE
The expected result for the sample string is 15
You can do this without using a loop. Here is a solution using Tally Table:
DECLARE #x VARCHAR(20) = '12345'
DECLARE #z INT = 0 -- base value
;WITH E1(N) AS( -- 10 ^ 1 = 10 rows
SELECT 1 FROM(VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))t(N)
),
E2(N) AS(SELECT 1 FROM E1 a CROSS JOIN E1 b), -- 10 ^ 2 = 100 rows
E4(N) AS(SELECT 1 FROM E2 a CROSS JOIN E2 b), -- 10 ^ 4 = 10,000 rows
CteTally(N) AS(
SELECT TOP(LEN(#x)) ROW_NUMBER() OVER(ORDER BY(SELECT NULL))
FROM E4
),
CteChars(N, num) AS(
SELECT
t.N, CAST(SUBSTRING(#x, t.N, 1) AS INT)
FROM CteTally t
WHERE t.N <= LEN(#x)
)
SELECT
SUM(
CASE
WHEN N % 2 = 0 THEN num
WHEN num * 2 < 10 THEN num * 2
ELSE (num * 2) - 9
END
) + #z
FROM CteChars
The CTEs up to CteTally generates a list of number from 1 to LEN(#x). CteChars breaks #x character by character into separate rows. Then the final SELECT does a SUM based on the conditions.
OUTPUT : 15
Check below if it helps you
DECLARE #x varchar(20) = '12345'
DECLARE #p int = 1
DECLARE #result bigint=0;
DECLARE #tempval int =0;
WHILE #p <= len(#x)
BEGIN
SET #tempval = CONVERT(INT,substring(#x, #p, 1));
if(#p%2 = 1)
BEGIN
SET #tempval = #tempval * 2;
IF(#tempval >= 10) SET #tempval = #tempval - 9;
END
SET #result = #result + #tempval;
SET #p = #p + 1;
END;
PRINT #result;--This is the result
RETURN #x;
DECLARE #x INT = 12345
DECLARE #p int = len(#x)
DECLARE #z INT =0
PRINT #p%2
SET #x=#x/10
PRINT #x
WHILE #p > 0
BEGIN
IF(#p%2 = 0)
BEGIN
SET #z=#z+#x%10
SET #p=#p-1
SET #x=#x/10
END
ELSE
BEGIN
SET #z=#z+(2*(#x%10))
SET #p=#p-1
SET #x=#x/10
IF(#x>=10)
BEGIN
SET #x=(#x/10+#x%10)
END
END
END
SELECT #z
The while loop does not seem necessary here.
This can be achieved with a CTE that will split the string and a case statement:
DECLARE #x varchar(20) = '12345';
with split(id, v) as (
select 0, cast(0 as tinyint)
union all
select id+1, cast(SUBSTRING(#x, id+1, 1) as tinyint)
From split
Where id+1 <= len(#x)
)
Select Result = SUM(
Case When id % 2 = 0 then v
When v < 5 then v*2
Else (v*2)-9
End
)
From split
output = 15
I am using SQL Server, the column is a VARCHAR(50) and I want to sort it like this:
1A
1B
2
2
3
4A
4B
4C
5A
5B
5C
5N
14 Draft
21
22A
22B
23A
23B
23C
23D
23E
25
26
FR01584
MISC
What I have so far is:
Select *
From viewASD
ORDER BY
Case When IsNumeric(LEFT(asdNumNew,1)) = 1
Then CASE When IsNumeric(asdNumNew) = 1
Then Right(Replicate('0',20) + asdNumNew + '0', 20)
Else Right(Replicate('0',20) + asdNumNew, 20)
END
When IsNumeric(LEFT(asdNumNew,1)) = 0
Then Left(asdNumNew + Replicate('',21), 20)
End
But this SQL statement puts '14 Draft' right after '26'.
Could someone help? Thanks
Your WHERE statement is... oddly complex.
It looks like you want to sort by any leading numeric digits in integer order, and then sort by the remainder. If so, you should do that as separate clauses, rather than trying to do it all in one. The specific issue you're having is that you're only allowing for a single-digit number, instead of two or more. (And there's No such thing as two.)
Here's your fix, along with a SQLFiddle, using two separate calculated columns tests for your ORDER BY. (Note that this assumes the numeric portion of asdNumNew will fit in a T-SQL int. If not, you'll need to adjust the CAST and the maximum value on the first ELSE.)
SELECT * FROM viewASD
ORDER BY
CASE
WHEN ISNUMERIC(asdNumNew)=1
THEN CAST(asdNumNew as int)
WHEN PATINDEX('%[^0-9]%',asdNumNew) > 1
THEN CAST(
LEFT(
asdNumNew,
PATINDEX('%[^0-9]%',asdNumNew) - 1
) as int)
ELSE 2147483648
END,
CASE
WHEN ISNUMERIC(asdNumNew)=1
THEN NULL
WHEN PATINDEX('%[^0-9]%',asdNumNew) > 1
THEN SUBSTRING(
asdNumNew,
PATINDEX('%[^0-9]%',asdNumNew) ,
50
)
ELSE asdNumNew
END
If all numbers within the string are reasonably small, say not exceeding 10 digits,
you may expand all the numbers in the string to be exactly 10 digits:
123A -> 0000000123A
S4 -> S0000000004
A3B89 -> A0000000003B0000000089
and so on and then sort them
-- Expand all numbers within S by zeros to be MaxLen
create function [dbo].ExpandNumbers(#S VarChar(4000), #maxlen integer) returns VarChar(4000)
as
begin
declare #result VarChar(4000);
declare #buffer VarChar(4000);
declare #Ch Char;
declare #i integer;
set #buffer = '';
set #result = '';
set #i = 1;
while (#i <= len(#S))
begin
set #Ch = substring(#S, #i, 1);
if ((#Ch >= '0') and (#Ch <= '9'))
set #buffer = #buffer + #Ch
else
begin
if (len(#buffer) > 0)
set #result = #result + right(replicate('0', #maxlen) + #buffer, #maxlen);
set #buffer = '';
set #result = #result + #Ch;
end;
set #i = #i + 1;
end;
if (len(#buffer) > 0)
set #result = #result + right(replicate('0', #maxlen) + #buffer, #maxlen);
return #result;
end;
-- Final query is
select *
from viewASD
order by [dbo].ExpandNumbers(asdNumNew)
I had something similar, but with the possibility of dashes as leading characters as well as trailing spaces. This code worked for me.
SELECT
my_column,
PATINDEX('%[^0-9]%',my_column) AS first_alpha_position,
CONVERT(INT,
CASE
WHEN PATINDEX('%[^0-9]%',my_column) = 0 OR PATINDEX('-%',my_column) = 1
THEN ABS(my_column)
ELSE SUBSTRING(my_column,1,PATINDEX('%[^0-9]%',my_column) -1)
END) AS numeric_value,
LTRIM(
SUBSTRING(my_column,PATINDEX('%[^0-9]%',my_column),LEN(my_column)-PATINDEX('%[^0-9]%',my_column)+1)
) AS alpha_chars
FROM my_table
ORDER BY numeric_value,alpha_chars
TRY THIS
DECLARE #t table (Number nvarchar(20))
INSERT INTO #t
SELECT 'L010'
UNION ALL SELECT 'L011'
UNION ALL SELECT 'L011'
UNION ALL SELECT 'L001'
UNION ALL SELECT 'L012'
UNION ALL SELECT '18'
UNION ALL SELECT '8'
UNION ALL SELECT '17'
UNION ALL SELECT 'B004'
UNION ALL SELECT 'B006'
UNION ALL SELECT 'B008'
UNION ALL SELECT 'B018'
UNION ALL SELECT 'UG001'
UNION ALL SELECT 'UG011'
UNION ALL SELECT 'G001'
UNION ALL SELECT 'G002'
UNION ALL SELECT 'G011';
SELECT Number
FROM #t
ORDER BY
CAST
(
SUBSTRING
(
Number
, 1
, CASE
WHEN patindex('%[^0-9]%',Number) > 0 THEN patindex('%[^0-9]%',Number) - 1
ELSE LEN(Number) END
) AS int
)
, Number
What worked for me is I split up the numeric and the alpha parts and then sorted based on the Alpha, then the Numeric:
CREATE FUNCTION [admin].[GetUnitNumberAsIntFunc](#UnitNumber varchar(20))
RETURNS int
BEGIN
DECLARE #intPosition int
SET #intPosition = PATINDEX('%[^0-9]%', #UnitNumber)
WHILE #intNumber > 0
BEGIN
SET #UnitNumber = STUFF(#UnitNumber, #intNumber, 1, '')
SET #intPosition = PATINDEX('%[^0-9]%', #UnitNumber)
END
RETURN ISNULL(#UnitNumber,9999)
END;
CREATE FUNCTION [admin].[GetUnitNumberAsStrFunc](#UnitNumber varchar(20))
RETURNS varchar(20)
BEGIN
DECLARE #intPosition int
SET #intPosition = PATINDEX('%[0-9]%', #UnitNumber)
SET #UnitNumber = STUFF(#UnitNumber, #intPosition, 6, '')
RETURN ISNULL(#UnitNumber,9999)
END;
i want to change case using sql query
e.g if text is : My nAme is iShAn halaRNkar (text is jumbled i.e it may contain Lower case or Upper case anywhere in the senetence)
than i want the output to be : My Name Is Ishan Halarnkar
i have not worked on sql queries much. Kindly help.
Here is another Microsoft SQL function:
CREATE FUNCTION PROPERCASE(#TEXT AS VARCHAR(MAX))
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE #RESET BIT;
DECLARE #STR VARCHAR(MAX);
DECLARE #I INT;
DECLARE #C CHAR(1);
SELECT #RESET = 1, #I=1, #STR = '';
WHILE (#I <= LEN(#TEXT))
SELECT #C= SUBSTRING(#TEXT,#I,1),
#STR = #STR + CASE WHEN #RESET=1 THEN UPPER(#C) ELSE LOWER(#C) END,
#RESET = CASE WHEN #C LIKE '[A-ZA-Z]' THEN 0 ELSE 1 END,
#I = #I +1
RETURN #STR
END
There's no such function in any database which do this for you. You've to write a function which actually performs the check on each word in a sentence. Please check the solutions below:
MySql:
DELIMITER //
CREATE FUNCTION CAP_FIRST (input VARCHAR(255))
RETURNS VARCHAR(255)
DETERMINISTIC
BEGIN
DECLARE len INT;
DECLARE i INT;
SET len = CHAR_LENGTH(input);
SET input = LOWER(input);
SET i = 0;
WHILE (i < len) DO
IF (MID(input,i,1) = ' ' OR i = 0) THEN
IF (i < len) THEN
SET input = CONCAT(
LEFT(input,i),
UPPER(MID(input,i + 1,1)),
RIGHT(input,len - i - 1)
);
END IF;
END IF;
SET i = i + 1;
END WHILE;
RETURN input;
END//
DELIMITER ;
Example:
SELECT CAP_FIRST('this is exACtly tHe same!')
Output:
This Is Exactly The Same!
Copyrights:
http://joezack.com/2008/10/20/mysql-capitalize-function/
Hope this helps!
This SQL should work.
SELECT UPPER(LEFT(<ColumnName>, 1)) + LOWER(RIGHT(<ColumnName>,LEN(<ColumnName>)-1)) FROM {YourTableName}
First you need to create function
CREATE FUNCTION ProperCase(#OriginalText VARCHAR(8000))
RETURNS VARCHAR(8000)
BEGIN
DECLARE #CleanedText VARCHAR(8000)
;with
a1 as (select 1 as N union all select 1 union all
select 1 union all select 1 union all
select 1 union all select 1 union all
select 1 union all select 1 union all
select 1 union all select 1),
a2 as (select 1 as N from a1 as a cross join a1 as b),
a3 as (select 1 as N from a2 as a cross join a2 as b),
a4 as (select 1 as N from a3 as a cross join a2 as b),
Tally as (select top (len(#OriginalText)) row_number() over (order by N) as N from a4)
SELECT #CleanedText = ISNULL(#CleanedText,'') +
--first char is always capitalized?
CASE WHEN Tally.N = 1 THEN UPPER(SUBSTRING(#OriginalText,Tally.N,1))
WHEN SUBSTRING(#OriginalText,Tally.N -1,1) = ' ' THEN UPPER(SUBSTRING(#OriginalText,Tally.N,1))
ELSE LOWER(SUBSTRING(#OriginalText,Tally.N,1))
END
FROM Tally WHERE Tally.N
Now you just use this function
select dbo.ProperCase('My nAme is iShAn halaRNkar')