SQL Server : Like Syntax and Add operator Error - sql-server

I am using this syntax and it should work well if only it doesn't get an error.
SELECT
e.user_key,
e.char_key,
CONVERT(VARCHAR,substring(e.char_data, 9, 16)) AS name,
p.CHAR_DATA
FROM
CHAR_DATA0 AS e
INNER JOIN
CHAR_DATA1 AS p ON e.CHAR_KEY = p.CHAR_KEY
WHERE
p.CHAR_DATA LIKE '%'+CAST(cast(reverse(CONVERT(BINARY, 9998)) as BINARY(2)) AS BINARY(2))+'%'
ORDER BY
char_key
I need help. How to change this code for it to work?
CHAR_DATA column is of type BINARY(2000)
I have data like so: (got it using select)
0x04005C03020F2789080100000F278908010000FFFFFFFFFFFFFF0E2787080100000E278708010000FFFFFFFFFFFFFFBA3B8C08000000BB3B8C080000000F2789080100000F278908010000FFFFFFFFFFFFFF0E2787080100000E278708010000FFFFFFFFFFFFFFBC3B8C08000000BD3B8C080000000F2789080100000F278908010000FFFFFFFFFFFFFF0E2787080100000E278708010000FFFFFFFFFFFFFFBE3B8C08000000BF3B8C080000000F2789080100000F278908010000FFFFFFFFFFFFFF0E2787080100000E278708010000FFFFFFFFFFFFFFC03B8C08000000C13B8C08000000B5388B08020000B5388B08020000FFFFFFFFFFFFFF0E2787080100000E278708010000FFFFFFFFFFFFFFBA3B8C08000000BB3B8C08000000B5388B08020000B5388B08020000FFFFFFFFFFFFFF0E2787080100000E278708010000FFFFFFFFFFFFFFBC3B8C08000000BD3B8C080000000E2789080100000E278908010000FFFFFFFFFFFFFF0E2787080100000E278708010000FFFFFFFFFFFFFFBE3B8C08000000BF3B8C080000000E2789080100000E278908010000FFFFFFFFFFFFFF0E2787080100000E278708010000FFFFFFFFFFFFFFC03B8C08000000C13BFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFF0F27FFFF0100000F27FFFF0100000E2789080000000E278908000000FFFFFFFFFFFFFF7E107F08000000EC168408000000B0177D080000000F27FFFF0100000F27FFFF0100000E2789080000000E27890800000052167C081E000052167C081E0000E2167D08000000271F2005000000FFFFFFFFFFFFFFFFFFFFFFFFFFFF0E2787080100000E27870801000052167C081E000052167C081E0000FFFFFFFFFFFFFF13127F08000000C813FFFF1E0000C813FFFF1E00000E2787080100000E27870801000028127A08000000BF3B2D05000000FFFFFFFFFFFFFF13127F08000000C813FFFF1E0000C813FFFF1E0000FFFFFFFFFFFFFFFFFFFFFFFFFFFF28127A08000000FFFFFFFFFFFFFF1B1A80081A00001B1A80081A0000E915FFFF1B0000E915FFFF1B000023067A0800000024147B0800000020120D05000000084792080100001B1A80081A00001B1A80081A0000E915FFFF1B0000E915FFFF1B000025067A0800000024147B0800000020120D05000000E21610050000000000009D000000FFFF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
I need to search somewhere in those lines if it contains the entry I'm trying to find.
What I'm trying to find is always 2 bytes. So I'm looking for 0x0E27 in the syntax above.
This is a working syntax but its not what I want to do:
SELECT
CONVERT(INT,cast(reverse(substring(char_data, 37, 2)) as BINARY(2))) AS helm
FROM CHAR_DATA0
WHERE CHAR_KEY = 5
Another this is if I use nvarchar(MAX) it gives results that doesn't even contain the data I'm trying to find.

where Convert(varChar(4000), CHAR_DATA,2 ) like '%' + Convert(varChar(4), CONVERT(BINARY(2), 9998),2 )+'%'

I tried just selecting that like clause, mainly because I don't need your schema (tables) to do so, and found a bug (I think) already:
SELECT '%' + CAST( CAST(REVERSE(CONVERT(BINARY, 9998)) as BINARY(2)) AS BINARY(2) ) + '%'
produces:
Msg 402, Level 16, State 1, Line 1
The data types varchar and binary are incompatible in the add operator.
... where as (changing the overal result type to varchar):
SELECT '%' + CAST( CAST(REVERSE(CONVERT(BINARY, 9998)) as BINARY(2)) AS VARCHAR(2) ) + '%'
produces (we'll need some luck with the encoding here):
%'% -- that is: percent, apostrophe, beam (the musical note), percent
Maybe that's the whole problem (though I doubt it)? Try it and let-is know how you go. I doubt it because I guess that if it was the whole problem then you would have worked it out for yourself from the error message (that I presume you would have gotten from SQL-Server).
Cheers. Keith.

Related

Escaping an ampersand in SQL Server Full-Text Search query using CONTAINSTABLE

I have a very peculiar case. My ASP.NET page calls a stored procedure of ours that performs a Full-Text Search query on our database. Some of the commonly searched strings include an ampersand because a few brands of our products (well-known brands, too) have an & in their name.
It turns out that in a certain case I get no results unless I escape the ampersand (\&), and in a certain other case I get no results only if I escape the ampersand.
I don't know if this is relevant, but (without giving out the brand names) one ends in &b and the other one in &c.
Is it possible that these strings (&b or &c) have some special meaning of their own? And that by escaping them I'm actually passing a special string to T-SQL?
EDIT
Additional info: after further testing, I proved that the error is in the stored procedure itself. Calling it with & or \& yields different results.
I'll try to post selected parts of the stored procedures. I won't post it all, because most of it isn't really relevant.
The vParamBuca parameter is the one that causes the troubles. Values could be 'word&letter' or word\&letter.
SET #ricercaA = '''FORMSOF(INFLECTIONAL,"' +
REPLACE(LTRIM(RTRIM(#vParamBuca)),' ', '") AND FORMSOF(INFLECTIONAL,"') + '")'''
The variable #ricercaA is then used to create the query string:
[...]
FROM Products AS FT_TBL
LEFT OUTER JOIN CONTAINSTABLE (Products, Sign1, '+ #ricercaA + ') AS ColSign1_0 ON FT_TBL.ID = ColSign1_0.[KEY]
LEFT OUTER JOIN CONTAINSTABLE (Products, ManufacturerAdditionalText, '+ #ricercaA + ') AS ColManufacturerAdditionalText_0 ON FT_TBL.ID = ColManufacturerAdditionalText_0.[KEY]
LEFT OUTER JOIN CONTAINSTABLE (Products, ManufacturerForSearch, '+ #ricercaA + ') AS ColManufacturer_0 ON FT_TBL.ID = ColManufacturer_0.[KEY]
LEFT OUTER JOIN CONTAINSTABLE (Products, TuttaLaRiga, '+ #ricercaA + ') AS ColTuttaLaRiga_0 ON FT_TBL.ID = ColTuttaLaRiga_0.[KEY]
[...]
EDIT 2
Many thanks to #srutzky for pointing me in the right direction! In the meanwhile, I also found a data inconsistency where one of the brands with the & in its name was modified not to have the &, and the other one wasn't modified (bottom line, my current problem is caused by that: a partial fix that was made by someone in the past).
Anyway, back on track. Now I understand that the & character in the CONTAINSTABLE function is treated as a logical AND (non bitwise).
I still need a solution for that. This answer gives a solution that doesn't work for me (the conditions are not the same as mine). How could I perform a CONTAINSTABLE search for a string with an ampersand in it? Preferably without having to transform the ampersand to another safe character?
The odd behavior you are seeing is most likely due to the CONTAINS and CONTAINSTABLE functions (both used with SQL Server's Full Text Search feature) using the ampersand ( & ) character as equivalent to the AND operator. The following statement is taken from the documentation for CONTAINS:
The ampersand symbol (&) may be used instead of the AND keyword to represent the AND operator.
There is no mention of there being any escape character for it (and a back-slash isn't typically an escape character in SQL anyway).
UPDATE
Based on the information now provided in "Edit 2" of the Question, and additional research, I would say that you do not need to escape anything. It seems that putting the search phrases in double-quotes (as a result of using FORMSOF) treats the & as either a literal or a word-breaker, depending on the values on both sides of the &. Try the following examples:
DECLARE #Term NVARCHAR(100);
SET #Term = N'bob&sally'; -- 48 rows
--SET #Term = N'bob\&sally'; -- 48 rows
--SET #Term = N'r&f'; -- 4 rows
--SET #Term = N'r\&f'; -- 24 rows
SET #Term = N'FORMSOF(INFLECTIONAL,"' + #Term + '")';
SELECT * FROM sys.dm_fts_parser(#Term, 1033, 0, 0);
SELECT * FROM sys.dm_fts_parser(#Term, 1033, 0, 1);
SELECT * FROM sys.dm_fts_parser(#Term, 1033, NULL, 0);
SELECT * FROM sys.dm_fts_parser(#Term, 1033, NULL, 1);
The results for bob&sally and bob\&sally are the same, and in both cases bob and sally are separated and never combined into a single exact-match string.
The results between r&f and r\&f, however, are not the same. r&f is only ever treated as a single, exact-match string because r and f alone are not known words. On the other hand, adding in the back-slash separates the two letter since \ is a word-breaker, in which case you get both r and f.
Given that you stated in the Update that you have "data inconsistency, where one of the brands with the "&" in its name was modified not to have the "&", and the other one wasn't", I suspect that when you do not add in the \ character you get the brand that was not modified (since it is an exact match for the full term). But when you do add in the \ character, then you get the brand that was modified to have the & removed, since you are now searching on both pieces, each one matching part of that brand name.
I would fix the data to be consistent: update the brand names that had the & removed to put the ampersands back in. Then when people search using & without the extra \ added, it will be an exact match. This behavior will be consisted across the data, and will not require you adding code to circumvent the natural operation of FTS, which seems to be an error-prone approach.

Why are my results in SSRS different from SQL SMS?

I've never seen this happen before, so I'm curious if anybody knows why, and maybe how I can correct for it.
This particular part of my code:
SELECT inv_num, co_line,
STUFF((
SELECT '/' + rs2.inv_pro_description
FROM #ReportSet rs2
WHERE rs2.inv_num = rs.inv_num AND
rs2.co_line = rs.co_line
FOR XML PATH('')), 1, 1, '') as ipd_combo
FROM #ReportSet rs
WHERE inv_pro_seq IS NOT NULL AND inv_pro_description <> 'Less Previously Invoiced'
GROUP BY inv_num, co_line
results in a correct concatenation of my two results, e.g., "10% Advance/Fixed $5 Required" in this case. However, when utilizing this procedure in SSRS, my field contains instead "Fixed $5 Required/10% Advance".
I have grown accustomed to being able to predict my SSRS reports based on running SQL queries, so this confused me.
I don't really understand the STUFF / XML PATH code, of course. I've copied it from somebody else (on this website, naturally) so I know that might have something to do with it.
To get consistent ordering, add an order by clause to your inner select:
SELECT inv_num, co_line,
STUFF((
SELECT '/' + rs2.inv_pro_description
FROM #ReportSet rs2
WHERE rs2.inv_num = rs.inv_num AND
rs2.co_line = rs.co_line
ORDER BY rs2.inv_pro_seq --********
FOR XML PATH('')), 1, 1, '') as ipd_combo
FROM #ReportSet rs
WHERE inv_pro_seq IS NOT NULL AND inv_pro_description <> 'Less Previously Invoiced'
GROUP BY inv_num, co_line
The commented asterisks indicate the added line.
(I answered in comments, but adding this here for consistency/permanency).

Concat the values in a string with SQL Server

I want to select a list of items and part numbers for for each item as a string:
SELECT top 100 *
FROM ii
OUTER APPLY
(SELECT def, ( ipr.part_number + ',') as prt
FROM ipr
WHERE ii.item_id = ipr.item_id
FOR XML PATH('') ) PN
The error is:
[Error Code: 8155, SQL State: S0002] No column name was specified for
column 1 of 'PN'.
How can I fix this?
I think that your whole OUTER APPLY statement generates one XML for both default_part_number and concatenated string, which(the whole XML) doesn't have a name.
What you could try to do would be adding alias like this AS PN(TestThis).
However, I don't think that you're expecting result you're going to get. It would better if you'd give us some example data and expected output. It will be easier for us to solve your problem in that case.
The combination of XML and STUFF is funny but perfectly fitting to your needs.
First you concat your strings with the ', ' in front, then you must return your XML with ", TPYE). You must read the result with ".value()" and use STUFF to replace the first ', '.
You'll find a lot of exampels in the net...

CAST error in a Where Clause

On the query below I keep getting this error:
Cannot read the next data row for the dataset DataSetProject. (rsErrorReadingNextDataRow)
It appears to be the where clause, if I take it out it seems to work. So I added a cast to the where clause with no luck. Is there something special I need to do in the where clause to get this to work? Just an FYI this is in a report that is pulling an id from the url.
SELECT new_projects.new_projectsId AS ProjectId
, new_projects.new_name AS ProjectName
, new_projects.new_Description AS ProjectDescription
FROM
new_projects
LEFT OUTER JOIN new_projectsteps
ON new_projects.new_projectsId = new_projectsteps.new_ProjectSteps2Id
LEFT OUTER JOIN Task
ON new_projectsteps.new_projectstepsId = Task.RegardingObjectId
WHERE
(new_projects.new_projectsId = cast(#id AS UNIQUEIDENTIFIER))
Thanks!
EDIT:
The id in SQL is a Unique Identifier, the value of #id is being pulled from the querystring(url). So it would look like: &id='BC02ABC0-A6A9-E111-BCAD-32B731EEDD84'
Sorry for the missing info.
I suspect the single quotes are coming through. So either don't have them there by stripping them out before being passed to your parameter or use:
WHERE new_projects.new_projectsId = CONVERT(UNIQUEIDENTIFIER, REPLACE(#id, '''', ''));
If you try a direct comparison when the GUID contains other characters, you should get:
Msg 8169, Level 16, State 2, Line 1 Conversion failed when
converting from a character string to uniqueidentifier.
If this is not what's happening, then don't say "the id in SQL is a Unique Identifier" - show ALL of the code so we can try to reproduce the problem.

TSQL to insert an ascending value

I am running some SQL that identifies records which need to be marked for deletion and to insert a value into those records. This value must be changed to render the record useless and each record must be changed to a unique value because of a database constraint.
UPDATE Users
SET Username = 'Deleted' + (ISNULL(
Cast(SELECT RIGHT(MAX(Username),1)
FROM Users WHERE Username LIKE 'Deleted%') AS INT)
,0) + 1
FROM Users a LEFT OUTER JOIN #ADUSERS b ON
a.Username = 'AVSOMPOL\' + b.sAMAccountName
WHERE (b.sAMAccountName is NULL
AND a.Username LIKE 'AVSOMPOL%') OR b.userAccountControl = 514
This is the important bit:
SET Username = 'Deleted' + (ISNULL(
Cast(SELECT RIGHT(MAX(Username),1)
FROM Users WHERE Username LIKE 'Deleted%') AS INT)
,0) + 1
What I've tried to do is have deleted records have their Username field set to 'Deletedxxx'. The ISNULL is needed because there may be no records matching the SELECT RIGHT(MAX(Username),1) FROM Users WHERE Username LIKE 'Deleted%' statement and this will return NULL.
I get a syntax error when trying to parse this (Msg 156, Level 15, State 1, Line 2
Incorrect syntax near the keyword 'SELECT'.
Msg 102, Level 15, State 1, Line 2
Incorrect syntax near ')'.
I'm sure there must be a better way to go about this, any ideas?
If your Users table already has an integer PK column, you can simply use this column to generate 'Deleted'+PK usernames.
Btw, would the SELECT RIGHT(MAX(Username),1) not fail after 10 users? Better to use SUBSTRING().
Is it strictly necessary to use incremental 'xxx' values? Couldn't you just use random values?
SET Username = Username + '_deleted_' + CAST(NEWID() AS char(36))
Additionally, it might be a bad idea to overwrite the login completely. Given that you disable the record, not delete it entirely, I assume that you need it for audit purposes or smth. like that. In this case, records with IDs like 'Deleted1234' might be too anonymous.
I suspect this would work better as a multi-step SQL statement, but I'm unsure if that's reasonable.
The error you're seeing is because you're trying to concatenate an int to a string, you're also adding 1. Your order of operations is all screwy in that set statement. This does what you're asking, but it will fail the minute you get more than 9 deleted entries.
SELECT 'DELETED' + CAST(
ISNULL(
CAST(
SELECT RIGHT(MAX(Username),1)
FROM #Users WHERE username LIKE 'DELETED%')
AS INT)
, 0) + 1 )
AS VARCHAR(3))
edit: sorry for the horrible formatting. Couldn't figure out how to make it readable.

Resources