I want to sum each character of an integer in SQL
For instance. I have 16273481 as INT
But now (Without to complicated methods) sum
1 + 6 + 2 + 7 + 3 + 4 + 8 + 1 = 32
DECLARE #someInt INT = 16273481
-- you could put this all into a function
-- and then it would be reusable...
--
-- like... SELECT SumOfIndividualIntegers(16273481)
DECLARE #count INT = LEN(#someInt),
#counter INT = 1
DECLARE #Sum INT = 0
WHILE #counter <= #count
BEGIN
SELECT #sum += CAST(SUBSTRING(CAST(#someInt AS VARCHAR), #counter, 1) AS int)
SELECT #counter += 1
END
SELECT #sum --32
-- and then you would RETURN #sum instead
Would using the remainder operator be suitable for your situation with a loop?
Pseuodo code:
x = 16273481;
sum = 0;
Loop:
sum = sum + (x % 10);
x = (x / 10);
Something along those lines?
Related
I found this code at this website and is working well in SQL SERVER
CREATE FUNCTION [dbo].[CalculaDigitoRut]
(
#rut int
)
RETURNS char(1)
AS
BEGIN
DECLARE #digito int
DECLARE #contador int
DECLARE #multiplo int
DECLARE #acumulador int
DECLARE #ret char
set #contador = 2
set #acumulador = 0
while (#rut <> 0)
begin
set #multiplo = (#Rut % 10) * #contador
set #acumulador = #acumulador + #multiplo
set #rut = #rut / 10
set #contador = #contador + 1
if (#contador = 8)
set #contador = 2
end
set #digito = 11 - (#acumulador % 11)
if (#digito = 10)
return ('K')
if (#digito = 11)
return ('0')
return (#digito)
END
Expected result
RUT -- validation_digit
10214564 K
3781561 6
3433444 7
3066256 3
I tried to adapt it to the MariaDB (10.3.30-MariaDB) syntax and after a few tries there weren't syntax erros but the function isn't returning the expected result.
Heres the new code for MariaDB
CREATE FUNCTION Calculate_national_id_verifier (rut INT)
RETURNS CHAR(1)
BEGIN
DECLARE digito INT;
DECLARE contador INT;
DECLARE multiplo INT;
DECLARE acumulador INT;
DECLARE ret CHAR;
SET contador = 2;
SET acumulador = 0;
WHILE rut <> 0 DO
SET multiplo = (rut % 10) * contador;
SET acumulador = acumulador + multiplo;
SET rut = rut / 10;
SET contador = contador + 1; -- 3
IF (contador = 8) THEN
SET contador = 2;
END IF;
END WHILE;
SET digito = 11 - (acumulador % 11);
IF (digito = 10) THEN
RETURN ('K');
ELSEIF (digito = 11) THEN
RETURN ('0');
ELSE
RETURN (digito);
END IF;
END;
This problem seems very dumb, I've been comparing it for hours and I can't find where is the problem and why there is a difference between both functions.
I'm using DBeaver 21.3.5 as a client to run the queries.
Here are the actual results
RUT -- validation_digit
10214564 6
3781561 K
3433444 7
3066256 5
This is my firts time asking something so sorry if I made a mistake. I couldn't find the answer.
My requirement is to build a rhombus using ‘X’ symbol based on below conditions.
If the length is 2, then it should display
X
XXX
X
If the length is 3, then it should display
X
XXX
XXXXX
XXX
X
If the length is 5, then it should display 5 lines above and 5 lines below with spaces.
I tried writing code, but I’m unable to get lower half part and spaces. Can someone help me here?
declare #X nvarchar(1) = 'X'
declare #chars int = 5
declare #W nvarchar(100) = 1
while (#chars > 0)
begin
print replicate(#X,#W)
set #chars = #chars - 1
set #W = #W + 2
end
Output:
X
XXX
XXXXX
XXXXXXX
XXXXXXXXX
You can get spaces using SPACE function. I have used your approach and added some code which returns lower part as well.
DECLARE #X NVARCHAR(1) = 'X'
DECLARE #chars INT = 5
DECLARE #LowerPart INT = #chars
DECLARE #W NVARCHAR(100) = 1
WHILE (#chars > 0)
BEGIN
PRINT SPACE(#chars)+REPLICATE(#X,#W)
SET #chars = #chars - 1
SET #W = #W + 2
END
WHILE (#chars <= #LowerPart)
BEGIN
PRINT SPACE(#chars)+REPLICATE(#X,#W)
SET #chars = #chars + 1
SET #W = #W - 2
END
I've considered your example rhombus for 3. So, for a given length 5, there will be only 4 lines above and 4 lines below with my solution.
declare #displayCharacter nvarchar(1) = 'X'
declare #rhombusLength int = 5
declare #repetition int = 1
declare #topRow int = 1
declare #bottomRow int = 1
--Top rows
while (#rhombusLength > #topRow)
begin
print REPLICATE(' ', #rhombusLength - #topRow) + REPLICATE(#displayCharacter, #repetition)
set #topRow = #topRow + 1
set #repetition = #repetition + 2
end
--Middle row
print REPLICATE(#displayCharacter, #repetition)
--Bottom rows
while (#rhombusLength > #bottomRow)
begin
set #repetition = #repetition - 2
print REPLICATE(' ', #bottomRow) + REPLICATE(#displayCharacter, #repetition)
set #bottomRow = #bottomRow + 1
end
I want to find a credit card numeric value in a sql string.
for example;
DECLARE #value1 NVARCHAR(MAX) = 'The payment is the place 1234567812345678'
DECLARE #value2 NVARCHAR(MAX) = 'The payment is the place 123456aa7812345678'
DECLARE #value3 NVARCHAR(MAX) = 'The payment1234567812345678is the place'
The result should be :
#value1Result 1234567812345678
#value2Result NULL
#value3Result 1234567812345678
16 digits must be together without space.
How to do this in a sql script or a function?
edit :
if I want to find these 2 credit card value.
#value4 = 'card 1 is : 4034349183539301 and the other one is 3456123485697865'
how should I implement the scripts?
You can use PathIndex as
PATINDEX('%[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]%', yourStr)
if the result is 0 then it doesnt containg 16 digits other was it contains.
It can be used withing a Where statement or Select statement based on your needs
You can write as:
SELECT case when Len(LEFT(subsrt, PATINDEX('%[^0-9]%', subsrt + 't') - 1)) = 16
then LEFT(subsrt, PATINDEX('%[^0-9]%', subsrt + 't') - 1)
else ''
end
FROM (
SELECT subsrt = SUBSTRING(string, pos, LEN(string))
FROM (
SELECT string, pos = PATINDEX('%[0-9]%', string)
FROM table1
) d
) t
Demo
DECLARE #value1 NVARCHAR(MAX) = 'card 1 is : 4034349183539301 and the other one is 3456123485697865'
DECLARE #Lenght INT
,#Count INT
,#Candidate CHAR
,#cNum INT
,#result VARCHAR(16)
SELECT #Count = 1
SELECT #cNum = 0
SELECT #result = ''
SELECT #Lenght = LEN(#value1)
WHILE #Count <= #Lenght
BEGIN
SELECT #Candidate = SUBSTRING(#value1, #Count, 1)
IF #Candidate != ' '
AND ISNUMERIC(#Candidate) = 1
BEGIN
SET #cNum = #cNum + 1
SET #result = #result + #Candidate
END
ELSE
BEGIN
SET #cNum = 1
SET #result = ''
END
IF #cNum > 16
BEGIN
SELECT #result 'Credit Number'
END
SET #Count = #Count + 1
END
There you go kind sir.
DECLARE
#value3 NVARCHAR(MAX) = 'The payment1234567812345678is the place',
#MaxCount int,
#Count int,
#Numbers NVARCHAR(100)
SELECT #Count = 1
SELECT #Numbers = ''
SELECT #MaxCount = LEN(#value3)
WHILE #Count <= #MaxCount
BEGIN
IF (UNICODE(SUBSTRING(#value3,#Count,1)) >= 48 AND UNICODE(SUBSTRING(#value3,#Count,1)) <=57)
SELECT #Numbers = #Numbers + SUBSTRING(#value3,#Count,1)
SELECT #Count = #Count + 1
END
PRINT #Numbers
You can make this as a function if you are planning to use it a lot.
I need to find how many true bit exists in my binary value.
example:
input: 0001101 output:3
input: 1111001 output:5
While both answers work, both have issues. A loop is not optimal and destructs the value. Both solutions can not be used in a select statement.
Possible better solution is by masking together as follows
select #counter = 0
+ case when #BinaryVariable2 & 1 = 1 then 1 else 0 end
+ case when #BinaryVariable2 & 2 = 2 then 1 else 0 end
+ case when #BinaryVariable2 & 4 = 4 then 1 else 0 end
+ case when #BinaryVariable2 & 8 = 8 then 1 else 0 end
+ case when #BinaryVariable2 & 16 = 16 then 1 else 0 end
+ case when #BinaryVariable2 & 32 = 32 then 1 else 0 end
+ case when #BinaryVariable2 & 64 = 64 then 1 else 0 end
+ case when #BinaryVariable2 & 128 = 128 then 1 else 0 end
+ case when #BinaryVariable2 & 256 = 256 then 1 else 0 end
+ case when #BinaryVariable2 & 512 = 512 then 1 else 0 end
This can be used in a select and update statement. It is also an order of magnitude faster. (on my server about 50 times)
To help you might want to use the following generator code
declare #x int = 1, #c int = 0
print ' #counter = 0 ' /*CHANGE field/parameter name */
while #c < 10 /* change to how many bits you want to see */
begin
print ' + case when #BinaryVariable2 & ' + cast(#x as varchar) + ' = ' + cast(#x as varchar) + ' then 1 else 0 end ' /* CHANGE the variable/field name */
select #x *=2, #c +=1
end
Also as further note: if you use a bigint or go beyond 32 bits it is necessary to cast like follows
print ' + case when #Missing & cast(' + cast(#x as varchar) + ' as bigint) = ' + cast(#x as varchar) + ' then 1 else 0 end '
Enjoy
DECLARE #BinaryVariable2 VARBINARY(10);
SET #BinaryVariable2 = 60; -- binary value is 111100
DECLARE #counter int = 0
WHILE #BinaryVariable2 > 0
SELECT #counter +=#BinaryVariable2 % 2, #BinaryVariable2 /= 2
SELECT #counter
Result:
4
I've left various debug selects in.
begin
declare #bin as varbinary(20);
declare #bitsSet as int;
set #bitsSet = 0;
set #bin = convert(varbinary(20), 876876876876);
declare #i as int;
set #i = 0
select LEN(#bin), 'Len';
while #i < LEN(#bin)
begin
declare #bit as varbinary(1);
set #bit = SUBSTRING(#bin, #i, 1);
select #bit, 'Bit';
declare #power as int
set #power = 0;
while #power < 8
begin
declare #powerOf2 as int;
set #powerOf2 = POWER(2, #power);
if #powerOf2 <> 0
set #bitsSet = #bitsSet + (#bit & #powerOf2) / #powerOf2; -- edited to add the divisor
select #power, #powerOf2;
set #power = #power + 1;
end;
select #bitsSet;
set #i = #i + 1;
end;
select #bitsSet, 'End'
end;
Cheers -
You can handle an arbitrary length binary value by using a recursive CTE to split the data into a table of 1-byte values and counting all of the bits that are true in each byte of that table...
DECLARE #data Varbinary(MAX) = Convert(Varbinary(MAX), N'We can count bits of very large varbinary values without a loop or number table if you like...');
WITH each ( byte, pos ) AS (
SELECT Substring(#data, Len(#data), 1), Len(#data)-1 WHERE Len(#data) > 0
UNION ALL
SELECT Substring(#data, pos, 1), pos-1 FROM each WHERE pos > 0
)
SELECT Count(*) AS [True Bits]
FROM each
CROSS JOIN (VALUES (1),(2),(4),(8), (16),(32),(64),(128)) [bit](flag)
WHERE each.byte & [bit].flag = [bit].flag
OPTION (MAXRECURSION 0);
From SQL Server 2022 you can just use SELECT BIT_COUNT(input)
expression_value can be
Any integer or binary expression that isn't a large object (LOB).
For integer expressions the result can depend on the datatype. e.g. -1 as smallint has a binary representation of 1111111111111111 (two's complement) and will have more bits set for int datatype.
I just had to scour the internet for this code yet again so I figured I would put it here so I can find it a little faster the next time and hopefully you found it a little faster too :)
Check this.
The code below can check digit in all GTIN's (EAN8, EAN13, EAN14, UPC/A, UPC/E)
CREATE FUNCTION [dbo].[check_digit]
(
#GTIN VARCHAR(14)
)
RETURNS TINYINT
AS
BEGIN
DECLARE #Index TINYINT,
#Multiplier TINYINT,
#Sum TINYINT,
#checksum TINYINT,
#result TINYINT,
#GTIN_strip VARCHAR(13)
SELECT #GTIN_strip = SUBSTRING(#GTIN,1,LEN(#GTIN)-1);
SELECT #Index = LEN(#GTIN_strip),
#Multiplier = 3,
#Sum = 0
WHILE #Index > 0
SELECT #Sum = #Sum + #Multiplier * CAST(SUBSTRING(#GTIN_strip, #Index, 1) AS TINYINT),
#Multiplier = 4 - #Multiplier,
#Index = #Index - 1
SELECT #checksum = CASE #Sum % 10
WHEN 0 THEN '0'
ELSE CAST(10 - #Sum % 10 AS CHAR(1))
END
IF (SUBSTRING(#GTIN,LEN(#GTIN),1) = #checksum)
RETURN 1; /*true*/
RETURN 0; /*false*/
END
CREATE FUNCTION [dbo].[fn_EAN13CheckDigit] (#Barcode nvarchar(12))
RETURNS nvarchar(13)
AS
BEGIN
DECLARE #SUM int , #COUNTER int, #RETURN varchar(13), #Val1 int, #Val2 int
SET #COUNTER = 1 SET #SUM = 0
WHILE #Counter < 13
BEGIN
SET #VAL1 = SUBSTRING(#Barcode,#counter,1) * 1
SET #VAL2 = SUBSTRING(#Barcode,#counter + 1,1) * 3
SET #SUM = #VAL1 + #SUM
SET #SUM = #VAL2 + #SUM
SET #Counter = #Counter + 2;
END
SET #SUM=(10-(#SUM%10))%10
SET #Return = #BARCODE + CONVERT(varchar,((#SUM)))
RETURN #Return
END
And here's a MySQL implementation as well.
Note it requires a 13 digit UPC/EAN13 as input, so you should LPAD your input as required.
drop function if exists barcodify;
delimiter //
at the last digit.
create function barcodify(upc varchar(15))
returns varchar(15)
sql security invoker
begin
declare i, r, odd, even,result int;
set odd=0;
set even =0;
set i = length(upc);
while i > 0 do
set r = substring(upc, i, 1) ;
if(i % 2 >0) then set odd = odd + r;
else set even = even + r;
end if;
set i = i - 1;
end while;
set result = (3*odd)+even;
if result % 10 =0 then return 0;
else return (10 - (result %10));
end if;
end //
delimiter ;
Here's my implementation of a function in Oracle.
CREATE OR REPLACE FUNCTION GenerateCheckDigit(pUPC IN VARCHAR2) RETURN INT
IS
vCheckDigit INT;
BEGIN
WITH barcodeData AS
(
SELECT pUPC barcode FROM dual
)
SELECT
10-REPLACE(MOD(SUM(SUBSTR(barcode, -LEVEL, 1) * DECODE(MOD(LEVEL-1, 2), 1, 1, 3)),10),0,10) INTO vCheckDigit
FROM barcodeData
CONNECT BY LEVEL <= LENGTH(barcode);
RETURN vCheckDigit;
END;
To calculate the last digit.
https://segovoni.medium.com/sql-server-function-to-calculate-gs1-barcode-check-digit-d55b478ff645
CREATE FUNCTION dbo.udf_GetGS1EAN13CheckDigit
(
#ACode AS VARCHAR(12)
)
RETURNS SMALLINT
AS BEGIN
/*
Author: Sergio Govoni
Notes: Calculate the check-digit of a GS1 EAN13 code
Version: 1.0
*/
DECLARE
#tmpCode AS VARCHAR(12)
,#tmpMulSup AS VARCHAR(8000)
,#tmp AS VARCHAR(8000)
,#i AS INT
,#j AS INT
,#z AS INT
,#SumDEven AS INT
,#SumDOdd AS INT
,#List AS VARCHAR(8000)
,#tmpList AS VARCHAR(8000)
,#CheckSum AS SMALLINT
SET #SumDEven = 0
SET #SumDOdd = 0
SET #List = ''
SET #tmpList = ''
SET #tmp = ''
SET #tmpCode = #ACode
/* 0. List builder */
SET #j = LEN(#tmpCode) + 1
SET #i = 1
WHILE (#i <= LEN(#tmpCode)) BEGIN SET #List = #List + '|' + LTRIM(RTRIM(STR(#j))) + ';' + SUBSTRING(#tmpCode, #i, 1) SET #j = (#j - 1) SET #i = (#i + 1) END /* 1. Add up the digits in even position */ SET #i = 1 SET #tmpList = #List WHILE (CHARINDEX('|', #tmpList) > 0)
BEGIN
SET #j = CHARINDEX('|', #tmpList)
SET #z = CHARINDEX(';', #tmpList)
IF (CAST(SUBSTRING(#tmpList, (#j + 1), (#z - (#j + 1))) AS INTEGER) % 2) = 0
BEGIN
SET #SumDEven = #SumDEven + CAST(SUBSTRING(#tmpList, (#z + 1), 1) AS INTEGER)
END
SET #tmpList = SUBSTRING(#tmpList, (#z + 2), LEN(#tmpList))
END
/* 2. Multiply the result of the previous step (the first step) to 3 (three) */
SET #SumDEven = (#SumDEven * 3)
/* 3. Add up the digits in the odd positions */
SET #i = 1
SET #tmpList = #List
WHILE (CHARINDEX('|', #tmpList) > 0)
BEGIN
SET #j = CHARINDEX('|', #tmpList)
SET #z = CHARINDEX(';', #tmpList)
IF (CAST(SUBSTRING(#tmpList, (#j + 1), (#z - (#j + 1))) AS INTEGER) % 2) <> 0
BEGIN
SET #SumDOdd = #SumDOdd + CAST(SUBSTRING(#tmpList, (#z + 1), 1) AS INTEGER)
END
SET #tmpList = SUBSTRING(#tmpList, (#z + 2), LEN(#tmpList))
END
/* 4. Add up the results obtained in steps two and three */
SET #CheckSum = (#SumDEven + #SumDOdd)
/* 5. Subtract the upper multiple of 10 from the result obtained in step four */
IF ((#CheckSum % 10) = 0)
BEGIN
/* If the result of the four step is a multiple of Ten (10), like
Twenty, Thirty, Forty and so on,
the check-digit will be equal to zero, otherwise the check-digit will be
the result of the fifth step
*/
SET #CheckSum = 0
END
ELSE BEGIN
SET #tmpMulSup = LTRIM(RTRIM(STR(#CheckSum)))
SET #i = 0
WHILE #i <= (LEN(#tmpMulSup) - 1)
BEGIN
SET #tmp = #tmp + SUBSTRING(#tmpMulSup, #i, 1)
IF (#i = LEN(#tmpMulSup) - 1)
BEGIN
SET #tmp = LTRIM(RTRIM(STR(CAST(#tmp AS INTEGER) + 1)))
SET #tmp = #tmp + '0'
END
SET #i = (#i + 1)
END
SET #CheckSum = CAST(#tmp AS INTEGER) - #CheckSum
END
RETURN #CheckSum
END;
CREATE FUNCTION sfn_ean_chkdigit(#barcode varchar(20))
RETURNS CHAR(1)
AS
BEGIN
DECLARE #chk_digit int, #chk int
DECLARE #num TABLE (num int)
IF LEN(#barcode) NOT IN (7, 12) RETURN NULL
INSERT INTO #num
SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL
SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL
SELECT 9 UNION ALL SELECT 10 UNION ALL SELECT 11 UNION ALL SELECT 12
SELECT #chk_digit = SUM(CONVERT(int, SUBSTRING(#barcode, LEN(#barcode) - num + 1, 1)) * CASE WHEN num % 2 = 1 THEN 3 ELSE 1 END)
FROM #num
WHERE num <= LEN(#barcode)
SELECT #chk_digit = (10 - (#chk_digit % 10)) % 10
RETURN CHAR(ASCII('0') + #chk_digit)
END
Num unico script
select lpad('123456789012',12,'0') || ( (r+1)*10 - soma )%10
from (select sum(v::int * case when i%2=0 then 3 else 1 end) soma,
round(sum(v::int * case when i%2=0 then 3 else 1 end)/10.0) r
from unnest(string_to_array(lpad('123456789012',12,'0'),null)) with ordinality d(v,i)
) a