I have this function for calculating crc16, but it is in MySQL, can someone help me convert to SQL Server?
I looked in several places, but I only find the crc32, this does not work for the generation of the PIX QRcode.
Below is an example of the function I have.
CREATE DEFINER=`root`#`%` FUNCTION `CRC16`( _STRING VARCHAR(25)) RETURNS varchar(50) CHARSET utf8mb4
DETERMINISTIC
BEGIN
DECLARE _myCRC integer;
DECLARE _ord INTEGER;
DECLARE _n Integer;
DECLARE _m Integer;
DECLARE _strlend Integer;
SET _myCRC := x'FFFF';
SET _n := 1;
SET _strlend := LENGTH(_STRING) ;
loop_crc: LOOP
IF _n > _strlend THEN
LEAVE loop_crc;
END IF;
SET _ord := ORD(SUBSTRING(_STRING, _n, 1) );
SET _myCRC := _myCRC ^ _ord;
SET _m := 0;
loop_bit: LOOP
IF _m = 8 THEN
LEAVE loop_bit;
END IF;
IF (_myCRC & x'0001') = x'0001' THEN
SET _myCRC := (_myCRC >> 1) ^ x'A001';
ELSE
SET _myCRC := _myCRC >> 1;
END IF;
SET _m := _m + 1;
END LOOP;
SET _n := _n + 1;
END LOOP;
return HEX(_myCRC);
END//
Converting this function to Transact-SQL should be straightforward. In general:
Get rid of the definer, the backticks and DETERMINISTIC in the function header.
For loops, use WHILE condition BEGIN ... END. Notice a 'while' condition is the negation of a 'leave' condition.
Variable and parameter names must be prefixed with #.
Use decimal literals. (Use a calculator to convert the hexadecimals.)
Use = instead of := for variable assignment.
Replace >> 1 with / 2.
Replace LENGTH with LEN.
Replace ORD with ASCII or UNICODE.
Replace HEX(...) with CONVERT(char(4), CONVERT(binary(2), ...), 2), as suggested here.
Related
This code is from the proposed solution:
https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:9541646100346616701
My query is 'select * from table'
The second column is a DATE and this routine writes it as appears in my IDE session ('DD-MON-YY');
How can I report the values in DATE columns to 'YYYY-MM-DD'?
procedure clob_maker(p_query varchar2) is
l_theCursor integer default dbms_sql.open_cursor;
l_columnValue varchar2(4000);
l_status integer;
l_descTbl dbms_sql.desc_tab;
l_colCnt number;
n number := 0;
l_data clob;
begin
dbms_sql.parse( l_theCursor, p_query, dbms_sql.native );
dbms_sql.describe_columns( l_theCursor, l_colCnt, l_descTbl );
for i in 1 .. l_colCnt loop
dbms_sql.define_column(l_theCursor, i, l_columnValue, 4000);
end loop;
l_status := dbms_sql.execute(l_theCursor);
while ( dbms_sql.fetch_rows(l_theCursor) > 0 ) loop
for i in 1 .. l_colCnt loop
dbms_sql.column_value( l_theCursor, i, l_columnValue );
--dbms_output.put_line(l_columnValue); --this puts every column on a separate line
l_data := l_data || l_columnValue ||',';
end loop;
dbms_output.put_line(l_data);
n := n + 1;
end loop;
--dbms_output.put_line(l_data);
end clob_maker;
clob_maker('select * from mlb_catcher_birthdays fetch first 10 rows only');
The default format in which dates are represented is controlled by NLS parameter ns_date_format. You can just change this parameter at session level:
alter session set nls_date_format = 'YYYY-MM-DD';
You could also use TO_CHAR(), with the same format specifier as second argument - but this does not fit very well to your use case, since you would then need to check the datatype of each column before printing its value.
Write a PL/SQL block to display the multiples of a Given Number
without including multiples of 10 for a given range (Start Value and
End Value), using GOTO.
This is my try, but I couldn't place the goto statement in correct place:
declare
start_value number; end_value number; n number;
result;
begin
start_value:=&start_value;
end_value:=&end_value;
n :=&n;
for x in start_value..end_value loop
<<calc>>
if((x mod n)=0 and (x mod 10)!=0) then
dbms_output.put_line(x);
end if;
goto calc;
end loop;
end;
First off, this is a really bad assignment. Teaching you to use GOTO's is like teaching a naval architect to build ships without watertight bulkheads - it's Just Wrong. (sigh) But, oh well...
DECLARE
start_value NUMBER;
end_value NUMBER;
n NUMBER;
BEGIN
start_value := &start_value;
end_value := &end_value;
n := &n;
FOR x IN start_value..end_value LOOP
IF MOD(x, 10) = 0 THEN
GOTO skip_calc;
END IF;
DBMS_OUTPUT.PUT_LINE(n * x);
<<skip_calc>>
NULL;
END LOOP;
END;
The way this would normally be written is:
DECLARE
start_value NUMBER;
end_value NUMBER;
n NUMBER;
BEGIN
start_value := &start_value;
end_value := &end_value;
n := &n;
FOR x IN start_value..end_value LOOP
IF MOD(x, 10) <> 0 THEN
DBMS_OUTPUT.PUT_LINE(n * x);
END IF;
END LOOP;
END;
Shorter and easier to read.
I have Written Following Code :
DECLARE
n integer;
s integer;
d integer;
BEGIN
n:=&n;
while n!=0 loop
d:=mod(n,10);
s:=s+d;
n:=n/10;
end loop;
dbms_output.put_line('output :'||s);
end;
/
Input Value : 1234
Output Value : 4321 (Perfect What I want)
But When I Tried with following (I found incorrect output)
Input value : 5678
Output : 88761
Expected Output : 8765
The code you provided didn't work for me but the error is because it is rounding this operation:
n:=n/10;
If you change it to this it should work:
n:=floor(n/10); OR n:=trunc(n/10);
However it's not working for me, I needed to add something to s:=s+d. Here's my code:
DECLARE
n INTEGER;
s INTEGER:= 0;
d INTEGER;
i INTEGER:= 0;
BEGIN
n:= 5678;
i:= length(to_char(n))-1;
WHILE n!=0 LOOP
d:=mod(n,10);
s:=s+(d*power(10,i));
i := i - 1;
n:= trunc(n/10);
END LOOP;
dbms_output.put_line('output :'||s);
END;
/
You should initialize s and a few more changes.
DECLARE
n INTEGER;
s integer := 0;
d integer;
BEGIN
n:=&n;
while n!=0 loop
d:=mod(n,10);
s:=(s*10)+d;
n:=floor(n/10);
end loop;
dbms_output.put_line('output :'||s);
END;
/
I am new to PL/SQL... In Varray how can i get multiple value from IN parameter..... else Is there another ways to get the values...
I want to interate the values through VArray... if any other options then its fine..
coding:
CREATE OR REPLACE
PROCEDURE dynamic_query_build(
vr_plan_sku_id IN VARCHAR2 )
IS
type plan_sku_id_array IS VARRAY(999) OF VARCHAR2(5000);
plan_sku_id plan_sku_id_array;
total INTEGER;
vrx_plan_sku_id VARCHAR2(3000);
BEGIN
vrx_plan_sku_id:= REPLACE(vr_plan_sku_id,',',chr(39)||','||chr(39));
plan_sku_id := plan_sku_id_array(chr(39)||vrx_plan_sku_id||chr(39));
total := plan_sku_id.count;
FOR i IN 1 .. total
LOOP
dbms_output.put_line(plan_sku_id(i));
END LOOP;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);
END dynamic_query_build;
Execution:
set serveroutput on;
declare
vr_plan_sku_id varchar2(200) := '5863314,5863315';
BEGIN
dynamic_query_build(vr_plan_sku_id);
END;
/
My Output:
anonymous block completed
'5863314','5863315'
Expected output:
5863314
5863315
now it is considering as single value....
I created anonymous block with procedure dynamic_query_build. Added there code, that will split VARCHAR2 variable into varray.
I think, the key to your question is this line - plan_sku_id.EXTEND();
You can extend varray dynamically, but only till it reaches defined maximum (in your case - 999).
DECLARE
vr_plan_sku_id varchar2(200) := '5863314,5863315';
PROCEDURE dynamic_query_build(
vr_plan_sku_id IN VARCHAR2 )
IS
type plan_sku_id_array IS VARRAY(999) OF VARCHAR2(5000);
plan_sku_id plan_sku_id_array;
total INTEGER;
position PLS_INTEGER := 0;
last_position PLS_INTEGER := 1;
tmp VARCHAR2(5000);
counter PLS_INTEGER := 1;
BEGIN
plan_sku_id := plan_sku_id_array();
LOOP
position := INSTR(vr_plan_sku_id, ',', last_position);
IF position > 0 THEN
tmp := SUBSTR(vr_plan_sku_id, last_position, position - last_position);
last_position := position + 1;
ELSE
tmp := SUBSTR(vr_plan_sku_id, last_position);
END IF;
plan_sku_id.EXTEND();
plan_sku_id(counter) := tmp;
counter := counter + 1;
EXIT WHEN position = 0 OR counter > 10;
END LOOP;
total := plan_sku_id.count;
FOR i IN 1 .. total
LOOP
dbms_output.put_line(plan_sku_id(i));
END LOOP;
EXCEPTION
WHEN OTHERS THEN
raise_application_error(-20001,'An error was encountered - '||SQLCODE||' -ERROR- '||SQLERRM);
END dynamic_query_build;
BEGIN
dynamic_query_build(vr_plan_sku_id);
END;
/
Put a replace in the dbms_output statement this will eliminate the quotes from the string
....
dbms_output.put_line replace (replace (plan_sku_id(i), '''' ))',',chr(10);
.....
I have SQL strings that my users write. They look like:
SELECT Name, Age from Users WHERE Name LIKE '%a%' AND {UsersWhere}
On the oracle server side when such an SQL is to be executed I want to replace the {tags} first. The replacements for the {tags} will be valid SQL sub strings I am holding in a table. Pre-manufactered sub sqls. So the treated string will be valid SQL.
Is there some fancy build-in Oracle function to make this happen?
Thanks for a hint!
I have written a small function for anyone interested:
CREATE OR REPLACE FUNCTION SA.REPLACE_VARIABLES (p_sql IN VARCHAR2)
RETURN VARCHAR2
IS
vs_return VARCHAR2 (4000);
-- Deklarationen
vs_sql VARCHAR2(4000);
vs_substring VARCHAR2(4000);
vs_variable VARCHAR2(200);
vs_variable_content VARCHAR2(4000);
BEGIN
vs_sql := p_sql;
IF INSTR(p_sql, '{') > 0 THEN
vs_substring := vs_sql;
WHILE LENGTH(vs_substring) > 0 LOOP
IF INSTR(vs_substring, '{') <> 0
THEN
vs_variable := SUBSTR(vs_substring, INSTR(vs_substring, '{'), INSTR(vs_substring, '}') - INSTR(vs_substring, '{') + 1);
-- Do whatever you want with the variable
--vs_sql := REPLACE(vs_sql, vs_variable, vs_variable_content);
-- Substring verkürzen
vs_substring := SUBSTR(vs_substring, INSTR(vs_substring, vs_variable) + LENGTH(vs_variable) + 1);
ELSE
vs_substring := '';
END IF;
END LOOP;
END IF;
RETURN vs_sql;
EXCEPTION
WHEN OTHERS
THEN
-- Err -handle
END REPLACE_VARIABLES;
/
I'd just keep it simple:
v_sql := REPLACE(v_sql, '{UsersWhere}', '...whatever you need...');