RCPT10-66631 IS A varchar value retrieved from database.
How to add 1 in it. that is i want to take next value
i.e RCPT10-66632.
you can split the string but i think that is not better solution
declare #s varchar(50)
set #s = 'RCPT10-66631'
select cast(cast(right(#s, len(#s)-charindex('-', #s, 0)) as int)+1 as varchar(50))
Related
Is it possible to execute a SQL statement that has been stored within a table as text.
I am trying to create a configuration table to drive a large number of SSRS subscriptions and don’t want to code any values directly into the report I want them all driven from a table for maintance.
E.G.
If part of one reports file name will always be the year of the previous month (2013 for example) but this needs to be generated at run time.
Can I stored this as a text field
CAST(YEAR(DATEADD(month, -1, GETDATE())) AS VARCHAR(4))
Then execute it and resolve the result into a SQL query?
If I understand your question correctly, then yes by using dynamic SQL. For example:
DECLARE #SQL NVARCHAR(4000)
DECLARE #YEAR VARCHAR(4)
SET #SQL = 'SELECT #yr = CAST(YEAR(DATEADD(month, -1, GETDATE())) AS VARCHAR(4))'
EXECUTE sp_executesql #SQL, N'#yr VARCHAR(4) OUTPUT', #yr=#YEAR OUTPUT
SELECT #YEAR
...returns 2013 into variable #YEAR.
Here I've hardcoded the query but it is a simple case to build the value of #SQL from a table's column value instead. You can then use the result from this query to build another dynamic query and so on.
Below is a subset of the above showing the SQL being taken from a table instead:
CREATE TABLE Dynamic (id INTEGER, text VARCHAR(4000) )
INSERT Dynamic values (1, 'CAST(YEAR(DATEADD(month, -1, GETDATE())) AS VARCHAR(4))')
SET #SQL = 'SELECT #yr = ' + (SELECT text FROM Dynamic WHERE id = 1)
why couldn't you?
Is it only one line of values per report?
I see 2 choices with SSRS.
1) everything in sql, you do dynamic sql.
declare #sql nvarchar(4000)
select #sql = 'select * from mytable where year = ' mavar'
from tablevalue where uniqueid = blablabla
exec sp_executesql #sql
second possibilty :
You make a first dataset in SSRS getting this value and then you evaluate the value of your condition and send it to a third dataset.
If you have multiple values, you can still imagine to get the value from a first dataset, evaluate them and send this to a subreport.
I don't know your application enought to determine the performance of this.
Until you are in SSRS, i recommand to try to find a solution in SSRS instead of Sql (but it's not a gold rule at all!!!)
Originally i thought that this issue is related to C# TransactionScope or Dapper.NET. But since i have tested the sql in SSMS and the issue remains i assume that it's a pure sql issue.
This is the (simplified) update which should update a varchar(40) column. I don't get any errors and row-count is 1. The old SparePartDescription is EC801/¦USB/Exch Acc/JP/PE bag:
declare #rowCount int
UPDATE [tabSparePart] SET
[SparePartDescription] = 'EC801/╡USB/Exch Acc/JP/PE bag'
WHERE ([idSparePart] = 13912)
set #rowCount = ##ROWCOUNT
select #rowCount
So the only difference are these special characters: ╡ and ¦.
Maybe you have an idea why i cannot update this column.
Well, the special character you are using:
╡
Is not supported in ASCII. See:
DECLARE #x VARCHAR(32) = 'EC801/╡USB/Exch Acc/JP/PE bag';
SELECT #x;
Result:
EC801/¦USB/Exch Acc/JP/PE bag
So the update is working fine, technically, it's just not doing what you want, because in order to fit into the ASCII space, it has to substitute your character for one that is valid.
In order to support that character, you'll have to use Unicode for your column (and maybe a specific collation, I'm not sure). This works fine:
DECLARE #x NVARCHAR(32) = N'EC801/╡USB/Exch Acc/JP/PE bag';
SELECT #x;
Result:
EC801/╡USB/Exch Acc/JP/PE bag
It will be important to specify the N prefix on string literals that contain such characters...
I want to pass multiple values in a single parameter. SQL Server 2005
You can have your sproc take an xml typed input variable, then unpack the elements and grab them. For example:
DECLARE #XMLData xml
DECLARE
#Code varchar(10),
#Description varchar(10)
SET #XMLData =
'
<SomeCollection>
<SomeItem>
<Code>ABCD1234</Code>
<Description>Widget</Description>
</SomeItem>
</SomeCollection>
'
SELECT
#Code = SomeItems.SomeItem.value('Code[1]', 'varchar(10)'),
#Description = SomeItems.SomeItem.value('Description[1]', 'varchar(100)')
FROM #XMLDATA.nodes('//SomeItem') SomeItems (SomeItem)
SELECT #Code AS Code, #Description AS Description
Result:
Code Description
========== ===========
ABCD1234 Widget
You can make a function:
ALTER FUNCTION [dbo].[CSVStringsToTable_fn] ( #array VARCHAR(8000) )
RETURNS #Table TABLE ( value VARCHAR(100) )
AS
BEGIN
DECLARE #separator_position INTEGER,
#array_value VARCHAR(8000)
SET #array = #array + ','
WHILE PATINDEX('%,%', #array) <> 0
BEGIN
SELECT #separator_position = PATINDEX('%,%', #array)
SELECT #array_value = LEFT(#array, #separator_position - 1)
INSERT #Table
VALUES ( #array_value )
SELECT #array = STUFF(#array, 1, #separator_position, '')
END
RETURN
END
and select from it:
DECLARE #LocationList VARCHAR(1000)
SET #LocationList = '1,32'
SELECT Locations
FROM table
WHERE LocationID IN ( SELECT CAST(value AS INT)
FROM dbo.CSVStringsToTable_fn(#LocationList) )
OR
SELECT Locations
FROM table loc
INNER JOIN dbo.CSVStringsToTable_fn(#LocationList) list
ON CAST(list.value AS INT) = loc.LocationID
Which is extremely helpful when you attempt to send a multi-value list from SSRS to a PROC.
Edited: to show that you may need to CAST - However be careful to control what is sent in the CSV list
Just to suggest. You can't really do so in SQL Server 2005. At least there is no a straightforward way. You have to use CSV or XML or Base 64 or JSON. However I strongly discourage you to do so since all of them are error prone and generate really big problems.
If you are capable to switch to SQL Server 2008 you can use Table valued parameters (Reference1, Reference2).
If you cannot I'd suggest you to consider the necessity of doing it in stored procedure, i.e. do you really want (should/must) to perform the sql action using SP. If you are solving a problem just use Ad hoc query. If you want to do so in education purposes, you might try don't even try the above mentioned things.
There are multiple ways you can achieve this, by:
Passing CSV list of strings as an argument to a (N)VARCHAR parameter, then parsing it inside your SP, check here.
Create a XML string first of all, then pass it as an XML datatype param. You will need to parse the XML inside the SP, you may need APPLY operator for this, check here.
Create a temp table outside the SP, insert the multiple values as multiple rows, no param needed here. Then inside the SP use the temp table, check here.
If you are in 2008 and above try TVPs (Table Valued Parameters) and pass them as params, check here.
Due to a rather brilliant oversight in my current project, we have some guids getting stored in a varchar column in one table, which need to be compared to a uniqueidentifier column in another.
How can I do this? SQL server simply says it cannot convert from a character string to a uniqueidentifier.
If SQL complains it cannot cast it means not only you stored the uniqueidentifier as varchar, you used a different format than SQL Server (eg. you added the '{' and '}'). SQL is perfectly capable of casting string to uniqueidentifier when properly formatted:
declare #u uniqueidentifier;
declare #s varchar(64);
select #u = NEWID();
select #s = CAST(#u as varchar(64));
select CAST(#s as uniqueidentifier), #u, #s;
Depending on how you actualy stored the uniqueidentifier, you will most likely have tomodify the data and your code to match the SQL format (no {}).
Convert the uniqueidentifier to varchar:
CAST( uniqueidentifier_col_name as varchar)
I just worked up the following test script:
DECLARE
#Foo Uniqueidentifier
,#Foo2 varchar(50)
SET #Foo = newid()
SET #Foo2 = newId()
print #Foo
print #Foo2
if #Foo = #Foo2
print 'Yes'
else
print 'No'
set #Foo = #Foo2
if #Foo = #Foo2
print 'Yes'
else
print 'No'
Run in an SSMS window or via slqcmd -i file, the results are the same -- SQL (2005) does implicit conversion. This supports what I recall from SQL 2000 when I had a similar problem years ago.
The key thing is that the varchar string has to match the guid pattern:
8 hex digits
dash
4 hex digits
dash
4 hex digits
dash
4 hex digits
dash
12 hex digits
You'll have to cast the other uniqueidentifier to varchar.
SQL Server is probably tryng to cast things like "bob" to uniqueidentifier and it fails.
According to CAST/CONVERT it's allowed, so it must be the values in the varchar column.
I've got a stored procedure in my database, that looks like this
ALTER PROCEDURE [dbo].[GetCountingAnalysisResults]
#RespondentFilters varchar
AS
BEGIN
#RespondentFilters = '''8ec94bed-fed6-4627-8d45-21619331d82a, 114c61f2-8935-4755-b4e9-4a598a51cc7f'''
DECLARE #SQL nvarchar(600)
SET #SQL =
'SELECT *
FROM Answer
WHERE Answer.RespondentId IN ('+#RespondentFilters+'''))
GROUP BY ChosenOptionId'
exec sp_executesql #SQL
END
It compiles and executes, but somehow it doesn't give me good results, just like the IN statement wasn't working. Please, if anybody know the solution to this problem, help me.
You should definitely look at splitting the list of GUIDs into a table and joining against that table. You should be able to find plenty of examples online for a table-valued function that splits an input string into a table.
Otherwise, your stored procedure is vulnerable to SQL injection. Consider the following value for #RespondentFilters:
#RespondentFilters = '''''); SELECT * FROM User; /*'
Your query would be more secure parsing (i.e. validating) the parameter values and joining:
SELECT *
FROM Answer
WHERE Answer.RespondentId IN (SELECT [Item] FROM dbo.ParseList(#RespondentFilters))
GROUP BY ChosenOptionId
or
SELECT *
FROM Answer
INNER JOIN dbo.ParseList(#RespondentFilters) Filter ON Filter.Item = Answer.RespondentId
GROUP BY ChosenOptionId
It's slightly more efficient as well, since you aren't dealing with dynamic SQL (sp_executesql will cache query plans, but I'm not sure if it will accurately identify your query as a parameterized query since it has a variable list of items in the IN clause).
You need single quotes around each GUID in the list
#RespondentFilters = '''8ec94bed-fed6-4627-8d45-21619331d82a'', ''114c61f2-8935-4755-b4e9-4a598a51cc7f'''
It looks like you don't have closing quotes around your #RespondentFilters '8ec94bed-fed6-4627-8d45-21619331d82a, 114c61f2-8935-4755-b4e9-4a598a51cc7f'
Since GUIDs do a string compare, that's not going to work.
Your best bet is to use some code to split the list out into multiple values.
Something like this:
-- This would be the input parameter of the stored procedure, if you want to do it that way, or a UDF
declare #string varchar(500)
set #string = 'ABC,DEF,GHIJK,LMNOPQRS,T,UV,WXY,Z'
declare #pos int
declare #piece varchar(500)
-- Need to tack a delimiter onto the end of the input string if one doesn't exist
if right(rtrim(#string),1) ','
set #string = #string + ','
set #pos = patindex('%,%' , #string)
while #pos 0
begin
set #piece = left(#string, #pos - 1)
-- You have a piece of data, so insert it, print it, do whatever you want to with it.
print cast(#piece as varchar(500))
set #string = stuff(#string, 1, #pos, '')
set #pos = patindex('%,%' , #string)
end
Code stolen from Raymond Lewallen
I think you need quotes inside the string too. Try:
#RespondentFilters = '''8ec94bed-fed6-4627-8d45-21619331d82a'',''114c61f2-8935-4755-b4e9-4a598a51cc7f'''
You could also consider parsing the #RespondentFilters into a temporary table.
Tank you all for your ansewers. They all helped a lot. I've dealt with the problem by writing a split function, and it works fine. It's a litte bit overhead from what I could have done, but you know, the deadline is hiding around the corner :)