I have been seraching solution for this issue .Though this particular question has been discussed many times in this forum, i did not get any proper answer for my problem.
I will be getting data from 3rd party which can contain single quote.This data need to be inserted into data base and when it contains single quote it fails and throws following error:
Msg 105, Level 15, State 1, Line 7
Unclosed quotation mark after the character string '
---Following is c++ code to pass trandata as input along with other parameters and invoke fn_stripsingleQuote10 function from SQL server:
strSQLText = "declare #returnType as varchar(max)\n EXEC #returnType = CABINET..fn_stripsingleQuote10 ";
sqlTxtParams.Format("'%s', '%s', '%s', tranData, sing_quote, double_sing_quote);
strSQLText += sqlTxtParams;
----My sql function(fn_stripsingleQuote10) to replace single quote
USE [cabinet]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE function [dbo].[fn_stripsingleQuote10](
#strip varchar(Max),#patern varchar(5),#replace varchar(5)
)
returns varchar(Max) as begin
declare #CleanString varchar(Max)
SET #CleanString=(REPLACE(#strip,#patern, #replace))
return #CleanString
end
sample output:
ex:
declare #returnType as varchar(max) EXEC #returnType = CABINET..fn_stripsingleQuote10 'fsds'd','''',''''''
I feel the way i am invoking the function is not proper.Please provide a solution .
Strictly speaking you're looking for QUOTENAME, which does exactly what you're asking:
'quote_character' Is a one-character string to use as the delimiter.
Can be a single quotation mark ( ' ), a left or right bracket ( [ ] ),
or a double quotation mark ( " ).
However, it is very very likely that your code is exposed to SQL Injection right now and you should actually use a parameter. It is almost never required to concatenate input into the resulted executed SQL.
Related
I have a string in SQL with the following structure:
#number <logical> #number <logical> ....
ex:
#SQL='((#1 or #2) and (#10 or #21))'
I would like to update the string to be:
#SQL='((con_1=1 or con_2=1) and (con_10=1 or con_21=1))'
meaning remove the '#' and replace it with 'con_', leave the number (1 digit or more) as is and add '=1' after the digit.
Any idea how to do it?
Please avoid composing function or procedure for that.
you may use patindex, stuff or any other built in function for that.
First split the string into records on the '#' char that starts the value needing processed.
STUFF can be used to insert the '=1' after the last digit of the value in each record. I think searching for the last number is harder than searching for the first. The reverse allows searching for the first instead of the last. Because the string is reversed, insert the reverse '1=' at the start of the reverse number. If there is no number, return the revered value as is.
Concatenate it all back with 'con_' instead of '#'.
declare #SQL varchar(200) = ' ((#1 or #2) and (#10 or #21)) #33 #55 ';
with split as (
select value, REVERSE(value) as [rev], PATINDEX('%[0-9]%', REVERSE(value)) as [pat]
FROM STRING_SPLIT(#SQL, '#')
), fixed as (
select value, rev, pat, CASE WHEN pat= 0 THEN REVERSE(rev) ELSE REVERSE(STUFF(rev, pat, 0, '1=')) END as [fix]
FROM split
) select STRING_AGG(fix, 'con_') from fixed
Result: ((con_1=1 or con_2=1) and (con_10=1 or con_21=1)) con_33=1 con_55=1
It would be nice if Regex support was included in SQL server. I imagine to do so would require a careful implementation to avoid using all the server resources. A regex search on a millions of records or varchar(max) columns....
Found this solution which uses SQL# (SQLsharp).
SQL# is a .NET / CLR library that resides in a SQL Server 2005 (or newer) database and provides a suite of User-Defined Functions, Stored Procedures, User-Defined Aggregates, and User-Defined Types.
My solution:
declare #SQL varchar(200) = '#1 OR(#2 AND #3 AND (#4 or #5 or #6) AND (#7 or #8))'
SELECT SQL#.RegEx_Replace4k(#SQL, N'(#)+(\d*)', N'CON_$2=1', -1, 1, N'')
I have a piece of code I am not familiar with sql server, only oracle. Can someone tell me what this is doing? Thanks.
What is the #flowcontrol
what is set #flowcontrol = ##error? Why two ##?
Why is print twice? What does print do here?
What is raiseerror doing?
Use [ra8]
declare #flowcontrol integer
set #flowcontrol = ##error
if #flowcontrol = 0
begin
print ' '
print 'create temp[nw] table'
create table [dbo].[temp] ([feild] [varchar] (200) nulll
end
else
begin
print ' '
print ' '
raiserror('raiseerror: create temp[nw] failed',12,1) with seterror
end
go
What is the #flowcontrol
#flowcontrol in this case is an integer variable (declared above)
what is set #flowcontrol = ##error? Why two ##?
the 2 # means this is a special - or system - function
Why is print twice? What does print do here?
print is a function who write in the 'pipe' (messages parts in sql management studio). I think they are here to make some room in the messages to be more readable.
What is raiseerror doing?
Raiseerror, as its name sounds like - is raising an error.
Globally, this is creating an integer variable, checking errors on a previous instruction, if there are no error create a table, else raising an error.
##VARIABLE - means it is a global variable maintained by SQL Server. Such variables represent information specific to the server or a current user session.
This wiki page has a listing of them and sample values: Global Variables in SQL Server
I have wrote a phraser which is phrasing a quite long string into small pieces, after the phrasing of one item is completed, it removes him from #input and continue, until it wont be able to find any items to phrase.
I am selecting items based on LIKE pattern.
In some cases, there are however it is selecting some other parts of the message, and then it's end in infinitive loop.
The pattern I am looking for to be selected using LIKE clause is in format of :
(Any number from 1 to 9) + (variable length A-Z only) + '/' +
(variable length A-Z only)+space of Cr or Lf or CrLf.
--This is what I do have:
DECLARE #match NVarChar(100)
SET #match = '%[1-9][a-z]%'
DECLARE #input1 varchar(max),#input2 varchar(max)
SET #input1 ='1ABCD/EFGH *W/17001588 *RHELLO SMVML1C'
DECLARE #position Int
SET #position = PATINDEX(#match, #input1);
SELECT #position;
--after the loop- it is also 'catching' the 1C at the end of the string:
SET #input2 = '*W/17001588 *RHELLO SMVML1C'
SET #position = PATINDEX(#match, #input2);
SELECT #position
---In order to eliminate this, I have tried to change #match:
SET #match = '%[1-9][a-z][/][a-z]%'
SET #position = PATINDEX(#match, #input1);
SELECT #position --postion is 0, so the first item, that should have been selected, wasn't selected
SET #position = PATINDEX(#match, #input2);
SELECT #position --postion is 0
Many thanks for help!
Try changing your match variable/criteria to this:
SET #match = '%[1-9][a-z]%[/][a-z]%'
This will get you the desired result. Loosely translated it is saying "Get me the starting position of the first match where the pattern is [anything]-[number from 1-9]-[single letter from a-z]-[anything]-[slash]-[single letter from a-z]-[anything].
Hope this helps!
I agree with the comments above; this is a regex problem that needs to be solved with regex tools. I would recommend the assembly created by SimpleTalk. You can get their code and read their very thorough article.
Unfortunately this solution requires serious admin rights to the database and server, so it won't be portable as a script. But I think these functions are worth any effort it takes to get the installed if you develop on the same database on a regular basis.
Just be forwarned, regex is a real processing hog and undermines much of the indexing efficiency in SQL Server. Use it only when you can't use like.
I don't know if this solves your entire problem , but if you can prefix your input with a space, you can modify the pattern to avoid matching a number without a preceding space.
set #input = ' '+#input;
set #match = '% [1-9][a-z]%';
If you need your pattern to account for other whitespace like Cr and Lf, your pattern could look like this:
set #match = '%[ '+char(13)+char(10)+'][1-9][a-z]%';
I have Change Data Capture (CDC) activated on my MS SQL 2008 database and use the following code to add a new tabel to the data capture:
EXEC sys.sp_cdc_enable_table
#source_schema ='ordering',
#source_name ='Fields',
#role_name = NULL,
#supports_net_changes = 0;
However, whenever I try to select the changes from the tracking tables using the sys.fn_cdc_get_min_lsn(#TableName) function
SET #Begin_LSN = sys.fn_cdc_get_min_lsn('Fields')
I always get the zero value.
I tried adding the schema name using the following spelling:
SET #Begin_LSN = sys.fn_cdc_get_min_lsn('ordering.Fields')
but this didn't help.
My mystake was to assume that sys.fn_cdc_get_min_lsn() accepts the table name. I was mostly misguided by the examples in MSDN documentation, probably and didn't check the exact meaning of the parameters.
It turns out that the sys.fn_cdc_get_min_lsn() accepts the capture instance name, not table name!
A cursory glance at my current capture instances:
SELECT capture_instance FROM cdc.change_tables
returns the correct parameter name:
ordering_Fields
So, one should use underscore as schema separator, and not the dot notation as it is common in SQL Server.
I know this is mostly already explained in this post but I thought I would put together my evenings journey through CDC
This error:
"An insufficient number of arguments were supplied for the procedure or function cdc..."
Is probably caused by your low LSN being 0x00
This in turn might be because you put the wrong instance name in with fn_cdc_get_min_lsn.
Use SELECT * FROM cdc.change_tables to find it
Lastly make sure you use binary(10) to store your LSN. If you use just varbinary or binary, you will again get 0x00. This is clearly payback for me scoffing at all those noobs using varchar and wondering why their strings are truncated to one character.
Sample script:
declare #S binary(10)
declare #E binary(10)
SET #S = sys.fn_cdc_get_min_lsn('dbo_YourTable')
SET #E = sys.fn_cdc_get_max_lsn()
SELECT #S, #E
SELECT *
FROM [cdc].[fn_cdc_get_net_changes_dbo_issuedToken2]
(
#S,#E,'all'
)
The above answer is correct. Alternatively you can add an additional parameter capture_instance to the cdc enable
EXEC sys.sp_cdc_enable_table
#source_schema ='ordering',
#source_name ='Fields',
#capture_instance = 'dbo_Fields'
#role_name = NULL,
#supports_net_changes = 0;
then use the capture_instance string in the min_lsn function
SET #Begin_LSN = sys.fn_cdc_get_min_lsn('dbo_Fields')
will return the first LSN, and not 0x00000000000000000000.
This is partiularly useful when trying to solve the error
"An insufficient number of arguments were supplied for the procedure or function cdc..." from SQL when calling
cdc_get_net_changes_Fields(#Begin_LSN, sys.fn_cdc_get_max_lsn(), 'all')
Which simply means "LSN out of expected range"
I have an interesting SQL Server search requirement.
Say I have a table with Part Numbers as follows:
PARTNO DESCRIPTION
------ -----------
ABC-123 First part
D/12a92 Second Part
How can I create a search that will return results if I search, say, for 'D12A'?
I currently have a full text search set up for the description column, but I am looking to find parts that match the part no even when users don't include the / or - etc.
I'd rather do this in a single SQL statement rather than creating functions if possible as we only have read access to the DB.
You could do something like:
SELECT * FROM PART_TABLE
WHERE REPLACE(REPLACE(PARTNO,'/', ''),'-','') LIKE '%D12A%'
This would work for the 2 characters you specified and could be extended for more character like so:
SELECT * FROM PART_TABLE
WHERE REPLACE(REPLACE(REPLACE(PARTNO,'/', ''),'-',''),*,'') LIKE '%D12A%'
Probably not the most elegant of solutions unless your special characters are limited. Otherwise I'd suggest writing a Function to strip out non-alphanumeric characters.
Here is an example of such a function:
CREATE FUNCTION dbo.udf_AlphaNumericChars
(
#String VARCHAR(MAX)
)
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE #RemovingCharIndex INT
SET #RemovingCharIndex = PATINDEX('%[^0-9A-Za-z]%',#String)
WHILE #RemovingCharIndex > 0
BEGIN
SET #String = STUFF(#String,#RemovingCharIndex,1,'')
#RemovingCharIndex = PATINDEX('%[^0-9A-Za-z]%',#String)
END
RETURN #String
END
------- Query Sample (untested)---------
SELECT *
FROM PART_TABLE
WHERE DBO.udf_AlphaNumericChars(PARTNO) LIKE '%D12A%'
Taken From: http://sqlserver20.blogspot.co.uk/2012/06/find-alphanumeric-characters-only-from.html