How to convert the Long value to String using sql - plsql

I am doing a long to string conversion using java in following way.
Long longValue = 367L;
String str = Long.toString(longValue, 36).toUpperCase();
this is returning me as value A7. how can achieve this in doing oracle sql.
UPDATED:
Hi, I have analyzed how java code is working then wanted to implement the same thing in procedure.
First point is Input vaues. LONG and Radix. in my case Radix is 36. so i will have values from 1..9A...Z0 It picks up the values from this set only.
Second point Long value as input. we have to divide this value with radix. if the quotient is more than 36 again we need to divide.
For eaxmple 367 then my converted value is 10(quotient) 7(remainder) that is A7.
3672 converted value is 102 0 i need to do again for 102 that is 2 -6 so my final value will be 2-6 0 that is 2U0(- means reverse the order).
UPDATE 2:
Using oracle built in functions we can do this. this was solved by my friend and gave me a function.I want to thank my friend. this will give me an out put as follows.
367 then my converted value is 10(quotient) 7(remainder) that is *A*7.(I modified this to my requirement).
FUNCTION ENCODE_STRING(BASE_STRING IN VARCHAR2,
FROM_BASE IN NUMBER,
TO_BASE IN NUMBER)
RETURN VARCHAR2
IS
V_ENCODED_STRING VARCHAR(100);
BEGIN
WITH N1 AS (
SELECT SUM((CASE
WHEN C BETWEEN '0' AND '9'
THEN TO_NUMBER(C)
ELSE
ASCII(C) - ASCII('A') + 10
END) * POWER(FROM_BASE, LEN - RN)
) AS THE_NUM
FROM (SELECT SUBSTR(BASE_STRING, ROWNUM, 1) C, LENGTH(BASE_STRING) LEN, ROWNUM RN
FROM DUAL
CONNECT BY ROWNUM <= LENGTH(BASE_STRING))
),
N2 AS (
SELECT (CASE
WHEN N < 10
THEN TO_CHAR(N)
ELSE CHR(ASCII('A') + N - 10)
END) AS DIGI, RN
FROM (SELECT MOD(TRUNC(THE_NUM/POWER(TO_BASE, ROWNUM - 1)), TO_BASE) N, ROWNUM RN
FROM N1
CONNECT BY ROWNUM <= TRUNC(LOG(TO_BASE, THE_NUM)) + 1)
)
SELECT SYS_CONNECT_BY_PATH(DIGI, '*') INTO V_ENCODED_STRING
FROM N2
WHERE RN = 1
START WITH RN = (SELECT MAX(RN) FROM N2)
CONNECT BY RN = PRIOR RN - 1;
RETURN V_ENCODED_STRING;

IN PL/SQL (or Oracle SQL) you have the a function called TO_CHAR.
http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions181.htm

It is not possible to do it in the pure SQL. You have to use PL/SQL.
Simple example how to do it PL/SQL:
CREATE TABLE long_tbl
(
long_col LONG
);
INSERT INTO long_tbl VALUES('How to convert the Long value to String using sql');
DECLARE
l_varchar VARCHAR2(32767);
BEGIN
SELECT long_col
INTO l_varchar
FROM long_tbl;
DBMS_OUTPUT.PUT_LINE(l_varchar);
END;
-- How to convert the Long value to String using sql
There is TO_LOB function but it can only by used when you insert data into table.
http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions185.htm
You can apply this function only to a LONG or LONG RAW column, and
only in the select list of a subquery in an INSERT statement.
There is also other, more proper way to do it by using "dbms_sql.column_value_long" but this gets complicated (fetching of the LONG column and appending to the CLOB type.)
http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_sql.htm#i1025399
(Oracle Database PL/SQL Packages and Types Reference)

Related

what is different between using Variable and not in Mariadb?

I just want to get some hint. Is there a type issue?
issue case.
SET #ids = '4094,8562,11144,3017,5815,11121,1957,4095,8563,11145,3018,5816,8527,11122,1959,4096,8564,3020,5817,8528,11123,1961,4097,8571,3021,6020,8535,11128,1962,5181,8572,3581,6021';
this #ids value is actually collected by GROUP_CONCAT() from the subquery;
SELECT
ifnull(sum(case when a.student IS NOT NULL then total END), 0)
from
tb_class a
WHERE
a.id IN (#ids)
and a.date >= '2023-02-01' AND a.DATE <= '2023-02-02'
==> 0
correct case2.
SELECT
ifnull(sum(case when a.student IS NOT NULL then total END), 0)
from
tb_class a
WHERE
a.id IN (4094,8562,11144,3017,5815,11121,1957,4095,8563,11145,3018,5816,8527,11122,1959,4096,8564,3020,5817,8528,11123,1961,4097,8571,3021,6020,8535,11128,1962,5181,8572,3581,6021)
and a.date >= '2023-02-01' AND a.DATE <= '2023-02-02'
==> 54
I got answer from googling. use function FIND_IN_SET()
SELECT
ifnull(sum(case when a.student IS NOT NULL then total END), 0)
from
tb_class a
WHERE
FIND_IN_SET(a.id, #ids)
and a.date >= '2023-02-01' AND a.DATE <= '2023-02-02'
Variables store single values, not lists. Your #ids is just a string that happens to have a comma separated list of numbers. The IN operator only compares against an explicit list; what you are doing is no different than a.id = #ids (which will actually be true, with a warning, for the first number in the list if id is a numeric type, since the string will be converted to a number and the trailing non-numeric portion discarded).
Sometimes you do want to work with a string containing a list of ids such as this, for instance if you have a query that reads many rows that you want to use to produce a small list of ids to update, without the update locking those all the rows read. Then you can use dynamic sql:
SET #ids = '4094,8562,...';
SET #sql = concat('select * from a where a.id in (',#ids,')');
prepare stmt from #sql;
execute stmt;
deallocate prepare stmt;
Or, in mariadb since 10.2,
EXECUTE IMMEDIATE concat('select * from a where a.id in (',#ids,')');
Another alternative is to use FIND_IN_SET, as shown in another answer, but that will not use an index to look up ids, so may be inefficient.

Teradata SQL - Convert values separated by ; in a single column to multiple rows

I have a single column with comma separated values like below.
sel job_dependency from test_table;
job_dependency
1;2;3;4;5;6
I need to convert it into below format in Teradata SQL where each number is a row.
job_dependency
1
2
3
4
5
6
Any help would be really helpful.
There's a table function for this task:
WITH cte AS
(
SELECT
1 AS inKey -- might be a column, either INT or VarChar up to 60 bytes
-- Other data types should be CASTed to VarChar (and back in the Select)
,job_dependency2 AS inString
FROM test_table
)
SELECT *
FROM TABLE
( StrTok_Split_To_Table(cte.inKey, cte.inString, ';')
RETURNS (outKey INTEGER, -- data type must match input column
tokenNum INTEGER,
token VARCHAR(20))
) AS dt

Evaluating string/combination of variables as logical expression in oracle pl/sql

In my Pl/Sql code , I have three variables v_var1 , v_operand , v_var2 whose values are populated based on some logic (v_var1 & v_var2 can be date , number , varchar. Associated Operand will be according to data type only). A sample would be
v_var1 = 10 , v_operand = '=' , v_var2 = 20.
Based on these value , I have to evaluate whether the condition "v_var1 -v_operand- v_var2"is true or false.
Ex :- with above values, I have to evaluate whether 10 equals 20 or not.
How can I achieve this ? Can I pass the whole string as '10 = 20' to some function and get the result as false?
One way I can think of is to write CASE statements for evaluating but can there be a better way ?
You could use dynamic SQL to do the evaluation as a filter on the dual table:
declare
v_var1 varchar2(10) := '10';
v_operand varchar2(10) := '=';
v_var2 varchar2(10) := '20';
l_result number;
begin
execute immediate 'select count(*) from dual where :var1 ' || v_operand || ' :var2'
into l_result using v_var1, v_var2;
if l_result = 1 then
dbms_output.put_line('True');
else
dbms_output.put_line('False');
end if;
end;
/
PL/SQL procedure successfully completed.
False
If the condition is true the count will get 1, otherwise it will get 0, and you can then test that via the local variable you select the count into.
Holding dates and numbers as strings isn't ideal, even temporarily, but might be OK as long as you convert to/from the real data types consistently, e.g. always explicitly converting dates with to_date and to_char and specifying the format masks.

Convert Columns to ROW

I am stuck with this requirement -
I have some data in the format
(Entries now show data for both periods (Jan. 2011) and (Feb. 2011) on the same line as apposed to appearing separately).
At the end I need to print the data using dbms_output.put_line command.
I am using Oracle 10.2g.
Oracle 10g does not have a PIVOT function but you can convert the rows of data into columns using an aggregate function with a CASE expression. The basic syntax would be:
select d.id,
d.site,
d.entrance,
sum(case when d.date = 'Jan.2011' then enters else 0 end) "Jan.2011",
sum(case when d.date = 'Feb.2011' then enters else 0 end) "Feb.2011"
from
(
select id, site, entrance, date, enters
from yourdata
) d
group by d.id, d.site, d.entrance;
Note: you can replace the subquery with yourdata with your current query.

How To Create A Stored Procedure That return a Random Number If Not Exist In The Table

I Want To Create A Stored procedure That return A Random Number Between (11111,99999)
Provided that the Number Should Not Exist In The Table
I use This complicated Function to Do that But I Need To Convert it to Stored Procedure
Function GiveRandomStudentNumber() As String
s:
Dim rnd As New Random
Dim st_num As String = rnd.Next(11111, 99999)
Dim cmd As New SqlCommand("select count(0) from student where st_num = " & st_num,con)
dd.con.Open()
Dim count As Integer = cmd.ExecuteScalar()
dd.con.Close()
If count <> 0 Then
GoTo s
Else
Return st_num
End If
End Function
this Function Is Works But I need To Convert it To Stored Procedure ..
Thanks In Advance ...
CREATE PROCEDURE [dbo].[Select_RandomNumber]
(
#Lower INT, --11111-- The lowest random number
#Upper INT --99999-- The highest random number
)
AS
BEGIN
IF NOT (#Lower < #Upper) RETURN -1
--TODO: If all the numbers between Lower and Upper are in the table,
--you should return from here
--RETURN -2
DECLARE #Random INT;
SELECT #Random = ROUND(((#Upper - #Lower -1) * RAND() + #Lower), 0)
WHILE EXISTS (SELECT * FROM YourTable WHERE randCol = #Random)
BEGIN
SELECT #Random = ROUND(((#Upper - #Lower -1) * RAND() + #Lower), 0)
END
SELECT #Random
END
Create a table of student IDs. Fill it up with IDs between X and Y. Every time you want to use an ID, remove it from the table.
create table [FreeIDs] (
[ID] int,
[order] uniqueidentifier not null default newid() primary key);
insert into [FreeIDs] ([ID]) values (11111),(11112),...,(99999);
to get a free ID:
with cte as (
select top(1) [ID]
from [FreeIDs]
order by [order])
delete cte
output deleted.ID;
The persisted predeterminer order speeds up generating new IDs.
BTW, if you're tempted to 'optimize' the table and go by a numbers table:
with Digits as (
select Digit
from (
values (0), (1), (2), (3), (4), (5),
(6), (7), (8), (9)) as t(Digit)),
Numbers as (
select u.Digit + t.Digit*10 +h.Digit*100 + m.Digit*1000+tm.Digit*10000 as Number
from Digits u
cross join Digits t
cross join Digits h
cross join Digits m
cross join Digits tm)
select top(1) Number
from Numbers
where Number between 11111 and 99999
and Number not in (
select ID
from Students)
order by (newid());
just don't. The requirement to randomize the set is a performance killer and the join to eliminate existing (used) IDs is also problematic. But most importantly the solution fails under concurrency, as multiple requests can get the same ID (and this increases as the number of free IDs is reduced). And of course, the semantically equivalent naive row-by-painfully-slow-row processing, like your original code or Kaf's answer, have exactly the same problem but are also just plain slow. It really worth testing the solution when all but one of the IDs are taken, watch the light dim as you wait for the random number generator to hit the jackpot...

Resources