Something wrong in Preprending string with spaces - sql

Based on the suggestion in this post Right pad a string with variable number of spaces
For testing purposes, I created a table and added the following rows
CREATE TABLE CharTest (
ID int,
CharField char(6) NULL
);
INSERT INTO CharTest
VALUES (1, ' 90');
INSERT INTO CharTest
VALUES (1, ' 89');
INSERT INTO CharTest
VALUES (1, NULL);
INSERT INTO CharTest
VALUES (1, ' 91');
INSERT INTO CharTest
VALUES (1, ' 90');
I then tried executing this query
DECLARE #lCharField char(6)
SET #lCharField = '90'
SELECT CharField FROM CharTest
where CharField = RIGHT(space(6) + #lCharField, 6)
it returned no rows.
I checked the output of the following queries
SELECT RIGHT(space(6) + #lCharField, 6) FROM CharTest
SELECT RIGHT(' ' + #lCharField, 6) FROM CharTest
and it doesn't seem to right-pad or pre-prend the spaces as expected.
Any help in pointing out what I am doing wrong is highly appreciated.

The issue is this code:
DECLARE #lCharField char(6);
SET #lCharField = '90';
You think the result is '90' but it is really '90 '. That throws everything off. Use:
DECLARE #lCharField varchar(6);
SET #lCharField = '90';
Here is a db<>fiddle.
Note that finicky spaces are one important reason why varchar() is used -- say -- 100 times more often than char(). The only really good use for char() is for columns that are of fixed width, such as ISO3 code for counties.

Related

Generating a unique batch id (SQL Server)

This is possible 2x questions in 1x. Sorry about that, but here goes:
PROBLEM
I am creating a unique batch id everytime a user uploads some data to SQL Server. Currently, I do this by looking at the last value of the 'Identity Specification' and add +1 to that.
Problem arises, as you might have guessed, if multiple users input data at the same, they both would get the same batch id...
Possible Solution
In order to mitigate this issue, I have come up with this method to generate 3 letter + random number; and the (last id value + 1):
DECLARE #tmp CHAR(3) = CHAR(CAST(RAND()*26 AS int)+65) + CHAR(CAST(RAND()*26 AS int)+65) + CHAR(CAST(RAND()*26 AS int)+65);
SELECT #tmp;
select cast(RAND()*9999 as int)
(1) I am not sure how to concatenate this into one line of string.
(2) The other question, is there a way to 100% guarantee every user is given a unique batch id every time they submit a request, regardless of how many are doing it simultaneously?
I would really appreciate your input in this.
1 - Concatenation part is very simple, you can do the following:
DECLARE #tmp VARCHAR(10);
SET #tmp = CHAR(CAST(RAND()*26 AS int)+65)
+ CHAR(CAST(RAND()*26 AS int)+65)
+ CHAR(CAST(RAND()*26 AS int)+65)
+ CAST(cast(RAND()*9999 as int) AS VARCHAR(4));
SELECT #tmp;
2 - I would suggest to populate a table with the Random values you would like to issue to users and then select from it, to avoid the race-condition.
Create a table called BatchNumbers with two Columns BatchNumber and Used.
Populate the batch number table and 0 as default value for Used Column.
Then everytime you need a batch number do the following.
CREATE PROC dbo.usp_Get_BatchNumber
#BatchNumber VARCHAR(10) OUTPUT
AS
BEGIN
SET NOCOUNT ON;
Declare #t TABLE (BN VARCHAR(10));
UPDATE TOP (1) BatchNumbers
SET Used = 1
OUTPUT inserted.BatchNumber INTO #t (BN )
WHERE Used = 0;
SELECT #BatchNumber = BN FROM #t;
END
You need an "Upload" table with a Bigint Identity column for the BatchID, then add a new row for every user upload.
The server will maintain the correct values and prevent collisions.
I would use the built in function for this:
select newid()
> 240CA878-135E-4176-AE57-0FA83FF74037
For the first problem, you can either create a variable for your random number as a char(4) and just simply concatenate the 2, or create it as an int and then CAST it as a VARCHAR while concatenating. Everything that is concatenated into a string must be a string.
DECLARE #tmp CHAR(3) = CHAR(CAST(RAND()*26 AS int)+65) + CHAR(CAST(RAND()*26 AS int)+65) + CHAR(CAST(RAND()*26 AS int)+65);
SELECT #tmp;
DECLARE #randNum VARCHAR(4) = CAST(RAND()*9999 AS INT)
-- OR DECLARE #randNum INT = CAST(Rand()*9999) AS INT)
SELECT #randNum
DECLARE #batchID VARCHAR(MAX) = #tmp + #randNum
-- OR DECLARE #batchID VARCHAR(MAX) = #tmp + CAST(#randNum AS VARCHAR)
SELECT #batchID
try the following:
1)
DECLARE #tmp CHAR(7) = CHAR(CAST(RAND()*26 AS int)+65) + CHAR(CAST(RAND()*26 AS int)+65) + CHAR(CAST(RAND()*26 AS int)+65) + cast(cast(RAND()*9999 as int) as varchar(4));
SELECT #tmp;
2) Yes, I think so.
I upvoted Terry Carmen's answer, but from his comments it sounds like he's suggesting something different from what I first thought, so here's a complete example. I think you want a table that has a key defined with the IDENTITY property, which will tell SQL Server that you want unique, sequential values in that column and you want the database to worry about the details of guaranteeing that this is so.
create table dbo.Import
(
-- identity(1, 1) means that SQL Server will automatically assign values for
-- this column when you insert a record, with 1 being the first value
-- assigned and each subsequent value incrementing by 1.
Identifier bigint not null identity(1, 1),
-- This column for illustration only; replace it with whatever data you need
-- to store.
YourStuffHere varchar(max)
);
-- Now simply use any INSERT or MERGE command against dbo.Import, and omit the
-- Identifier column from the list of columns whose values the command supplies.
-- Then you can use the SCOPE_IDENTITY() function or an OUTPUT clause to capture
-- the Identifier value that SQL Server has inserted.
-- Example 1: INSERT with explicit values and OUTPUT.
insert dbo.Import
(YourStuffHere)
output
inserted.Identifier
values
('Example 1');
-- Example 2: INSERT/SELECT with OUTPUT.
insert dbo.Import
(YourStuffHere)
output
inserted.Identifier
select
'Example 2';
-- Example 3: INSERT with SCOPE_IDENTITY().
insert dbo.Import
(YourStuffHere)
values
('Example 3');
select Identifier = convert(bigint, scope_identity());
-- Show table contents.
select * from dbo.Import;
The first INSERT statement above produces the following result:
Identifier
1
The second:
Identifier
2
The SELECT following the third INPUT gives:
Identifier
3
And the final SELECT shows you the contents of the table:
Identifier YourStuffHere
1 Example 1
2 Example 2
3 Example 3
This is the easiest way to go about this as it allows SQL Server to do all the real work for you. Please let me know if I've misunderstood your requirements.

SQL Find Replacement Character as a part of a string

I need help with writing a query which will find Replacement Character in SQL table.
I have multiple cells which contain that character and I want to find all those cells. This is how the value of cell looks like this:
Thank you for your help!
The UNICODE suggestion didn't work for me - the � character was being treated as a question mark, so the query was finding all strings with question marks, but not those with �.
The fix posted by Tom Cooper at this link worked for me: https://social.msdn.microsoft.com/forums/sqlserver/en-US/2754165e-7ab7-44b0-abb4-3be487710f31/black-diamond-with-question-mark
-- Find rows with the character
Select * From [MyTable]
Where CharIndex(nchar(65533) COLLATE Latin1_General_BIN2, MyColumn) > 0
-- Update rows replacing character with a !
Update [MyTable]
set MyColumn = Replace(MyColumn, nchar(65533) COLLATE Latin1_General_BIN2, '!')
Use the Unicode function:
DECLARE #TEST TABLE (ID INT, WORDS VARCHAR(10))
INSERT INTO #TEST VALUES (1, 'A�AA')
INSERT INTO #TEST VALUES (2, 'BBB')
INSERT INTO #TEST VALUES (3, 'CC�C')
INSERT INTO #TEST VALUES (4, 'DDD')
SELECT * FROM #TEST WHERE WORDS LIKE '%' + NCHAR(UNICODE('�')) + '%'
UPDATE #TEST
SET WORDS = REPLACE(WORDS, NCHAR(UNICODE('�')), 'X')
SELECT * FROM #TEST WHERE WORDS LIKE '%' + NCHAR(UNICODE('�')) + '%'
SELECT * FROM #TEST
In Sql you can able to replace the black diamond symbol.
Input : You�ll be coached through alternating
Output : You will be coached through alternating
select replace(description, nchar(65533) COLLATE Latin1_General_BIN2,' wi') from [Fitnesstable]
where description LIKE '%' + '. You'+NCHAR(55296) +'ll'+ '%'
Try the following code to search the query for the character you wish to find.
select field_name from tbl_name where instr(field_name, 'charToBeSearched') > 0;
This query will find and selects the records which has replacement character.

Add $ symbol to column values

I want to add $ symbol to column values and convert the column values to western number system
Dollars
4255
25454
467834
Expected Output:
$ 4,255
$ 25,454
$ 467,834
My Query:
select ID, MAX(Date) Date, SUM(Dollars) Dollars, MAX(Funded) Funding from Application
Dollars is the int datatype and needs to be changed.
You can do something like that. Converting from money to varchar with style 1 adds thousand separator:
declare #value int = 4255
select '$ ' + replace(convert(varchar(100), convert(money, #value), 1), '.00', '')
-- output: $ 4,255
If you process the data from SQL Server in any application, formatting is much easier to do in the code though.
Hello basing on your output you can approach like this also
declare #table Table (ID INT)
INSERT INTO #table (ID) VALUES (4255)
INSERT INTO #table (ID) VALUES (25454)
INSERT INTO #table (ID) VALUES (467834)
SELECT '$' + LEFT(CONVERT(VARCHAR(100),CAST(id AS MONEY),1),LEN(id)+ 1) from #table
Thanks

LIKE with Multiple Consecutive White Spaces

I have following query with LIKE predicate in SQL Server 2012. It replaces white spaces with %. I have two records in the table.
DECLARE #MyTable TABLE (ITMEID INT, ITMDESC VARCHAR(100))
INSERT INTO #MyTable VALUES (1,'Healty and Alive r')
INSERT INTO #MyTable VALUES (2, 'A liver patient')
DECLARE #SearchCriteria VARCHAR(100)
SET #SearchCriteria = 'Alive'
SELECT *
FROM #MyTable
WHERE (ITMDESC LIKE '%'+REPLACE(#SearchCriteria,' ','%')+'%' ESCAPE '\')
I got this query from a friend to consider multiple consequent white spaces as a single space. The challenge is I don't see any reference for this.
Is there a pitfall in the approach?
REPLACE(#SearchCriteria,' ','%') always returns Alive. There is no Alive word in the second row, therefore it's not returned.
In fact, WHERE clause will look like this: WHERE (ITMDESC LIKE '%Alive%' ESCAPE '\')
The second row doesn't meet it.
Probably, you want something like this:
SELECT *
FROM #MyTable
WHERE (REPLACE(ITMDESC,' ','') LIKE '%'+#SearchCriteria+'%' ESCAPE '\')
you can use as below
DECLARE #MyTable TABLE (ITMEID INT, ITMDESC VARCHAR(100))
INSERT INTO #MyTable VALUES (1,'Healty and Alive r')
INSERT INTO #MyTable VALUES (2, 'A liver patient')
ECLARE #SearchCriteria VARCHAR(100)
SET #SearchCriteria = 'Alive'
SELECT *
FROM #MyTable
WHERE (REPLACE(ITMDESC,' ','') LIKE '%'+#SearchCriteria+'%' ESCAPE '\')
it will return both records as you want
The simplest solution is to replace all spaces with some moniker and then replace that moniker with a single space.
Select Replace(Replace(ItmDesc, ' ', '<z>'), '<z>', ' ')
From MyTable
SQL Fiddle version

SQL How to find if all values from one field exist in another field in any order

I am trying to match data from an external source to an in house source. For example one table would have a field with a value of "black blue" and another table would have a field with a value of "blue black". I am trying to figure out how to check if all individual words in the first table are contained in a record the 2nd table in any order. It's not always two words that need to be compared it could be 3 or 4 as well. I know I could use a cursor and build dynamic sql substituting the space with the AND keywod and using the contains function but I'm hoping not to have to do that.
Any help would be much appreciated.
Try doing something like this: Split the data from the first table on the space into a temporary table variable. Then use CHARINDEX to determine if each word is contained in the second table's record. Then just do this for each word in the first record and if the count is the same as the successful checks then you know every word from the first record is used in the second.
Edit: Use a Split function such as:
CREATE FUNCTION dbo.Split (#sep char(1), #s varchar(512))
RETURNS table
AS
RETURN (
WITH Pieces(pn, start, stop) AS (
SELECT 1, 1, CHARINDEX(#sep, #s)
UNION ALL
SELECT pn + 1, stop + 1, CHARINDEX(#sep, #s, stop + 1)
FROM Pieces
WHERE stop > 0
)
SELECT pn,
SUBSTRING(#s, start, CASE WHEN stop > 0 THEN stop-start ELSE 512 END) AS s
FROM Pieces
)
Here's another method you could try, you could sample some simple attributes of your strings such as, length, number of spaces, etc.; then you could use a cross-join to create all of the possible string match combinations.
Then within your where-clause you can sort by matches, the final piece of which in this example is a check using the patindex() function to see if the sampled piece of the first string is in the second string.
-- begin sample table variable set up
declare #s table(
id int identity(1,1)
,string varchar(255)
,numSpace int
,numWord int
,lenString int
,firstPatt varchar(255)
);
declare #t table(
id int identity(1,1)
,string varchar(255)
,numSpace int
,numWord int
,lenString int
);
insert into #t(string)
values ('my name');
insert into #t(string)
values ('your name');
insert into #t(string)
values ('run and jump');
insert into #t(string)
values ('hello my name is');
insert into #s(string)
values ('name my');
insert into #s(string)
values ('name your');
insert into #s(string)
values ('jump and run');
insert into #s(string)
values ('my name is hello');
update #s
set numSpace = len(string)-len(replace(string,' ',''));
update #s
set numWord = len(string)-len(replace(string,' ',''))+1;
update #s
set lenString = len(string);
update #s
set firstPatt = rtrim(substring(string,1,charindex(' ',string,0)));
update #t
set numSpace = len(string)-len(replace(string,' ',''));
update #t
set numWord = len(string)-len(replace(string,' ',''))+1;
update #t
set lenString = len(string);
-- end sample table variable set up
-- select all combinations of strings using a cross join
-- and sort the entries in your where clause
-- the pattern index checks to see if the sampled string
-- from the first table variable is in the second table variable
select *
from
#s s cross join #t t
where
s.numSpace = t.numspace
and s.numWord = t.numWord
and s.lenString = t.lenString
and patindex('%'+s.firstPatt+'%',t.string)>0;