Remove Punctuation in a field in Oracle SQL Developer - sql

I have a field in table in Oracle SQL developer that I need to remove all punctuations in a specific field. The table name is "punctuationtest"
and the function that I tried does not work, I got error with the #InputString
Here is the function that I tried : any ideas and suggestions will be helpful thanks
CREATE FUNCTION dbo.fn_RemovePunctuation
(
#InputString VARCHAR(500)
)
RETURNS VARCHAR(500)
AS
BEGIN
SELECT
#InputString = REPLACE(#InputString, P.Symbol, '')
FROM
Punctuationtest P
RETURN #InputString
END
GO

"Oracle SQL Developer" is a tool you use to establish connection to a database and do something. Which database is it? Usually, it is Oracle. But, then again, code you posted certainly is NOT Oracle - hence error you got (at least, I think so).
If your database really is Oracle, then you could try with such a regular expression (see line #6):
SQL> with test (col) as
2 (select 'abc,!23' from dual union all
3 select '?xyz,.' from dual
4 )
5 select col,
6 regexp_replace(col, '[[:punct:]]') result
7 from test;
COL RESULT
------- ----------------------------
abc,!23 abc23
?xyz,. xyz
SQL>
Or, as you want to update a table, you'd
update your_table set
that_column = regexp_replace(that_column, '[[:punct:]]');

Related

String manipulation SQL

I have a row of strings that are in the following format:
'Order was assigned to lastname,firsname'
I need to cut this string down into just the last and first name but it is always a different name for each record.
The 'Order was assigned to' part is always the same.......
Thanks
I am using SQL Server. It is multiple records with different names in each record.
In your specific case you can use something like:
SELECT SUBSTRING(str, 23) FROM table
However, this is not very scalable, should the format of your strings ever change.
If you are using an Oracle database, you would want to use SUBSTR instead.
Edit:
For databases where the third parameter is not optional, you could use SUBSTRING(str, 23, LEN(str))
Somebody would have to test to see if this is better or worse than subtraction, as in Martin Smith's solution but gives you the same result in the end.
In addition to the SUBSTRING methods, you could also use a REPLACE function. I don't know which would have better performance over millions of rows, although I suspect that it would be the SUBSTRING - especially if you were working with CHAR instead of VARCHAR.
SELECT REPLACE(my_column, 'Order was assigned to ', '')
For SQL Server
WITH testData AS
(
SELECT 'Order was assigned to lastname,firsname' as Col1 UNION ALL
SELECT 'Order was assigned to Bloggs, Jo' as Col1
)
SELECT SUBSTRING(Col1,23,LEN(Col1)-22) AS Name
from testData
Returns
Name
---------------------------------------
lastname,firsname
Bloggs, Jo
on MS SQL Server:
declare #str varchar(100) = 'Order was assigned to lastname,firsname'
declare #strLen1 int = DATALENGTH('Order was assigned to ')
declare #strLen2 int = len(#str)
select #strlen1, #strLen2, substring(#str,#strLen1,#strLen2),
RIGHT(#str, #strlen2-#strlen1)
I would require that a colon or some other delimiter be between the message and the name.
Then you could just search for the index of that character and know that anything after it was the data you need...
Example with format changing over time:
CREATE TABLE #Temp (OrderInfo NVARCHAR(MAX))
INSERT INTO #Temp VALUES ('Order was assigned to :Smith,Mary')
INSERT INTO #Temp VALUES ('Order was assigned to :Holmes,Larry')
INSERT INTO #Temp VALUES ('New Format over time :LootAt,Me')
SELECT SUBSTRING(OrderInfo, CHARINDEX(':',OrderInfo)+1, LEN(OrderInfo))
FROM #Temp
DROP TABLE #Temp

how to select distinct and concatenate in sql

Lets say we have a following table with two columns and following rows of data in SQLServer-2005:
Tiger 50
Wolf 4
Tiger 53
Lion 55
Elephant 54
Rhino 52
Lion 5
Can we have a sql query that result as following: Tiger,Wolf,Lion,Elephant,Rhino as a single string varchar output?Is it possible ?
using T-SQL not possible singe I am using the result in c# as a result of executescalar
Thank you in advance.
You can use for xml path to concatenate the values:
select distinct name + ', ' as [text()]
from #t
for xml path('')
-->
Elephant, Lion, Rhino, Tiger, Wolf,
Chop of the last 2 bytes if you don't like trailing ,'s.
Not sure why you can't use T-SQL, you can use this in combination with ExecuteScalar() just fine.
Sample data:
declare #t table (name varchar(max), id int)
insert into #t
select 'Tiger', 50
union all select 'Wolf', 4
union all select 'Tiger', 53
union all select 'Lion', 55
union all select 'Elephant', 54
union all select 'Rhino', 52
union all select 'Lion', 5
See How to return multiple values in one column (T-SQL)?
Use GROUP_CONCAT() with DISTINCT:
SELECT GROUP_CONCAT(DISTINCT colName) FROM tblName;
Assuming you are getting this from ExecuteScalar and using the resulting composite string in C#, then you are going to end up writing a sproc, or just having your code work with the datatable.
Can you provide more detail on why you can't use a sproc? A few good examples have been provided that would do fine with that, and you can still get your scalar result
The most efficient way is probably to use a User-Defined Aggregate, but you can also abuse the UPDATE statement:
DECLARE #Result varchar(500)
SET #Result = ''
UPDATE Animals
SET #Result = #Result + Name + ','
SELECT #Result
This is how Andomar's Answer was implemented.Thanks to Andomar's answer got to learn some thing new with this .
select distinct summaryColumn + ', '
as [text()] from tablename for
xml path('')

SQL Server - Replacing Single Quotes and Using IN

I am passing a comma-delimited list of values into a stored procedure. I need to execute a query to see if the ID of an entity is in the comma-delimited list. Unfortunately, I think I do not understand something.
When I execute the following stored procedure:
exec dbo.myStoredProcedure #myFilter=N'1, 2, 3, 4'
I receive the following error:
"Conversion failed when converting the varchar value '1, 2, 3, 4' to data type int."
My stored procedure is fairly basic. It looks like this:
CREATE PROCEDURE [dbo].[myStoredProcedure]
#myFilter nvarchar(512) = NULL
AS
SET NOCOUNT ON
BEGIN
-- Remove the quote marks so the filter will work with the "IN" statement
SELECT #myFilter = REPLACE(#myFilter, '''', '')
-- Execute the query
SELECT
t.ID,
t.Name
FROM
MyTable t
WHERE
t.ID IN (#myFilter)
ORDER BY
t.Name
END
How do I use a parameter in a SQL statement as described above? Thank you!
You could make function that takes your parameter, slipts it and returns table with all the numbers in it.
If your are working with lists or arrays in SQL Server, I recommend that you read Erland Sommarskogs wonderful stuff:
Arrays and Lists in SQL Server 2005
You need to split the string and dump it into a temp table. Then you join against the temp table.
There are many examples of this, here is one at random.
http://blogs.microsoft.co.il/blogs/itai/archive/2009/02/01/t-sql-split-function.aspx
Absent a split function, something like this:
CREATE PROCEDURE [dbo].[myStoredProcedure]
#myFilter varchar(512) = NULL -- don't use NVARCHAR for a list of INTs
AS
SET NOCOUNT ON
BEGIN
SELECT
t.ID,
t.Name
FROM
MyTable t
WHERE
CHARINDEX(','+CONVERT(VARCHAR,t.ID)+',',#myFilter) > 0
ORDER BY
t.Name
END
Performance will be poor. A table scan every time. Better to use a split function. See: http://www.sommarskog.se/arrays-in-sql.html
I would create a function that takes your comma delimited string and splits it and returns a single column table variable with each value in its own row. Select that column from the returned table in your IN statement.
I found a cute way of doing this - but it smells a bit.
declare #delimitedlist varchar(8000)
set #delimitedlist = '|1|2|33|11|3134|'
select * from mytable where #delimitedlist like '%|' + cast(id as varchar) + '|%'
So... this will return all records with an id equal to 1, 2, 33, 11, or 3134.
EDIT:
I would also add that this is not vulnerable to SQL injection (whereas dynamic SQL relies on your whitelisting/blacklisting techniques to ensure it isn't vulnerable). It might have a performance hit on large sets of data, but it works and it's secure.
I have a couple of blog posts on this as well, with a lot of interesting followup comments and dialog:
More on splitting lists
Processing list of integers

Informix: Select null problem

Using Informix, I've created a tempory table which I am trying to populate from a select statement. After this, I want to do an update, to populate more fields in the tempory table.
So I'm doing something like;
create temp table _results (group_ser int, item_ser int, restype char(4));
insert into _results (group_ser, item_ser)
select
group_ser, item_ser, null
from
sometable
But you can't select null.
For example;
select first 1 current from systables
works but
select first 1 null from systables
fails!
(Don't get me started on why I can't just do a SQL Server like "select current" with no table specified!)
You don't have to write a stored procedure; you simply have to tell IDS what type the NULL is. Assuming you are not using IDS 7.31 (which does not support any cast notation), you can write:
SELECT NULL::INTEGER FROM dual;
SELECT CAST(NULL AS INTEGER) FROM dual;
And, if you don't have dual as a table (you probably don't), you can do one of a few things:
CREATE SYNONYM dual FOR sysmaster:"informix".sysdual;
The 'sysdual' table was added relatively recently (IDS 11.10, IIRC), so if you are using an older version, it won't exist. The following works with any version of IDS - it's what I use.
-- #(#)$Id: dual.sql,v 2.1 2004/11/01 18:16:32 jleffler Exp $
-- Create table DUAL - structurally equivalent to Oracle's similarly named table.
-- It contains one row of data.
CREATE TABLE dual
(
dummy CHAR(1) DEFAULT 'x' NOT NULL CHECK (dummy = 'x') PRIMARY KEY
) EXTENT SIZE 8 NEXT SIZE 8;
INSERT INTO dual VALUES('x');
REVOKE ALL ON dual FROM PUBLIC;
GRANT SELECT ON dual TO PUBLIC;
Idiomatically, if you are going to SELECT from Systables to get a single row, you should include 'WHERE tabid = 1'; this is the entry for Systables itself, and if it is missing, the fact that your SELECT statement does return any data is the least of your troubles. (I've never seen that as an error, though.)
This page says the reason you can't do that is because "NULL" doesn't have a type. So, the workaround is to create a sproc that simply returns NULL in the type you want.
That sounds like a pretty bad solution to me though. Maybe you could create a variable in your script, set it to null, then select that variable instead? Something like this:
DEFINE dummy INT;
LET dummy = NULL;
SELECT group_ser, item_ser, dummy
FROM sometable
SELECT group_ser, item_ser, replace(null,null) as my_null_column
FROM sometable
or you can use nvl(null,null) to return a null for your select statement.
Is there any reason to go for an actual table? I have been using
select blah from table(set{1})
select blah from table(set{1})
is nice when you are using 10.x database. This statement doesn't touch database. The amount of read/write operations is equal to 0,
but
when you're using 11.x it will cost you at least 4500 buffer reads because this version of Informix creates this table in memory and executes query against it.
select to_date(null) from table;
This works when I want to get a date with null value
You can use this expression (''+1) on the SELECT list, instead of null keyword. It evaluates to NULL value of type DECIMAL(2,0).
This (''+1.0001) evaluates to DECIMAL(16,4). And so on.
If you want DATE type use DATE(''+1) to get null value of type DATE.
(''+1)||' ' evaluates to an empty string of type VARCHAR(1).
To obtain NULL value of type VARCHAR(1) use this expression:
DATE(''+1)||' '
Works in 9.x and 11.x.

Like in CASE statement not evaluating as expected

Given this data:
CREATE TABLE tmpTable(
fldField varchar(10) null);
INSERT INTO tmpTable
SELECT 'XXX'
UNION ALL
SELECT 'XXX'
UNION ALL
SELECT 'ZZZ'
UNION ALL
SELECT 'ZZZ'
UNION ALL
SELECT 'YYY'
SELECT
CASE WHEN fldField like 'YYY' THEN 'OTH' ELSE 'XXX' END AS newField
FROM tmpTable
The expected resultset is:
XXX
XXX
XXX
XXX
OTH
What situation would casue SQL server 2000 to NOT find 'YYY'? And return the following as the resultset:
XXX
XXX
XXX
XXX
XXX
The problem is with the like 'YYY', I have found other ways to write this to get it to work, but I want to know why this exact method doesn't work. Another difficulty is that it works in most of my SQL Server 2000 environments. I need to find out what is different between them to cause this. Thanks for your help.
Check your service pack. After upgrading my SQL 2000 box to SP4 I now get the correct values for your situation.
I'm still getting the swapped data that I reported in my earlier post though :(
If you do SELECT ##version you should get 8.00.2039. Any version number less than that and you should install SP4.
I ran the code on a SQL 2000 box and got identical results. Not only that, but when I ran some additional code to test I got some VERY bizarre results:
CREATE TABLE dbo.TestLike ( my_field varchar(10) null);
GO
CREATE CLUSTERED INDEX IDX_TestLike ON dbo.TestLike (my_field)
GO
INSERT INTO dbo.TestLike (my_field) VALUES ('XXX')
INSERT INTO dbo.TestLike (my_field) VALUES ('XXX')
INSERT INTO dbo.TestLike (my_field) VALUES ('ZZZ')
INSERT INTO dbo.TestLike (my_field) VALUES ('ZZZ')
INSERT INTO dbo.TestLike (my_field) VALUES ('YYY')
GO
SELECT
my_field,
case my_field when 'YYY' THEN 'Y' ELSE 'N' END AS C2,
case when my_field like 'YYY' THEN 'Y' ELSE 'N' END AS C3,
my_field
FROM dbo.TestLike
GO
My results:
my_field C2 C3 my_field
---------- ---- ---- ----------
N XXX N XXX
N XXX N XXX
Y YYY N YYY
N ZZZ N ZZZ
N ZZZ N ZZZ
Notice how my_field has two different values in the same row? I've asked some others at the office here to give it a quick test. Looks like a bug to me.
It worked as expected on my SQL 2005 installation. If it works on other machines, it sounds like you've got an environment difference. Try comparing your connection properties in SQL Server Management Studio for a connection that works and one that doesn't to see if you can figure out what the differences are.
I am an Oracle person, not a SQL*Server person, but it seems to me you should be either:-
SELECT
CASE WHEN fldField like '%YYY%' THEN
'OTH'
ELSE 'XXX'
END AS newField
FROM
tmpTable
or ...
SELECT
CASE WHEN fldField = 'YYY' THEN
'OTH'
ELSE 'XXX'
END AS newField
FROM
tmpTable
The second is the direction I'd go in, as at least in Oracle equality resolves quicker than like.
When you use LIKE without specifying any search criteria, it behaves like an = comparison. In your example, I would expect it to work properly. In your real data, you probably have a hidden (non-printable) character in your data (think about Carriage Return, Line Feed, Tab, etc....).
Take a look at this example...
Declare #tmpTable TABLE(
fldField varchar(10) null);
INSERT INTO #tmpTable
SELECT 'XXX'
UNION ALL
SELECT 'XXX'
UNION ALL
SELECT 'ZZZ'
UNION ALL
SELECT 'ZZZ'
UNION ALL
SELECT 'YYY'
UNION ALL
SELECT 'YYY' + Char(10)
SELECT CASE WHEN fldField like 'YYY' THEN 'OTH' ELSE 'XXX' END AS YourOriginalTest,
CASE WHEN fldField like 'YYY%' THEN 'OTH' ELSE 'XXX' END AS newField
FROM #tmpTable
You'll notice that the last piece of data I added is YYY and a Line Feed. If you select this data, you won't notice the line feed in the data, but it's there, so your LIKE condition (which is acting like an equal condition) doesn't match.
The common 'hidden' characters are Tab, Carriage Return, and Line Feed. To determine if this is causing your problem...
Select *
From Table
Where Column Like '%[' + Char(10) + Char(9) + Char(13) + ']%'
What a cute bug. I think I know the cause. If I'm right, then you'll get the results you expect from:
SELECT
CASE
WHEN fldField like 'YYY ' -- 7 spaces
THEN 'OTH'
ELSE 'XXX'
END as newField
from tmpTable
The bug is that varchar(10) is behaving like char(10) is supposed to. As for why it doesn't, you'll need to understand the old trivia question of how two strings with no metacharacters can be = but not LIKE each other.
The issue is that a char(10) is internally supposed to be space padded. The like operator does not ignore those spaces. The = operator is supposed to in the case of chars. Memory tells me that Oracle ignores spaces for strings in general. Postgres does some tricks with casting. I have not used SQL*Server so I can't tell you how it does it.
How about fldField = '%YYY%'?
By adding (%) to the expression , it will work fine.
SELECT
CASE
WHEN fldField like '%YYY%' THEN 'OTH'
ELSE 'XXX' END AS newField
END
You aren't specifying what you are selecting and checking the CASE against...
SELECT CASE fldField WHEN 'YYY'
THEN 'OTH' ELSE 'XXX' END AS newField FROM tmpTable