Adding Trailing Zeros to an int field in SQL - sql

In the process of resequencing my web items, I am trying to append 4 zeros on the end of each item sequence number. Everything I try does not work, it seems to automatically remove the trailing zeros because of formatting. This is an int field. The only thing I got to work for 1 item as a test was actually doing a replace such as:
update sacatalogitem
set itm_seq = replace(itm_seq, '8021', '80210000')
where itm_id = '13' and ctg_id = '917'
I have tried using a cursor with the replace and it strips the trailing zeros when executing this:
declare #SEQ int
declare #ID int
declare #CTG int
declare cur cursor for
select a.itm_seq, a.itm_id, a.ctg_id from sacatalogitem as a
join saitem as b on b.itm_id = a.itm_id
where a.cat_id = '307' and a.itm_id = '13' and a.ctg_id = '917'
open cur
fetch next from cur into #SEQ,#ID,#CTG
While (##FETCH_STATUS=0)
Begin
Update sacatalogitem
set itm_seq = replace(itm_seq, #SEQ, #SEQ + '0000')
where itm_id = #ID and ctg_id = #CTG
Update saitem
set itm_import_action = 'P'
where itm_id = #ID
fetch next from cur into #SEQ,#ID,#CTG
end
close cur
deallocate cur
This also fails for me:
update sacatalogitem
set itm_seq = itm_seq + '0000'
where itm_id = '13' and ctg_id = '917'
Any help would be appreciated for this small frustrating problem.

If it is an integer field, MULTIPY IT BY 10000.
update sacatalogitem
set itm_seq = itm_seq * 10000
where itm_id = '13' and ctg_id = '917'

You could try
cast(cast (itemsec as varchar) + '0000' as int)
but frankly #VJHill 's answer is neater

Related

How to compare two strings based on percent match in SQL

I want to post a solution to a interesting problem I was facing in T-SQL.
The problem:
Compare two string fields based on a percent match.
In addition, the two strings may have the words in them translocated.
For example: "Joni Bravo" and "Bravo Joni". These two strings should return a match of 100%, which means that position is not relevant. Few more things worth noting are that this code is made to compare strings that have space as delimiter in them. If the first string doesnt have space the match is set to 100% without actual check. This was not developed, because the strings this function is ment to compare always contain two or more words. Also, it is written on MS SQL Server 2017 if that mathers.
So here is the solution, hope this helps anyone :)
gl
/****** Object: UserDefinedFunction [dbo].[STRCOMP] Script Date: 29/03/2018 15:31:45 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[STRCOMP] (
-- Add the parameters for the function here
#name_1 varchar(255),#name_2 varchar(255)
)
RETURNS float
AS
BEGIN
-- Declare the return variable and any needed variable here
declare #p int = 0;
declare #c int = 0;
declare #br int = 0;
declare #p_temp int = 0;
declare #emergency_stop int = 0;
declare #fixer int = 0;
declare #table1_temp table (
row_id int identity(1,1),
str1 varchar (255));
declare #table2_temp table (
row_Id int identity(1,1),
str2 varchar (255));
declare #n int = 1;
declare #count int = 1;
declare #result int = 0;
declare #total_result float = 0;
declare #result_temp int = 0;
declare #variable float = 0.0;
--clean the two strings from unwanted symbols and numbers
set #name_1 = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(#name_1,'!',''),' ',' '),'1',''),'2',''),'3',''),'4',''),'5',''),'0',''),'6',''),'7',''),'8',''),'9','');
set #name_2 = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(#name_2,'!',''),' ',' '),'1',''),'2',''),'3',''),'4',''),'5',''),'0',''),'6',''),'7',''),'8',''),'9','');
--check if the first string has more than one words inside. If the string does
--not have more than one words, return 100%
set #c = charindex(' ',substring(#name_1,#p,len(#name_1)));
IF(#c = 0)
BEGIN
RETURN 100.00
END;
--main logic of the operation. This is based on sound indexing and comparing the
--outcome. This loops through the string whole words and determines their soundex
--code and then compares it one against the other to produce a definitive number --showing the raw match between the two strings #name_1 and #name_2.
WHILE (#br != 2 or #emergency_stop = 20)
BEGIN
insert into #table1_temp(str1)
select substring (#name_1,#p,#c);
set #p = len(substring (#name_1,#p,#c))+2;
set #p = #p + #p_temp - #fixer;
set #p_temp = #p;
set #c = CASE WHEN charindex(' ',substring(#name_1,#p,len(#name_1))) = 0 THEN len(#name_1) ELSE charindex(' ',substring(#name_1,#p,len(#name_1))) END;
set #fixer = 1;
set #br = CASE WHEN charindex(' ',substring(#name_1,#p,len(#name_1))) = 0 THEN #br + 1 ELSE 0 END;
set #emergency_stop = #emergency_stop +1;
END;
set #p = 0;
set #br = 0;
set #emergency_stop = 0;
set #fixer = 0;
set #p_temp = 0;
set #c = charindex(' ',substring(#name_2,#p,len(#name_2)));
WHILE (#br != 2 or #emergency_stop = 20)
BEGIN
insert into #table2_temp(str2)
select substring (#name_2,#p,#c);
set #p = len(substring (#name_2,#p,#c))+2;
set #p = #p + #p_temp - #fixer;
set #p_temp = #p;
set #c = CASE WHEN charindex(' ',substring(#name_2,#p,len(#name_2))) = 0 THEN len(#name_2) ELSE charindex(' ',substring(#name_2,#p,len(#name_2))) END;
set #fixer = 1;
set #br = CASE WHEN charindex(' ',substring(#name_2,#p,len(#name_2))) = 0 THEN #br + 1 ELSE 0 END;
set #emergency_stop = #emergency_stop +1;
END;
WHILE((select str1 from #table1_temp where row_id = #n) is not null)
BEGIN
set #count = 1;
set #result = 0;
WHILE((select str2 from #table2_temp where row_id = #count) is not null)
BEGIN
set #result_temp = DIFFERENCE((select str1 from #table1_temp where row_id = #n),(select str2 from #table2_temp where row_id = #count));
IF(#result_temp > #result)
BEGIN
set #result = #result_temp;
END;
set #count = #count + 1;
END;
set #total_result = #total_result + #result;
set #n = #n + 1;
END;
--gather the results and transform them in a percent match.
set #variable = (select #total_result / (select max(row_count) from (
select max(row_id) as row_count from #table1_temp
union
select max(row_id) as row_count from #table2_temp) a));
RETURN #variable/4 * 100;
END
GO
PS: I decided to write it in a user-defined function just for the needs of my project.

My SQL Function is not returning the value I expected

This was my first attempt at a SQL function. I wrote it in VB and it works like a charm. When I translated it to SQL Server, it returns not what I expect. What the function is intended to do is to return a percentage match of two strings.
How I expected it to function is this:
accept two strings, compare the two, and based on my rating values, return a percentage of the match value...matchscore/max possiblescore
The length of the larger string is multiplied by 3. This is the max possiblescore.
Go character by character of the first string and find that character in the second string.
If the character is found in the same position in the second string, add three to the matchscore and move on to the next letter.
If the character is found in the second word, but not in the same position, add one to match score and move on to the next character.
If the character is not found in the second string, add nothing and move on to the next character.
Divide the matchscore by the max possiblescore. This returns a decimal value. I read RETURN only returns an integer, so I multiplied the division result by 100.
An example of what I expected is I compare "CAT" to "CART". My expected return is 7/12...0.58. Instead, I get 0. If I compare "CAT" to "CAT", I expect 9/9...1.00. Instead, I get 2.
(Note from 9/17/2014: I appreciate your input. I used what you suggested, and did one more major change, that doesn't affect what I asked about, other than getting the correct final answer is that I got rid of the second While Loop. Instead, I search for #strLetter in #strWord2. If it is found, then, I look to see if it is in the same position in #strWord2 as #strWord1. If it is, then I add 3, if not, I add 1. This sped up the function and made the count accurate.
Here is the code:
CREATE FUNCTION [dbo].[CompareWords]
(#strWord1 VARCHAR(2000), #strWord2 VARCHAR(2000))
RETURNS DECIMAL
AS
BEGIN
SET #strWord1 = UPPER(#strWord1)
SET #strWord2 = UPPER(#strWord2)
DECLARE #intLength INT
IF LEN(#strWord1) >= LEN(#strWord2)
BEGIN
SET #intLength = LEN(#strWord1)
END
ELSE
BEGIN
SET #intLength = LEN(#strWord2)
END
DECLARE #iWordLoop1 INT
DECLARE #iWordLoop2 INT
DECLARE #intWordLoop2 INT
DECLARE #intWordScore INT
DECLARE #intLetterScore INT
SET #intWordScore = 0
SET #intWordLoop2 = Len(#strWord2)
DECLARE #strLetter VARCHAR(1000)
DECLARE #count1 INT
SET #count1 = 0
SET #iWordLoop1 = Len(#strWord1)
WHILE (#count1 < #iWordLoop1)
BEGIN
SET #strLetter = SUBSTRING(#strWord1, #count1+1, 1)
SET #intLetterScore = 0
DECLARE #count2 INT
SET #count2 = 0
SET #iWordLoop2 = Len(#strWord2)
WHILE (#count2 < #iWordLoop2)
BEGIN
If #strLetter = SUBSTRING(#strWord2, #count2+1, 1)
BEGIN
If #iWordLoop1 = #iWordLoop2
BEGIN
SET #intLetterScore = 3
SET #iWordLoop2 = Len(#strWord2)
END
ELSE
BEGIN
SET #intLetterScore = 1
END
END
SET #intWordScore = #intWordScore + #intLetterScore
SET #count2 = (#count2 + 1)
END
SET #count1 = (#count1 + 1)
END
DECLARE #sinScore DEC
SET #sinScore = (#intWordScore / (3 * #intLength)) * 100
RETURN #sinSCore
END;
The most significant changes I made were to
reset the intLetterScore to 0 after it's been used in the intWordScore calculation. Without it being reset, the same value was being used each time the inner loop and the character was not matched.
move the multiplication by 100 into the
brackets in the calculation of sinScore.
As referred to in a previous post, because you are doing integer multiplication, the decimal portion is truncated from the calculation. By growing the wordScore by a factor of 100, it is much more likely to be larger than the length and yield a result which is non-zero.
Multiplying outside the brackets has the multiplies the integer result of the division score by length. If this answer is already zero, then the multiplication result is also zero.
Other changes I made are commented in the code: the variable intWordLoop2 has no effect on the calculation and can be removed; strLetter can be declared as a Char(1) instead of VarChar(1000).
CREATE FUNCTION [dbo].[CompareWords]
(#strWord1 VARCHAR(2000), #strWord2 VARCHAR(2000))
RETURNS DECIMAL
AS
BEGIN
SET #strWord1 = UPPER(#strWord1)
SET #strWord2 = UPPER(#strWord2)
--Set #intLength (maxLength as len of word1 or word2)
DECLARE #intLength INT --maxLength
IF LEN(#strWord1) >= LEN(#strWord2)
BEGIN
SET #intLength = LEN(#strWord1)
END
ELSE
BEGIN
SET #intLength = LEN(#strWord2)
END
DECLARE #iWordLoop1 INT, #iWordLoop2 INT--, #intWordLoop2 INT --This variable doesn't impact the calculation
DECLARE #intWordScore INT
DECLARE #intLetterScore INT
SET #intWordScore = 0
--SET #intWordLoop2 = Len(#strWord2)--this value is not used anywhere else, so removing makes no difference.
--DECLARE #strLetter VARCHAR(1000)
DECLARE #strLetter CHAR(1)--there is no need for 1000 characters since we're only ever assigning a single character to this
DECLARE #count1 INT
SET #count1 = 0
SET #iWordLoop1 = Len(#strWord1)
WHILE (#count1 < #iWordLoop1)
BEGIN
SET #strLetter = SUBSTRING(#strWord1, #count1+1, 1)
SET #intLetterScore = 0
DECLARE #count2 INT
SET #count2 = 0
SET #iWordLoop2 = Len(#strWord2)
WHILE (#count2 < #iWordLoop2)
BEGIN
If #strLetter = SUBSTRING(#strWord2, #count2+1, 1)
BEGIN
If #iWordLoop1 = #iWordLoop2
BEGIN
SET #intLetterScore = 3
SET #iWordLoop2 = Len(#strWord2)
END
ELSE
BEGIN
SET #intLetterScore = 1
END
END
SET #intWordScore = #intWordScore + #intLetterScore
SET #intLetterScore = 0
SET #count2 = (#count2 + 1)
END
SET #count1 = (#count1 + 1)
END
DECLARE #sinScore DEC
SET #sinScore = (#intWordScore*100 / (3 * #intLength))
RETURN #sinSCore
END;
select dbo.comparewords ('Cat','cart')

SQL if else stored procedure

I'm writing a stored procedure and it's working for if but not for else. For if I'm getting the correct ID value but for else it's just giving me null.
SELECT #ID = ID FROM PRODUCTS WHERE SN = #SN
SELECT #Chip_ID = Chip_ID FROM PRODUCTS WHERE SN = #SN
SELECT #Power = Power From Module_Cycle WHERE ChipID = #Chip_ID
SELECT #Test_ID=Test_ID FROM TestEE_Mod WHERE ID=#ID AND #TypeID = TypeID
IF(#Test_ID IS NOT NULL)
BEGIN
IF(#TypeID = '3')
BEGIN
SELECT #Temp_TestID=TestID FROM TempCycle WHERE ChipID = #Chip_ID AND #Power = 'false'
BEGIN
UPDATE TestEE_Mod SET Temp_TestID = #Temp_TestID WHERE ID = #ID AND TypeID = #TypeID
END
END
ELSE
BEGIN
SELECT #Temp_TestID=TestID FROM TempCycle WHERE ChipID = #Chip_ID AND #Power = 'true'
BEGIN
UPDATE TestEE_Mod SET Temp_TestID = #Temp_TestID WHERE ID = #ID AND TypeID = #TypeID
END
END
END
Most likely the issue lies in the #Power variable. In your two SELECT statements, the only difference is that one includes #Power = 'false' in the WHERE clause, while the other includes #Power = 'true'.
Since #Power is a variable, not an actual column in your TempCycle table, I'm guessing you actually meant to filter by Power = #Power in both of them.

Code inside SQL Cursor will only execute first FETCH

I have a SQL Cursor which I'm having issues with. When I remove the IF #debug = 1 statement from inside the cursor, only the first record from the FETCH will get updated but if I leave the IF #debug = 1 all the required records are updated. Any idea as to why this is happening, I know most likely something is wrong with my Cursor? Code is below:
DECLARE Verify_Shipment_Cur CURSOR LOCAL FAST_FORWARD READ_ONLY FOR
SELECT DISTINCT lpd_shipment_id, lpd_po_number, lpd_customer_id, lpd_sku, lpd_lottable01, lpd_lottable02, lpd_lottable03, lpd_putaway_zone, lpd_pdt
FROM PO_DETAIL01(NOLOCK)
WHERE lpd_shipment_id = #i_SHIPMENT_ID
AND lpd_po_number = #i_POKEY
AND lpd_customer_id = #i_CUSTOMER_ID
AND lpd_status = #AvailableStatus
OPEN Verify_Shipment_Cur
WHILE #ShipmentSKUCount >= #ShipmentSKUCountCur
BEGIN
FETCH NEXT FROM Verify_Shipment_Cur INTO #ShipmentID, #POKey, #CustomerID, #SKU, #Lottable01, #Lottable02, #Lottable03, #PutawayZone, #PDT
IF EXISTS(SELECT 1 FROM PO_DETAIL(NOLOCK) WHERE pd_asn_number = #i_SHIPMENT_ID AND pd_po_number = #i_POKEY
AND pd_sku = #SKU AND pd_type = #ShmtType AND pd_ordered_qty <> pd_received_qty)
BEGIN
UPDATE PO_DETAIL
SET pd_adjusted_qty = pd_ordered_qty - pd_received_qty
WHERE pd_asn_number = #i_SHIPMENT_ID
AND pd_po_number = #i_POKEY
AND pd_sku = #SKU
AND pd_type = #ShmtType
END
UPDATE PO_DETAIL
SET pd_lottable01 = #Lottable01
, pd_lottable02 = #Lottable02
, pd_lottable03 = #Lottable03
, pd_lottable04 = ''
, pd_lottable05 = #Date
, pd_putaway_zone = #PutawayZone
, pd_pdt = #PDT
, pd_status = #VerifiedStatus
WHERE pd_asn_number = #i_SHIPMENT_ID
AND pd_po_number = #i_POKEY
AND pd_sku = #SKU
AND pd_type = #ShmtType
UPDATE PO_DETAIL01
SET lpd_status = #VerifiedStatus
WHERE lpd_shipment_id = #i_SHIPMENT_ID
AND lpd_po_number = #i_POKEY
AND lpd_customer_id = #i_CUSTOMER_ID
AND lpd_status = #AvailableStatus
IF #debug = 1
BEGIN
SELECT #ShipmentSKUCount AS SKUCOUNT
, #ShipmentSKUCountCur AS SKUCOUNTCUR
, #SKU AS SKU
, #ShipmentID AS SHIPMENT
, #POKey AS POKEY
END
SET #ShipmentSKUCountCur = #ShipmentSKUCountCur + 1
END
CLOSE Verify_Shipment_Cur
DEALLOCATE Verify_Shipment_Cur
It looked ok to me but i obviously dont have your data to assist. Can I recommend putting a few print statements in various parts of your cursor. That way you can see how the code is actually flowing. It doesnt help but thats what I would do.
Please, can you try to define explicilty both variables: set #ShipmentSKUCount=[initial value],set #ShipmentSKUCountCur=[initial or constant value] and see what will happen?
Also, I found there is no checking for a ##FETCH_STATUS. It may also result into reading same row twice or more.
Please, give a feedback.

Replacing a string in a text field

I have a column in my database table which has lows of text and lows of rows. In the text, a url needs to be changed for every row. In each row the url can exist more than once.
Can I use the replace function to change all the urls in the text field in my database table without affecting the rest of the text in that same column?
Thanks
Use REPLACE()
UPDATE table SET text = REPLACE(text, 'from', 'to')
Make precise from: like with http://url_from.com/ to http://url_to.com/
Based on article posted at https://web.archive.org/web/20150521050102/http://sqlserver2000.databases.aspfaq.com:80/how-do-i-handle-replace-within-an-ntext-column-in-sql-server.html
I needed to write a find and replace for CHAR(146) ` in a text field. Above article for fort nText and the same solution for text worked with nText with the following changes:
- VARCHAR(32) from nVARCHAR(32)
- use #lenOldString = DATALENGTH(#oldString) instead of SET #lenOldString = DATALENGTH(#oldString)/2.
DECLARE
#TextPointer BINARY(16),
#TextIndex INT,
#oldString VARCHAR(32),
#newString VARCHAR(32),
#lenOldString INT,
#currentDataID INT;
SET #oldString = '’';
SET #newString = '''';
IF CHARINDEX(#oldString, #newString) > 0
BEGIN
PRINT 'Quitting to avoid infinite loop.';
END
ELSE
BEGIN
--Need the for nText fields
--SET #lenOldString = DATALENGTH(#oldString)/2
--Use this for text fields
SET #lenOldString = DATALENGTH(#oldString)
DECLARE irows CURSOR
LOCAL FORWARD_ONLY STATIC READ_ONLY FOR
SELECT
DataID
FROM
dbo.tbData
WHERE
PATINDEX('%'+#oldString+'%', TextData) > 0;
OPEN irows;
FETCH NEXT FROM irows INTO #currentDataID;
WHILE (##FETCH_STATUS = 0)
BEGIN
SELECT
#TextPointer = TEXTPTR(TextData),
#TextIndex = PATINDEX('%'+#oldString+'%', TextData)
FROM
dbo.tbData
WHERE
DataID = #currentDataID;
SELECT #TextPointer, #TextIndex
WHILE
(
SELECT
PATINDEX('%'+#oldString+'%', TextData)
FROM
dbo.tbData
WHERE
DataID = #currentDataID
) > 0
BEGIN
SELECT
#TextIndex = PATINDEX('%'+#oldString+'%', TextData)-1
FROM
dbo.tbData
WHERE
DataID = #currentDataID;
UPDATETEXT dbo.tbData.TextData #TextPointer #TextIndex #lenOldString #newString;
END
FETCH NEXT FROM irows INTO #currentDataID;
END
CLOSE irows;
DEALLOCATE irows;
END