Remove a particular character from varchar while retrieving data using query - sql

I want to remove a particular character while retrieving a varchar from a table. The query looks like this:
SELECT ServiceName,
case isNumeric(Ramusage)
when 1 then
cast ( ltrim ( rtrim ( ramusage )) as int )
else
0
end as test,
priority
FROM ProcessInfo
Here the problem is ramusage is a varchar and it stores values like 12,500K, 4,321K.
Here I want to remove the "K" from the entry and display the number alone.

You want to use the REPLACE function:
REPLACE(ramusage, 'k', '')
Reference:
SQL Server
Oracle
MySQL

Use REPLACE
DECLARE #ProcessInfo TABLE(
ServiceName VARCHAR(MAX),
Ramusage VARCHAR(MAX),
priority INT
)
INSERT INTO #ProcessInfo (ServiceName,Ramusage,priority)
SELECT 'TEST','12,123K',1
SELECT ServiceName,
case isNumeric(REPLACE(REPLACE(Ramusage,'K',''),',',''))
when 1 then
cast ( ltrim ( rtrim ( REPLACE(REPLACE(Ramusage,'K',''),',',''))) as int )
else
0
end as test,
priority
FROM #ProcessInfo
what we have done is to create a CLR function to take a string amd remove all non numeric items
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString RemoveNonNumeric(SqlString strValue)
{
string strNew = strValue.ToString();
char[] chrArray = strNew.ToCharArray();
strNew = null;
for (int iChar = 0; iChar < chrArray.Length; iChar++)
{
if (Char.IsNumber(chrArray[iChar]))
strNew += chrArray[iChar];
}
// Put your code here
return new SqlString(strNew);
}

substr( ltrim( rtrim( ramusage ) ), length( ramusage ) - 1)
edit: replace, as mentioned in the other answers, is probably better.

Related

How i can split column delimited by , in SSAS DAX

I have GPS coordinates in my column (latitude and longitude separated by ,) and I am trying to get them into two separate columns.
I am using the below formula but it is not working.
= PATHITEM ( SUBSTITUTE ( Fault[lastgps], “,”, “|” ), 1 )
1 represents position.
Your quotes look weird to me. Does this work?
= PATHITEM ( SUBSTITUTE ( Fault[lastgps], ",", "|" ), 1 )
Try this to handle different lat long sizes and separators:
EVALUATE
VAR V_Str = "-23.1232630, -46.68211551"
VAR V_Sep = ", "
VAR V_Pos = FIND(V_Sep,V_Str)
RETURN
ROW(
"Lat",LEFT(V_Str,V_Pos-1),
"Long",RIGHT(V_Str,LEN(V_Str)-LEN(V_Sep)-V_Pos+1)
)

Converting comma-separated value to in subquery

I have following query :
Set #OrderStatuses = 'Cancelled,Complete'
Select *
From TableName
Where Status in (#OrderStatuses)
The Status is what I am receiving externally and it fails to fetch any result as, what we actually need to process is:
Select *
From TableName
Where Status in ('Cancelled', 'Complete');
#OrderStatuses can contain any number of comma-separated values.
One method is dynamic SQL:
declare #sql nvarchar(max);
set #sql = 'Select * from TableName Where Status in (#list)';
set #sql = replace(#sql, '#list', '#OrderStatuses');
exec sp_executesql #sql;
Note: You cannot pass a list in as a parameter.
You can also use like:
Select *
from TableName
Where ',' + #OrderStatuses + ',' like '%,' + Status + ',%';
However, this cannot use an index for the the comparison.
You will need to use split string function and process the rest..
;with cte
as
(
select * from split_strings(#orderstatus,',')
)
select * from table where status in (select item from cte)
You must add the list as a Table-Valued Parameter
Here are two methods I use to convert any IEnumerable list of items (in this case, integers) into a Table Valued Parameter. You have to have created/defined a User Defined type (UDT) for the resultant table in your database. In the example below the UDT is named dbo.keyIds and is created (once) with this SQL:
CREATE TYPE [dbo].[KeyIds]
AS TABLE(pkId int NOT NULL, PRIMARY KEY CLUSTERED
( [pkId] ASC) WITH (IGNORE_DUP_KEY = OFF)
)
The c# code is:
public class DbParamList : List<IDbDataParameter>
{
public void AddSQLTableParm<T>(
string parmName, IEnumerable<T> values)
{
var parm = new SqlParameter(parmName, CreateDataTable(values))
{
SqlDbType = SqlDbType.Structured,
TypeName = "dbo.keyIds"
};
Add(parm);
}
internal static DataTable CreateDataTable<T>(IEnumerable<T> values)
{
var dt = new DataTable();
var props = typeof (T).GetProperties();
if (props.Length > 0)
{
foreach (var col in props)
dt.Columns.Add(col.Name, col.PropertyType);
foreach (var id in values)
{
var newRow = dt.NewRow();
foreach (var prop in id.GetType().GetProperties())
newRow[prop.Name] = prop.GetValue(id, null);
dt.Rows.Add(newRow);
}
}
else
{
dt.Columns.Add("ids");
foreach (var id in values) dt.Rows.Add(id);
}
return dt;
}
}

SQL SubString from Special Kind of ntext column

I have a DB table with the column of type ntext filled with the values like
A<1,?,'attrdisplay'=A<1,?,'1361147_2'='2','1361147_3'='3','1361147_4'='4','1361147_5'='5','1361147_6'='6','1361147_7'='1'>,'ClassificationInheritance'=A<1,?,'DisabledIds'=A<1,?>>,'Confidential'=0,'CreationNotification'=A<1,?,'mail'='Ärende har skapats','recipients'=A<1,?,1414822=-1,1414823=-1,1414824=-1,1414825=-1,1414826=-1,1414827=-1,1415811=-1>>,'IsSubBinder'=1,'name'=A<1,?,'fullname'='Ärendemall5','mlNames'=A<1,?,'sv'='Ärendemall5'>,'name'='Ärendemall5','nameFormat'=':name:','ok'=true,'refnr'='SJCM-2013-00014'>,'showDocumentsFirst'=true,'WorkItem'=A<1,?,'id'=-1,'Name'=''>>
I have to extract only this value SJCM-2013-00014 for each such row in the table.
Any idea how I can do that ?
Thank you in advance!
I guess what you really want is to search for and extract the refnr? If you have the possibility to add CLR-functions to the server, in order to be able to use regular expressions, this is by far the easiest way:
CREATE TABLE #test (data ntext)
INSERT INTO #test VALUES('A<1,?,''attrdisplay''=A<1,?,''1361147_2''=''2'',''1361147_3''=''3'',''1361147_4''=''4'',''1361147_5''=''5'',''1361147_6''=''6'',''1361147_7''=''1''>,''ClassificationInheritance''=A<1,?,''DisabledIds''=A<1,?>>,''Confidential''=0,''CreationNotification''=A<1,?,''mail''=''Ärende har skapats'',''recipients''=A<1,?,1414822=-1,1414823=-1,1414824=-1,1414825=-1,1414826=-1,1414827=-1,1415811=-1>>,''IsSubBinder''=1,''name''=A<1,?,''fullname''=''Ärendemall5'',''mlNames''=A<1,?,''sv''=''Ärendemall5''>,''name''=''Ärendemall5'',''nameFormat''='':name:'',''ok''=true,''refnr''=''SJCM-2013-00014''>,''showDocumentsFirst''=true,''WorkItem''=A<1,?,''id''=-1,''Name''=''''>>')
SELECT
*,
[dbo].[RegexMatchGroupClr](
CAST(data as nvarchar(max)),
'refnr''=''(?<refnr>[^'']+)''',
'refnr'
)
FROM
#test
This is done using regex in a CLR-function that looks like this in C#:
[SqlFunction]
public static SqlChars RegexMatchGroupClr(SqlChars input, string pattern, string groupName)
{
if (input.IsNull) return input;
string inputString = new string(input.Value);
rx.Match match = rx.Regex.Match(inputString, pattern);
if (match.Success && match.Groups[groupName].Success)
{
string resultString = match.Groups[groupName].Value;
SqlChars result = new SqlChars(resultString.ToCharArray());
return result;
}
return null;
}
If you don't have the possibility to add CLR-functions, it's still doable, but way more cumbersome:
CREATE TABLE #test (data ntext)
INSERT INTO #test VALUES('A<1,?,''attrdisplay''=A<1,?,''1361147_2''=''2'',''1361147_3''=''3'',''1361147_4''=''4'',''1361147_5''=''5'',''1361147_6''=''6'',''1361147_7''=''1''>,''ClassificationInheritance''=A<1,?,''DisabledIds''=A<1,?>>,''Confidential''=0,''CreationNotification''=A<1,?,''mail''=''Ärende har skapats'',''recipients''=A<1,?,1414822=-1,1414823=-1,1414824=-1,1414825=-1,1414826=-1,1414827=-1,1415811=-1>>,''IsSubBinder''=1,''name''=A<1,?,''fullname''=''Ärendemall5'',''mlNames''=A<1,?,''sv''=''Ärendemall5''>,''name''=''Ärendemall5'',''nameFormat''='':name:'',''ok''=true,''refnr''=''SJCM-2013-00014''>,''showDocumentsFirst''=true,''WorkItem''=A<1,?,''id''=-1,''Name''=''''>>')
DECLARE #SearchFor varchar(10) = 'refnr''=''';
DECLARE #EndsWith varchar(10) = '''';
WITH converted AS (
SELECT
CAST(data as nvarchar(max)) as data
FROM
#test
), startPos AS (
SELECT
*
,CHARINDEX(#SearchFor, data) + LEN(#SearchFor) as startPos
FROM
converted
), endPos AS (
SELECT
*
,CHARINDEX(#EndsWith, data, startPos) as endPos
FROM
startPos
)
SELECT
*
,SUBSTRING(data, startPos, endPos - startPos) as refnr
FROM
endPos
And if you can't use Common Table Expressions, it gets even more unreadable:
CREATE TABLE #test (data ntext)
INSERT INTO #test VALUES('A<1,?,''attrdisplay''=A<1,?,''1361147_2''=''2'',''1361147_3''=''3'',''1361147_4''=''4'',''1361147_5''=''5'',''1361147_6''=''6'',''1361147_7''=''1''>,''ClassificationInheritance''=A<1,?,''DisabledIds''=A<1,?>>,''Confidential''=0,''CreationNotification''=A<1,?,''mail''=''Ärende har skapats'',''recipients''=A<1,?,1414822=-1,1414823=-1,1414824=-1,1414825=-1,1414826=-1,1414827=-1,1415811=-1>>,''IsSubBinder''=1,''name''=A<1,?,''fullname''=''Ärendemall5'',''mlNames''=A<1,?,''sv''=''Ärendemall5''>,''name''=''Ärendemall5'',''nameFormat''='':name:'',''ok''=true,''refnr''=''SJCM-2013-00014''>,''showDocumentsFirst''=true,''WorkItem''=A<1,?,''id''=-1,''Name''=''''>>')
DECLARE #SearchFor varchar(10) = 'refnr''=''';
DECLARE #EndsWith varchar(10) = '''';
SELECT
*
,SUBSTRING(data, (CHARINDEX(#SearchFor, data) + LEN(#SearchFor)), (CHARINDEX(#EndsWith, data, (CHARINDEX(#SearchFor, data) + LEN(#SearchFor)))) - (CHARINDEX(#SearchFor, data) + LEN(#SearchFor))) as refnr
FROM
#test

Aggregate replace in SQL Server?

What I'm trying to achieve is to make dynamic a series of replacements that have to be performed on a certain field. (To make things even easier, I want in fact to remove data, so I'll be always comparing with
Say that sometimes I will have to do just one replacement:
... REPLACE(myField, stringToRemove, '')
Sometimes, I will need two replacements:
... REPLACE(REPLACE(myField, stringToRemove, ''), anotherStringToRemove, '')
However, I need to make this dynamic and I do not know in advance how many of those values I'll have, and so, how many replacements (removals) I'll have to do.
I tried searching for aggregate string manipulation functions and, of course, there's none. I also know that this can be achieved through a CLR aggregate function but I don't have the possibility of using it.
Any ideas?
You can setup a table variable with FromValue and ToValue and use a while loop to do the replacements.
-- Table to replace in
declare #T table
(
Value varchar(50)
)
insert into #T values
('first second third'),
('first second third')
-- Table with strings to replace
declare #Rep table
(
ID int identity primary key,
FromValue varchar(50),
ToValue varchar(50)
)
insert into #Rep values
('second', 'fourth'),
('third', 'fifth')
declare #ID int
select #ID = max(ID)
from #Rep
while #ID > 0
begin
update #T
set Value = replace(Value, FromValue, ToValue)
from #Rep
where ID = #ID
set #ID -= 1
end
select *
from #T
Result:
Value
-------------------
first fourth fifth
first fourth fifth
If you only want to query the values you can do something like this.
;with C as
(
select 0 as ID,
Value,
0 as Lvl
from #T
union all
select R.ID,
cast(replace(C.Value, R.FromValue, R.ToValue) as varchar(50)),
Lvl + 1
from #Rep as R
inner join C
on C.ID + 1 = R.ID
)
select top 1 with ties Value
from C
order by Lvl desc
Once you implement the CLR aggregate function below, you can do:
SELECT dbo.ReplaceAgg(t.[text], w.badword, w.goodword) // call CLR aggregate function
FROM [Texts] t CROSS JOIN BadWords w
GROUP BY t.[text]
CLR aggregate function in C#
/// <summary>
/// Allows to apply regex-replace operations to the same string.
/// For example:
/// SELECT dbo.ReplaceAgg(t.[text], w.badpattern, "...")
/// FROM [Texts] t CROSS JOIN BadPatterns w
/// GROUP BY t.[text]
/// </summary>
[Serializable]
[Microsoft.SqlServer.Server.SqlUserDefinedAggregate(Format.UserDefined,
IsInvariantToDuplicates = true, IsInvariantToOrder = false,
IsInvariantToNulls = true, MaxByteSize = -1)]
public class RegexReplaceAgg : IBinarySerialize
{
private string str;
private string needle;
private string replacement;
public void Init()
{
str = null;
needle = null;
replacement = null;
}
public void Accumulate(SqlString haystack, SqlString needle, SqlString replacement)
{
// Null values are excluded from aggregate.
if (needle.IsNull) return;
if (replacement.IsNull) return;
if (haystack.IsNull) return;
str = str ?? haystack.Value;
this.needle = needle.Value;
this.replacement = replacement.Value;
str = Regex.Replace(str, this.needle, this.replacement, RegexOptions.Compiled | RegexOptions.CultureInvariant);
}
public void Merge(RegexReplaceAgg group)
{
Accumulate(group.Terminate(), new SqlString(needle), new SqlString(replacement));
}
public SqlString Terminate() => new SqlString(str);
public void Read(BinaryReader r)
{
str = r.ReadString();
needle = r.ReadString();
replacement = r.ReadString();
}
public void Write(BinaryWriter w)
{
w.Write(str);
w.Write(needle);
w.Write(replacement);
}
}
You might have to write a scalar function to which you pass the original string, and enough information for it to know which strings to remove, and have it loop through them and return the result of the set of replacements.

Return value from MySQL stored procedure

So I've finally decided to get around to learning how to use stored procedures, and although I do have them working, I'm unsure if I'm doing it correctly - aka. the best way. So here's what I've got.
Three procedures: TryAddTag, CheckTagExists, and AddTag.
TryAddTag is the procedure that is my intermediary between other code (eg. PHP, etc...) and the other two procedures, so this is the one that gets called.
TryAddTag
DELIMITER //
CREATE PROCEDURE TryAddTag(
IN tagName VARCHAR(255)
)
BEGIN
-- Check if tag already exists
CALL CheckTagExists(tagName, #doesTagExist);
-- If it does not exist, add it
IF #doesTagExist = FALSE THEN
CALL AddTag(tagName);
END IF;
END //
DELIMITER ;
AddTag
DELIMITER //
CREATE PROCEDURE AddTag(
IN tagName VARCHAR(255)
)
BEGIN
INSERT INTO
tags
VALUES(
NULL,
tagName
);
END //
DELIMITER ;
CheckTagExists
DELIMITER //
CREATE PROCEDURE CheckTagExists(
IN
tagName VARCHAR(255),
OUT
doesTagExist BOOL
)
BEGIN
-- Check if tag exists
SELECT
EXISTS(
SELECT
*
FROM
tags
WHERE
tags.NAME = tagName
)
INTO
doesTagExist;
END //
DELIMITER ;
My problems stem from this and use of #doesTagExist.
-- Check if tag already exists
CALL CheckTagExists(tagName, #doesTagExist);
Is the the correct way to use one of these variables? And/or, how can I use a DECLARE'd variable to store the result of CheckTagExists within TryAddTag? I expected something along the lines of
...
DECLARE doesTagExist BOOL;
SET doesTagExist = CheckTagExist('str');
...
or something like that...
your stored procedure is a little over-engineered for my liking - keep it simple :)
MySQL
drop table if exists tags;
create table tags
(
tag_id int unsigned not null auto_increment primary key,
name varchar(255) unique not null
)
engine=innodb;
drop procedure if exists insert_tag;
delimiter #
create procedure insert_tag
(
in p_name varchar(255)
)
proc_main:begin
declare v_tag_id int unsigned default 0;
if exists (select 1 from tags where name = p_name) then
select -1 as tag_id, 'duplicate name' as msg; -- could use multiple out variables...i prefer this
leave proc_main;
end if;
insert into tags (name) values (p_name);
set v_tag_id = last_insert_id();
-- do stuff with v_tag_id...
-- return success
select v_tag_id as tag_id, 'OK' as msg;
end proc_main #
delimiter ;
PHP
<?php
ob_start();
try{
$conn = new mysqli("localhost", "foo_dbo", "pass", "foo_db", 3306);
$conn->autocommit(FALSE); // start transaction
// create the tag
$name = 'f00';
$sql = sprintf("call insert_tag('%s')", $conn->real_escape_string($name));
$result = $conn->query($sql);
$row = $result->fetch_array();
$result->close();
$conn->next_result();
$tagID = $row["tag_id"]; // new tag_id returned by sproc
if($tagID < 0) throw new exception($row["msg"]);
$conn->commit();
echo sprintf("tag %d created<br/>refresh me...", $tagID);
}
catch(exception $ex){
ob_clean();
//handle errors and rollback
$conn->rollback();
echo sprintf("oops error - %s<br/>", $ex->getMessage());
}
// finally
$conn->close();
ob_end_flush();
?>
Stored PROCEDURES can return a resultset. The last thing you SELECT in a stored procedure is available as a resultset to the calling environment.. Stored FUNCTIONS can return only a single result primitive.
You may also mark your parameters as INOUT parameters.
If you want this:
DECLARE doesTagExist BOOL;
SET doesTagExist = CheckTagExist('str');
then you should use functions:
DELIMITER //
CREATE FUNCTION CheckTagExists(
tagName VARCHAR(255)
)
BEGIN
DECLARE doesTagExist BOOL;
-- Check if tag exists
SELECT
EXISTS(
SELECT
*
FROM
tags
WHERE
tags.NAME = tagName
)
INTO
doesTagExist;
RETURN doesTagExist;
END //
DELIMITER ;
DECLARE doesTagExist BOOL;
SET CheckTagExist('str',doesTagExist);
is the correct way of doing it with just store procedures. There are no 'regular' return values.