How do I remove commas between a string of characters? In all posts. Search and Replace?
I have something like this: xfields column
...||ilo_ocen|870,664||kraj|...
I want to remove commas between "||ilo_ocen|" and "||kraj|" in all posts.
Thank you in advance for your help! :)
Usually, we replace it with something else. As you said that you want to "remove" comma, you'd replace it with an empty string.
This is Oracle database example (as you didn't state which database you actually use); I believe other databases have a similar function. Sample data in lines #1 - 4; query you might need begins at line #6.
SQL> with test (xfields) as
2 -- sample data
3 (select '||ilo_ocen|870,664||kraj|' from dual union all
4 select 'Little,foot has a big nose' from dual)
5 -- REPLACE!
6 select replace(xfields, ',', '') result
7 from test;
RESULT
--------------------------
||ilo_ocen|870664||kraj|
Littlefoot has a big nose
SQL>
Related
I've read countless posts on this topic but I can't seem to get any of the recommendations to apply to my particular situation (which isn't different than others...)
I have an SSRS report. Dataset 1 is using a stored procedure and in the where clause I have
and (#param is null or alias.column in
(select Item from dbo.ufnSplit(#param,',')))
I borrowed the dbo.ufnSplit function from this post here: https://stackoverflow.com/a/512300/22194
FUNCTION [dbo].[ufnSplit]
(#RepParam nvarchar(max), #Delim char(1)= ',')
RETURNS #Values TABLE (Item nvarchar(max))AS
--based on John Sansoms StackOverflow answer:
--https://stackoverflow.com/a/512300/22194
BEGIN
DECLARE #chrind INT
DECLARE #Piece nvarchar(100)
SELECT #chrind = 1
WHILE #chrind > 0
BEGIN
SELECT #chrind = CHARINDEX(#Delim,#RepParam)
IF #chrind > 0
SELECT #Piece = LEFT(#RepParam,#chrind - 1)
ELSE
SELECT #Piece = #RepParam
INSERT #Values(Item) VALUES(#Piece)
SELECT #RepParam = RIGHT(#RepParam,LEN(#RepParam) - #chrind)
IF LEN(#RepParam) = 0 BREAK
END
RETURN
END
In dataset 2 I am getting the values that I want to pass to dataset 1
select distinct list from table
My parameter for #param is configured to look at dataset 2 for available values
My issue is that if I select a single value from my parameter dropdown for #param, the report works. If I select multiple values from the dropdown, I only return data for the first value selected.
My values in dataset 2 do not contain any ,'s
Did I miss anything for fail to provide enough information? I'm open to criticism, feedback, do's and don'ts for this, I've struggled with this issue for some time, and by no means a SQL expert :)
Cheers,
MD
Update So SQL Profiler is showing me this:
exec sp... #param=N'value1,value2 ,value3 '
Questions are:
1. Shouldn't every value be wrapped in single quotes?
2. What's with the N before the list?
3. Guessing the trailing spaces need to be trimmed out
When you select multiple values from a parameter dropdown list they are stored in an array. In order to convert that to a string that you can pass to SQL you can use the Join function. Go to your dataset properties and then to the Parameters tab. Replace the Parameter Value with this expression:
=Join(Parameters!param.Value, ",")
It should look like this:
Now your split function will get one comma separated string like it's supposed to. I would also suggest having the split function trim off spaces from the values after it has separated them.
So I figured it out and wanted to post my results here in hopes it helps someone else.
Bad data. One trailing space was blowing up my entire result set, and I didn't notice it until I ran through several scenarios (choosing many combinations of parameters)
My result set had trailing spaces - once I did an rtrim on it I didn't have to do any fancy join/split's in SSRS.
I have been asked to do a bit of work on a SQL Server 2005 query that has 26 (!) nested Replace function calls.
There are two issues with this query.
The first is that the 26 replace functions are not enough, a few more are needed, but the query is hitting some size limitations (it's a stored procedure and its making using of sp_MSforEachDB).
The second problem is that the query is just not legible at this stage.
I would like to use table variable with a lookup, but the issue is that the replace query is being used to replace values in one column with values from another column. It does however all work, apparent from not replacing enough strings.
Here is a simplified example to hopefully better explain what I am trying to do.
Table to be converted
ID MainText Ptext1 Ptext2 Ptext3
1 Have a %Ptxt1 %Ptxt2 Apple Tonight
2 %Ptxt1 likes %Ptxt2 at %Ptxt3 Sally Cake Midnight
The desired result for 1 is "Have a Apple Tonight", the desired result for 2 is "Sally Likes Cake at Midnight".
The current SQL Looks a bit like
EXEC sp_MSForEachDB 'IF ''?'' LIKE ''%Database%''
Select Replace(Replace(Replace([Maintext], '%Ptxt1' , [Ptext1]),'%Ptxt2',[Ptext2]),'Ptxt3', [Ptext3]) from dbo.mytable
Please forgive any mistakes in the example.
I have seen nice examples of people using Table variables to store parameters for the replace function - but I haven't seen any where a column reference is used instead of a static string, is this possible ?
Call your base table: MyData.
Create a new table named MyValues (id, Token, data_value). the ID is FK to you base table. for each record in MyData, insert the values of field names into MyValues.
So, MyValues looks like
Id Token data_value
==== ====== ==========
1 Ptxt1 Apple
1 Ptxt2 Tonight
2 Ptxt1 Sally
2 Ptxt2 Cake
2 Ptxt3 Midnight
and so on...
Then you can join MyTable with MyValues.
Now, one way of solving the problem, is looping on MyData and inner loop on MyValues.
declare #i int
for each value in MyData
begin
#i++
read MyDaya.MainText into #mainText
for each value in MyValues where ID = Id of the MainData
begin
read MyValues.data_value into #actualValue
read MyValues.Token into #token
#mainText = Replace(#mainText, #toekn, #actualValue)
Update MyData with mainText or do what ever appropriate
end
end
This is pseudo-code, I hope you can implement that in T- SQL
I saw this line in an oracle script
SELECT COUNT(*) INTO version1 FROM &1..xxdt WHERE version = 3310;
I don't understand the &1.. part. I think xxdt is the name of the table, so what is the &1.. thing in front of it?
The &1 prompts for a user-entered value. Note how the entered value mytable is substituted for &1 below:
SQL> SELECT COUNT(*) FROM &1 WHERE col1 = 12;
Enter value for 1: mytable
old 1: SELECT COUNT(*) FROM &1 WHERE col1 = 12
new 1: SELECT COUNT(*) FROM mytable WHERE col1 = 12
COUNT(*)
----------
0
The dot (.) appends every non-space character that follows the dot to the entered value. Note how the value table after the dot is appended to the entered my:
SQL> SELECT COUNT(*) FROM &1.table WHERE COL1 = 12;
Enter value for 1: my
old 1: SELECT COUNT(*) FROM &1.table WHERE COL1 = 12
new 1: SELECT COUNT(*) FROM mytable WHERE COL1 = 12
COUNT(*)
----------
0
The two dots in &1..xxdt aren't a special operator. The first dot means to append; the second dot is literal. It looks like the &1 in your example is used to prompt for a schema/owner name. Note below how I've entered ed and &1..mytable is transformed into ed.mytable:
SQL> SELECT COUNT(*) FROM &1..mytable WHERE COL1 = 12;
Enter value for 1: ed
old 1: SELECT COUNT(*) FROM &1..mytable WHERE COL1 = 12
new 1: SELECT COUNT(*) FROM ed.mytable WHERE COL1 = 12
COUNT(*)
----------
0
Addendum: Great suggestion from David Aldridge to include a quick explanation of SET DEFINE, which goes hand-in-hand with variable substitution. Here goes...
The substitutions above are done by SQLPlus, and its behavior can be controlled using SET DEFINE:
SET DEFINE ON will allow the substitution and use the defined substitution character. This is normally the SQLPlus default, and was the case when I ran the queries above.
SET DEFINE <char> sets the substitution character. The ampersand (&) is the usual default. SQLPlus will only accept non-alphanumeric, non-space characters for the substitution character. Note that I've never had to change this value in over a decade of using Oracle.
SET DEFINE OFF will stop substitution. Use this if you need to have an actual literal ampersand in your query or proc, because SQLPlus will treat the ampersand as a substitution character no matter where you put it, including in a string.
I believe the ampersand is used for substitution variables. See http://www.oracle-base.com/articles/misc/literals-substitution-variables-and-bind-variables.php
Substitution Variables
Substitution variables are a feature of the SQL*Plus tool. They have
nothing to do with the way SQL is processed by the database server.
When a substitution variable is used in a statement, SQL*Plus requests
an input value and rewrites the statement to include it. The rewritten
statement is passed to the database. As a result, the database server
knows nothing of the substitution variable. The following example
illustrates this by repeating the previous test, this time using
substitution variables.
If SET CONCAT is a period (.) and you want to append a period immediately after a substitution variable then use two periods together. For example:
define mycity = Melbourne
spool &mycity..log
is the same as:
spool Melbourne.log
https://blogs.oracle.com/opal/entry/sqlplus_101_substitution_varia#9_7
Another Example:
Create a file run.sql with below queries in vi editor:
vi run.sql
select 'mv &1..log &2._' ||to_char(sysdate,'DD-MON-YYYY-HH24-MI') || '.log' from dual;
:wq
Now run:
sqlplus scott/tiger #run.sql listener renamelistener
Code Break Down:
(&1) -first parameter "listener"
(&2) -second parameter "renamelistener"
(.log) -is a substituted of &1
(.) -where the single dot(.) appends non-space characters with a passing parameter value
Thanks!
I have one table with specific columns, in that there is a column which contains comma separated values like test,exam,result,other.
I will pass a string like result,sample,unknown,extras as a parameter to the stored procedure. and then I want to get the related records by checking each and every phrase in this string.
For Example:
TableA
ID Name Words
1 samson test,exam,result,other
2 john sample,no query
3 smith tester,SE
Now I want to search for result,sample,unknown,extras
Then the result should be
ID Name Words
1 samson test,exam,result,other
2 john sample,no query
because in the first record result matched and in the second record sample matched.
That's not a great design, you know. Better to split Words off into a separate table (id, word).
That said, this should do the trick:
set nocount on
declare #words varchar(max) = 'result,sample,unknown,extras'
declare #split table (word varchar(64))
declare #word varchar(64), #start int, #end int, #stop int
-- string split in 8 lines
select #words += ',', #start = 1, #stop = len(#words)+1
while #start < #stop begin
select
#end = charindex(',',#words,#start)
, #word = rtrim(ltrim(substring(#words,#start,#end-#start)))
, #start = #end+1
insert #split values (#word)
end
select * from TableA a
where exists (
select * from #split w
where charindex(','+w.word+',',','+a.words+',') > 0
)
May I burn in DBA hell for providing you this!
Edit: replaced STUFF w/ SUBSTRING slicing, an order of magnitude faster on long lists.
Personally I think you'd want to look at your application/architecture and think carefully about whether you really want to do this in the database or the application. If it isn't appropriate or not an option then you'll need to create a custom function. The code in the article here should be easy enough to modify to do what you want:
Quick T-Sql to parse a delimited string (also look at the code in the comments)
Like the others have already said -- what you have there is a bad design. Consider using proper relations to represent these things.
That being said, here's a detailed article about how to do this using SQL Server:
http://www.sommarskog.se/arrays-in-sql-2005.html
One thing no one has covered so far, because it's often a very bad idea -- but then, you are already working with a bad idea, and sometimes two wrongs make a right -- is to extract all rows that match ANY of your strings (using LIKE or some such) and doing the intersection yourself, client-side. If your strings are fairly rare and highly correlated, this may work pretty well; it will be god-awful in most other cases.
I have a column of data that contains a percentage range as a string that I'd like to convert to a number so I can do easy comparisons.
Possible values in the string:
'<5%'
'5-10%'
'10-15%'
...
'95-100%'
I'd like to convert this in my select where clause to just the first number, 5, 10, 15, etc. so that I can compare that value to a passed in "at least this" value.
I've tried a bunch of variations on substring, charindex, convert, and replace, but I still can't seem to get something that works in all combinations.
Any ideas?
Try this,
SELECT substring(replace(interest , '<',''), patindex('%[0-9]%',replace(interest , '<','')), patindex('%[^0-9]%',replace(interest, '<',''))-1) FROM table1
Tested at my end and it works, it's only my first try so you might be able to optimise it.
#Martin: Your solution works.
Here is another I came up with based on inspiration from #mercutio
select cast(replace(replace(replace(interest,'<',''),'%',''),'-','.0') as numeric) test
from table1 where interest is not null
You can convert char data to other types of char (convert char(10) to varchar(10)), but you won't be able to convert character data to integer data from within SQL.
I don't know if this works in SQL Server, but within MySQL, you can use several tricks to convert character data into numbers. Examples from your sample data:
"<5%" => 0
"5-10%" => 5
"95-100%" => 95
now obviously this fails your first test, but some clever string replacements on the start of the string would be enough to get it working.
One example of converting character data into numbers:
SELECT "5-10%" + 0 AS foo ...
Might not work in SQL Server, but future searches may help the odd MySQL user :-D
You can do this in sql server with a cursor. If you can create a CLR function to pull out number groupings that will help. Its possible in T-SQL, just will be ugly.
Create the cursor to loop over the list.
Find the first number, If there is only 1 number group in their then return it. Otherwise find the second item grouping.
if there is only 1st item grouping returned and its the first item in the list set it to upper bound.
if there is only 1st item grouping returned and its the last item in the list set it to lower bound.
Otherwise set the 1st item grouping to lower, and the 2nd item grouping to upper bound
Just set the resulting values back to a table
The issue you are having is a symptom of not keeping the data atomic. In this case it looks purely unintentional (Legacy) but here is a link about it.
To design yourself out of this create a range_lookup table:
Create table rangeLookup(
rangeID int -- or rangeCD or not at all
,rangeLabel varchar(50)
,LowValue int--real or whatever
,HighValue int
)
To hack yourself out here some pseudo steps this will be a deeply nested mess.
normalize your input by replacing all your crazy charecters.
replace(replace(rangeLabel,"%",""),"<","")
--This will entail many nested replace statments.
Add a CASE and CHARINDEX to look for a space if there is none you have your number
else use your substring to take everything before the first " ".
-- theses steps are wrapped around the previous step.
It's complicated, but for the test cases you provided, this works. Just replace #Test with the column you are looking in from your table.
DECLARE #TEST varchar(10)
set #Test = '<5%'
--set #Test = '5-10%'
--set #Test = '10-15%'
--set #Test = '95-100%'
Select CASE WHEN
Substring(#TEST,1,1) = '<'
THEN
0
ELSE
CONVERT(integer,SUBSTRING(#TEST,1,CHARINDEX('-',#TEST)-1))
END
AS LowerBound
,
CASE WHEN
Substring(#TEST,1,1) = '<'
THEN
CONVERT(integer,Substring(#TEST,2,CHARINDEX('%',#TEST)-2))
ELSE
CONVERT(integer,Substring(#TEST,CHARINDEX('-',#TEST)+1,CHARINDEX('%',#TEST)-CHARINDEX('-',#TEST)-1))
END
AS UpperBound
You'd probably be much better off changing <5% and 5-10% to store 2 values in 2 fields. Instead of storing <5%, you would store 0, and 5, and instead of 5-10%, yould end up with 5 and 10. You'd end up with 2 columns, one called lowerbound, and one called upperbound, and then just check value >= lowerbound AND value < upperbound.