Is it possible to select a numeric column as string with proc sql in sas ?
for exemple i have this table (table_1):
+------+------+------+--------------+--+
| id_1 | id_2 | id_3 | date | |
+------+------+------+--------------+--+
| 3 | 7 | 3 | 25/06/2017 | |
| 4 | 11 | 9 | 25/06/2020 | |
+------+------+------+--------------+--+
id_1, id_2 and id_3 can be numeric or string.
i want to create a table (table_2) where these three columns should have string as type
I wrote this code :
proc sql;
Create table table_2 as
select date, Convert(varchar(30),a.id_1), Convert(varchar(30),a.id_2), Convert(varchar(30),a.id_3)
from table_1 a
;quit;
But it doesn't works
The best solution is to fix your up stream processes to always generate the variables using a consistent type.
In SAS you can use the PUT() function to convert a value to a string, just use a FORMAT that is appropriate for the type of the variable. For example if your variable is number but it should have been 9 digits long with significant leading zeros then you would want to use the Z9. format to convert it and have the leading zeros represented.
select put(id_1,z9.) as id_1
If you want to convert either a number or a character variable to a string without first knowing the type of the variable you could use the CATS() function. But then you will not have any control over how the numbers are converted into strings. Use the LENGTH= attribute to force SAS to define the variable with a length of 30.
select cats(id_1) as id_1 length=30
Just Try It ...
SELECT date, CAST(a.id_1 AS varchar(30)), CAST(a.id_2 AS varchar(30)), CAST(a.id_3 AS varchar(30))
FROM table_1 a
Related
I want to trim the number to 40 digit, but getting below error:
Query:
select 1123123211231231231231231231231231231123123123123123123123213213123213123213123123213123123123123213123123123126666666355555899 from dual;
Error:
ORA-01426: numeric overflow
01426. 00000 - "numeric overflow"
*Cause: Evaluation of an value expression causes an overflow/underflow.
*Action: Reduce the operands.
Error at Line: 14 Column: 8
Like this, perhaps? Enclose it into single quotes (so that it becomes a string) and apply SUBSTR to it:
SQL> select substr('1123123211231231231231231231231231231123123123123123123123213213123213123213123123213123123123123213123123123126666666355555899', 1, 40) result from dual;
RESULT
----------------------------------------
1123123211231231231231231231231231231123
SQL>
Use a string and TO_NUMBER( value DEFAULT NULL ON CONVERSION ERROR ):
SELECT TO_NUMBER( value DEFAULT NULL ON CONVERSION ERROR )
FROM long_numbers
Which, for the sample data:
CREATE TABLE long_numbers ( value ) AS
SELECT '1123123211231231231231231231231231231123123123123123123123213213123213123213123123213123123123123213123123123126666666355555899' FROM DUAL UNION ALL
SELECT '112312321123123123123123123123123123112312312312312312312321321312321312321312312321312312312312321312312312312666666635555589' FROM DUAL UNION ALL
SELECT '0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012345678901234567890123456789012345678901234567890' FROM DUAL;
Outputs:
| TO_NUMBER(VALUEDEFAULTNULLONCONVERSIONERROR) |
| ----------------------------------------------------------------------------------------------------------------------------------------------------: |
| null |
| 112312321123123123123123123123123123112300000000000000000000000000000000000000000000000000000000000000000000000000000000000000 |
| .0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000123456789012345678901234567890123456789 |
Why doesn't the first value work?
From the Oracle data types documentation:
The following numbers can be stored in a NUMBER column:
Positive numbers in the range 1 x 10-130 to 9.99...9 x 10125 with up to 38 significant digits
Negative numbers from -1 x 10-130 to 9.99...99 x 10125 with up to 38 significant digits
Zero
So your first example will not work as it is outside the limits that the NUMBER data type can accept. There is nothing that can be done to display it as a NUMBER as it is too big.
What can I use instead of a NUMBER data type?
If you require the exact value then you will need to store it as a string.
If you want an approximate numeric value then you can store it as a BINARY_DOUBLE:
SELECT TO_BINARY_DOUBLE( value )
FROM long_numbers
Outputs:
| TO_BINARY_DOUBLE(VALUE) |
| :---------------------- |
| 1.1231232112312312E+126 |
| 1.1231232112312312E+125 |
| 1.2345678901234568E-110 |
db<>fiddle here
I need to reconcile article1 (top) and article2 tables into a View displaying differences. But before that I need to drop all zeros from column 'type'. Create new ID column equals to filenumber + type so the resulting column should be use as index. All columns share same data type
Columns needed:
ID
C0016
C0029
C00311
You can utilize below script in SQL Server to get the format you want:
Reference SO post on removing padding 0
SELECT CONCAT(filenumber,type) AS filenumber, type, cost
FROM
(
SELECT
filenumber,
SUBSTRING(type, PATINDEX('%[^0]%',type),
LEN(type)- PATINDEX('%[^0]%',type)+ 1) AS type, cost
FROM
(
VALUES
('C001','00006',40),
('C002','00009',80),
('C003','00011',120)
) as t(filenumber,type, cost)
) AS t
Resultset
+------------+------+------+
| filenumber | type | cost |
+------------+------+------+
| C0016 | 6 | 40 |
| C0029 | 9 | 80 |
| C00311 | 11 | 120 |
+------------+------+------+
You can use try_convert() :
alter table table_name
add id as concat(filenumber, try_convert(int, type)) persisted -- physical storage
If you want a view :
create view veiw_name
as
select t.*, concat(filenumber, try_convert(int, type)) as id
from table t;
try_convert() will return null whereas conversation fails.
I have a requirement to convert all the characters in my string to *. My string can also contain special characters as well.
For Example:
abc_d$ should be converted to ******.
Can any body help me with regex like this in oracle.
Thanks
Use REGEXP_REPLACE and replace any single character (.) with *.
SELECT
REGEXP_REPLACE (col, '.', '*')
FROM yourTable
Demo
Instead of regex you could also use
select rpad('*', length('abc_d$ s'),'*') from dual
-- use '*' and pad it until length fits with other *
Doku: rpad(string,length,appendWhat)
Repeat with a string of '*' should work as well: repeat(string,count) (not tested)
regex or rpad makes no difference - they are optimized down to the same execution plan:
n-th try of rpad:
Plan Hash Value : 1388734953
-----------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost | Time |
-----------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 2 | 00:00:01 |
| 1 | FAST DUAL | | 1 | | 2 | 00:00:01 |
-----------------------------------------------------------------
n-th try of regex_replace
Plan Hash Value : 1388734953
-----------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost | Time |
-----------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 2 | 00:00:01 |
| 1 | FAST DUAL | | 1 | | 2 | 00:00:01 |
-----------------------------------------------------------------
So it does not matter wich u use.
THIS IS NOT AN ANSWER
As suggested by Tom Biegeleisen’s brother Tim, I ran a test to compare a solution based on regular expressions to one using just standard string functions. (Specifically, Tim's answer with regular expressions vs. Patrick Artner's solution using just LENGTH and RPAD.)
Details of the test are shown below.
CONCLUSION: On a table with 5 million rows, each consisting of one string of length 30 (in a single column), the regular expression query runs in 21 seconds. The query using LENGTH and RPAD runs in one second. Both solutions read all the data from the table; the only difference is the function used in the SELECT clause. As noted already, both queries have the same execution plan, AND the same estimated cost - because the cost does not take into account differences in function calculation time.
Setup:
create table tbl ( str varchar2(30) );
insert into tbl
select a.str
from ( select dbms_random.string('p', 30) as str
from dual
connect by level <= 100
) a
cross join
( select level
from dual
connect by level <= 50000
) b
;
commit;
Note that there are only 100 distinct values, and each is repeated 50,000 times for a total of 5 million values. We know the values are repeated; Oracle doesn't know that. It will really do "the same thing" 5 million times, it won't just do it 100 times and then simply copy the results; it's not that smart. This is something that would be known only by seeing the actual stored data, it's not known to Oracle beforehand, so it can't "prepare" for such shortcuts.
Queries:
The two queries - note that I didn't want to send 5 million rows to screen, nor did I want to populate another table with the "masked" values (and muddy the waters with the time it takes to INSERT the results into another table); rather, I compute all the new strings and take the MAX. Again, in this test all "new" strings are equal to each other - they are all strings of 30 asterisks - but there is no way for Oracle to know that. It really has to compute all 5 million new strings and take the max over them all.
select max(new_str)
from ( select regexp_replace(str, '.', '*' ) as new_str
from tbl
)
;
select max(new_str)
from ( select rpad('*', length(str), '*') as new_str
from tbl
)
;
Try this:
SELECT
REGEXP_REPLACE('B^%2',
'*([A-Z]|[a-z]|[0-9]|[ ]|([^A-Z]|[^a-z]|[^0-9]|[^ ]))', '*') "REGEXP_REPLACE"
FROM DUAL;
I have included for white spaces too
select name,lpad(regexp_replace(name,name,'*'),length(name),'*')
from customer;
I have the following table (table1):
+---+---------------------------------------------+
+---|--------att1 --------------------------------+
| 1 | 10.2.5.4 4.3.2.1.in-addr.arpa |
| 2 | asd 100.99.98.97 97.3.2.1.a.b.c fsdf |
| 3 | fd 95.94.93.92 92.5.7.1.a.b.c |
| 4 | a 11.4.99.75 75.77.52.41.in-addr.arpa |
+---+---------------------------------------------+
I would like to get the following values (that are located after the repetitive numbers): in-addr.arpa, a.b.c, a.b.c, in-addr.arpa.
I tried to use the following format with no success:
SELECT att1
FROM table1
WHERE REGEXP_LIKE(att1 , '^(\d+?)\1$')
I would like it to run in Impala and Oracle.
Use REGEXP_SUBSTR (assuming you are using an Oracle DB).
select regexp_substr(att1,'[0-9]\.([^0-9]+)',1,1,null,1)
from table1
[0-9]\. a numeric followed by a .
[^0-9]+ any character other than a numeric is matched until the next numeric is found. () around this indicates the group (first in this case) and we only extract that part of the string.
Sample Demo
I have in oracle a simple select statement (example):
SELECT * FROM organisation WHERE ID=15
This returns a row :
**ID | NAME | NOTES | VALUE**
15 | BEST | Just Notes...| 112
Now I want to take the Value (112) and use it as a parameter in an oracle function :
function get_session_text (
in_value in number
)
return varchar2 is....
So I would like to build a select statement that it will return something like that:
**ID | NAME | NOTES | VALUE | TEXT **
15 | BEST |Just Notes... | 112 | function's result
Select * from
I tried to build it but I am not familiar with functions, so could you please help me with that SQL statement?
SELECT id,
name,
notes,
value,
get_session_text( value )
FROM organization
should do it.