Replace function SQL - sql

I have problem that replace function does not work
DECLARE #Tabela nvarchar(25)
DECLARE #query nvarchar(max)
SET #Tabela = '_#tmp_tt2_POS_racuni_'
SET #query = 'SELECT * INTO '+#Tabela+((replace(convert(varchar(10), getdate(),121),'''-''',''''))+'-'+(replace(convert(nvarchar(10),getdate(),108),''':''','''')))+'NP'+' FROM _tabels'
PRINT #query
SELECT *
INTO _#tmp_tt2_POS_racuni_2021-12-21-11:15:27NP
FROM _tabels
Completion time: 2021-12-21T11:15:27.0724917+01:00

You should use FORMAT and specify the format you want directly instead of going through intermediate formats. For example :
select format(getdate(),'yyyyMMddhhmmss')
Produces 20211221124017. FORMAT is slower than CONVERT but in this case it's only called once. It's far more important to write a readable query that produces the correct result.
That said, it's probably better to use table partitioning instead of creating lots of temporary tables with a date in the name. All supported SQL Server versions and editions support partitioning, even LocalDB

The quotes you use are two too many.
You are using replace(date,''':''',''''). This will replace ':' with ''. However, the getdate() doesn't have quotes itself. I guess you did that because of the dynamic sql you are using - but for the dates, you should omit the quotes:
replace(date,':','')

Firstly, let's get onto the real problem that is discussed at lengths in the comments; this is a terrible idea.
The fact you want to create a table for an exact point in time smells very strongly of an XY Problem. What is the real problem you are trying to solve with this? Most likely what you really want is a partitioned table or a temporal table, so that you can query the data for an exact point in time. Which you need, we don't know, but I would suggest that you rethink your "solution" here.
As for the problem, it's working exactly as intended. Let's look at your REPLACE in solitude:
replace(convert(varchar(10), getdate(),121),'''-''','''')
So, in the above, you want to replace '-' (a hyphen wrapped in single quotes) with '' (2 single quotes). You don't want to replace a hyphen (-) with a zero length string; that would be REPLACE(..., '-','').
The style you are using, 121 gives the format yyyy-mm-dd hh:mi:ss.mmm, which doesn't contain a single single quote ('), so no wonder it isn't finding the pattern.
Though you don't need REPLACE on that date at all. YOu are taking the first 10 characters or the style and then removing the hyphens (-) to get yyyyMMdd, but there is already a style for that; style 112.
The above could be rewritten as:
DECLARE #Tabela sysname;
DECLARE #query nvarchar(max);
SET #Tabela = N'_#tmp_tt2_POS_racuni_';
SET #query = N'SELECT * INTO dbo.'+QUOTENAME(CONCAT(#Tabela,CONVERT(nvarchar(8),GETDATE(),112),,N'-'.REPLACE(CONVERT(nvarchar(10),GETDATE(),108),':',''),N'',N'NP')+N' FROM dbo._tabels;'
PRINT #query;

Related

Is it better to use Custom TABLE TYPE as parameter instead of SQL "IN" clause when passing a large comma separated value

I have a stored procedure it takes comma separated string as input. Which might be too large some times approximately more than 8 thousand characters or more. In that situation, query performance goes down sometimes. And I think there is a limitation for the character length inside the IN clause. For that, sometimes I get errors. Now, I need to know is it better to use a Custom TABLE TYPE as parameter and use Inner JOIN to find the result. If it is then why is it. Here are my 2 stored procedures (minimal code):
CREATE TYPE [dbo].[INTList] AS TABLE(
[ID] [int] NULL
)
Procedure 1
CREATE PROCEDURE [report].[GetSKU]
#list [INTList] READONLY,
AS
Select sk.SKUID,sk.Code SCode,sk.SName
FROM SKUs sk
INNER JOIN #list sst ON sst.ID=sk.SKUID
Procedure 2
CREATE PROCEDURE [report].[GetSKU]
#params varchar(max),
AS
Select sk.SKUID,sk.Code SCode,sk.SName
FROM SKUs sk
WHere CHARINDEX(','+cast( sk.SKUID as varchar(MAX))+',', #params) > 0
Now, which procedures is better to use.
Note: Original Stored Procedures does have few more Joins.
As this question did raise quite some discussion in comments but did not get any viable answer, I'd like to add the major points in order to help future research.
This question is about: How do I pass a (large) list of values into a query?
In most cases, people need this either in a WHERE SomeColumn IN(SomeValueList)-filter or to JOIN against this with something like FROM MyTable INNER JOIN SomeValueList ON....
Very important is the SQL-Server's version, as with v2016 we got two great tools: native STRING_SPLIT() (not position-safe!) and JSON support.
Furthermore, and rather obvious, we have to think about the scales and values.
Do we pass in a simple list of some IDs or a huge list with thousands of values?
Do we talk about simple integers or GUIDs?
And what's about text values, where we have to think about dangerous characters (like [ { " in JSON or < & in XML - there are many more...)?
What about CSV-lists, where the separating character might appear within the content (quoting / escaping)?
In some cases we might even want to pass several columns at once...
There are several options:
Table valued parameter (TVP, CREATE TYPE ...),
CSV together with string splitting functions (native since v2016, various home brewed, CLR...),
and text-based containers: XML or JSON (since v2016)
Table valued paramter (TVP - the best choice)
A table valued parameter (TVP) must be created in advance (this might be a draw back) but will behave as any other table once created. You can add indexes, you can use it in various use cases and you do not have to bother about anything under the hood.
Sometimes we cannot use this due to missing rights to use CREATE TYPE...
Character separated values (CSV)
With CSV we see three approaches
Dynamic Sql: Create a statement, where the CSV list is simply stuffed into the IN() and execute this dynamically. This can be a very efficient approach, but will be open to various obstacles (no ad-hoc-usage, injection threat, breaking on bad values...)
String splitting functions: There are tons of examples around... All of them have in common that the separated string will be returned as a list of items. Common issues here: performance, missing ordinal position, limits for the separator, handling of duplicate or empty values, handling of quoted or escaped values, handling of separators within the content. Aaron Bertrand did some great research about the various approaches of string splitting. Similar to TVPs one draw back might be, that this function must exist in the database in advance or that we need to be allowed to execute CREATE FUNCTION if not.
ad-hoc-splitters: Before v2016 the most used approach was XML based, since then we have moved to JSON based splitters. Both use some string methods to transform the CSV string to 1) separated elements (XML) or 2) into a JSON-array. The result is queried by 1) XQuery (.value() and .nodes()) or 2) JSON's OPENJSON() or JSON_VALUE().
Text based containers
We can pass the list as string, but within a defined format:
Using ["a","b","c"] instead of a,b,c allows for immediate usage of OPENJSON().
Using <x>a</x><x>b</x><x>c</x> instead allows for XML queries.
The biggest advantage here: Any programming language provides support for these formats.
Common obstacles like date and number formatting is solved implicitly. Passing JSON or XML is - in most cases - just some few lines of code.
Both approaches allow for type- and position-safe queries.
We can solve our needs without the need to rely on anything existing in advance.
For the very best performance you can use this function:
CREATE FUNCTION [dbo].StringSplit
(
#String VARCHAR(MAX), #Separator CHAR(1)
)
RETURNS #RESULT TABLE(Value VARCHAR(MAX))
AS
BEGIN
DECLARE #SeparatorPosition INT = CHARINDEX(#Separator, #String ),
#Value VARCHAR(MAX), #StartPosition INT = 1
IF #SeparatorPosition = 0
BEGIN
INSERT INTO #RESULT VALUES(#String)
RETURN
END
SET #String = #String + #Separator
WHILE #SeparatorPosition > 0
BEGIN
SET #Value = SUBSTRING(#String , #StartPosition, #SeparatorPosition- #StartPosition)
IF( #Value <> '' )
INSERT INTO #RESULT VALUES(#Value)
SET #StartPosition = #SeparatorPosition + 1
SET #SeparatorPosition = CHARINDEX(#Separator, #String , #StartPosition)
END
RETURN
END
This function return table - select * from StringSplit('12,13,14,15,16', ',') so you can join this function to your table or can use IN on the where clause.

Create INSERT statement using parameter

I need to create a INSERT statement using parameters. Say I have two variable name #DestinationFields, #InsertValues.
Here #DestinationFields contain the column name like: product,price and #InsertValues contains the values for those two columns, like: Book,100.
Now, How i create a insert command to insert those values where each value need to add a quotation mark .I already tried as
I already tried as
EXEC('INSERT into tbl_test('+#DestinationFields+')values('+#InsertValues+')')
But it's returning an error.
The name "book" is not permitted in this context. Valid expressions are constants, constant expressions, and (in some
contexts) variables. Column names are not permitted.
How do I do it? Thanks in advance.
Pretending there is no problem of SQL injection here*, you can quickly fix your code by adding quotation marks around Book. The value of # InsertValues should be
'Book', 100
instead of simply
Book, 100
You need to add quotation marks around each string value; otherwise, strings are interpreted as names, which is not valid.
EDIT : (in response to a comment) If all columns are of varchar type, you can put quotes around the entire string, and replace all commas with the quote-comma-quote pattern, like this:
values('''+REPLACE(#InsertValues,',',''',''')+''')'
* You should not put code like this into production, because it can be manipulated to harm your system rather severely. Here is a good illustration of the problem (link).
Try:
DECLARE #DestinationFields VARCHAR(200);
SET #DestinationFields = 'Col1, Col2, Col3'
DECLARE #InsertValues VARCHAR(200);
SET #InsertValues = '1, 2, 3'
DECLARE #SQLString VARCHAR(1000);
SET #SQLString = 'INSERT INTO tbl_test (' + #DestinationFields + ') VALUES (' + #InsertValues + ')';
EXEC (#SQLString)
However, this is very open to SQL Injection attacks. But, it will do what you require.
The Curse and Blessing of Dynamic SQL

sql- exceeding variable size in a exec?

I inherited some partially complete sql code that I can't get to work.
it accesses multiple databases, so it first searches for proper database using a userID number, then inserts that database name into a query. the part i'm having a problem with (extremely abbreviated) is...
DECLARE #sql AS VARCHAR(8000)
SET #sql = 'INSERT INTO ['+#DatabaseName+'].dbo.[customer]
( -- containing about 200 columns. )
VALUES(...)'
PRINT #sql
EXEC(#sql)
i would get errors in the middle of a column name, sometimes saying it's expecting a parenthesis or quote. i started deleting white space so that, ie, [first name],[last name] were on the same line and not two different lines and that would get me a little further down the query. i don't have much more white spaces i can delete and i'm only just getting into the Values(...) portion of it. the weird thing is. i copy and pasted just the columns portion and put it into Word and it comes up as being only about 3,000 characters, including white space.
am i missing something?
if it means anything, i'm running microsoft sql server 2005, and using the sql server management studio for editing
thanks!
See here: SQL Server: When 8000 Characters Is Not Enough for a couple of solutions
extremely abbreviated
Well, that doesn't really help since you have likely abbreviated away the cause of the issue.
If I were to guess, I have seen cases where NCHAR or CHAR variables/columns were involved. These expand to their full length when used in string concatenation and it will cause the final statement to be too long.
For what it's worth for style or otherwise, use NVarchar(Max) always for SQL Server 2005 and onwards. In fact, that is the expected type if you use sp_executesql.
If you check for fixed-width N/CHAR columns and switch to nvarchar(max), you may see the problem go away.
EDIT: Test showing NVarchar(Max) holding well in excess of 8000 bytes.
declare #sql nvarchar(max)
-- this CTE sets up the columns, 1 as field1, 2 as field2 etc
-- it creates 2000 columns
;with CTE(n, t) AS (
select 1, convert(nvarchar(max),'1 as field1')
union all
select n+1, convert(nvarchar(max),RIGHT(n, 12) + ' as field'+RIGHT(n, 12))
from cte
where N < 2000)
select #sql = coalesce(#sql+',','') + t
from CTE
option (maxrecursion 2000) -- needed, the default of 100 is not nearly enough
-- add the SELECT bit to make a proper SQL statement
set #sql = 'select ' + #sql
-- check the length : 33786
select LEN(#sql)
-- check the content
print #sql
-- execute to get the columns
exec (#sql)
Use an nvarchar(max) datatype for #sql.

Contains performs MUCH slower with variable vs constant string SQL Server

For some unknown reason I'm running into a problem when passing a variable to a full text search stored procedure performs many times slower than executing the same statement with a constant value. Any idea why and how can that be avoided?
This executes very fast:
SELECT * FROM table
WHERE CONTAINS (comments, '123')
This executes very slowly and times out:
DECLARE #SearchTerm nvarchar(30)
SET #SearchTerm = '123'
SET #SearchTerm = '"' + #SearchTerm + '"'
SELECT * FROM table
WHERE CONTAINS (comments, #SearchTerm)
Does this make any sense???
I've seen the same issue with trying to use a variable for top. SQL Server is not able to tune a query that is using a variable in this way.
You should try using the execsql command.
does this run slow: SELECT * FROM table WHERE CONTAINS (comments, N'123') ??
you are using a varchar '123' in the first example and a nvarchar variable in the second example. This type conversion could be causing you the problem. What is the column defined as?
Also why wrap the variable's value in " double qoutes, but not do the same in the first example. When you run the exact same queries using a literal and a variable do the run differently?
I think Matt b is right. The first query you are searching for
123
In the second query, you are searching for
'123'
The second query with the quotes is probably returning no results, and your program is probably timing out, not the query.

Accessing text fields in a stored procedure and insert to another table

I am trying to access a “text” type and inserting that value into another table viw a stored procedure. I’ve tried to cast it, convert it, but nothing works.
My code looks somethings like this:
Declare #Critique varchar(max), #Feedback varchar(max)
…
…
…
SELECT #Critique = CAST(comments as varchar(max)), #Feedback = CAST(public_critique as varchar(max)) FROM ASCO_vEXTERNAL_REVIEW_APPLICATIONS_LIST WHERE wf_task_assignment_id = #WfTaskAssignmentIDP1
– comments and public_critique are defined as text in view (also tried with table) ASCO_vEXTERNAL_REVIEW_APPLICATIONS_LIST
…
…
…
insert into WF_TASK_ASSIGNMENT_REVIEW (wf_task_assignment_review_id, wf_task_assignment_id, grantee_project_id, comments, public_critique) values (#NewID1, #WfTaskAssignmentIDP2, #GranteeProjectID, #Critique, #Feedback)
Can you please help me with this as soon as possible. I would really appreciate this.
Thanks,
Harish
I'm assuming that the WF_TASK_ASSIGNMENT_REVIEW is the one containing the text column you're trying to write into.
The text type is now deprecated in SQL 2005 and 2008. If at all possible try and upgrade the WF_TASK_ASSIGNMENT_REVIEW table to use the nvarchar(max) type instead.
If not, the only way is to use the WRITETEXT statement to write into the target column, in a loop (since WRITETEXT has an upper limit). See the WRITETEXT statement example in the SQL Server docs.
Your question is not sound good to understand .
Dont use text ,it wont support in many cases like where ,group by etc , so try use varchar
This is just an example
Declare #Critique varchar(max)
set #Critique = (select public_critique from ASCO_vEXTERNAL_REVIEW_APPLICATIONS_LIST
where convert(varchar(50), wf_task_assignment_id ) =#WfTaskAssignmentIDP1)