ERROR: Function SUBSTR requires a character expression as argument 1. and adding zeroes in front of data - sql

My end goal is to add zeroes in front of my data, so 918 becomes 0918 and 10 becomes 0010 limited at 4 characters. My solution so far is to use SUBSTR like i do below:
PROC SQL;
CREATE TABLE WORK.QUERY_FOR_DAGLIGEKORREKTION_0000 AS
SELECT (SUBSTR(line_item, 1, 4)) AS line_item,
(SUBSTR(column_item, 1, 4)) AS column_item
FROM QUERY_FOR_DAGLIGEKORREKTIONER t1;
QUIT;
But when I run my query I get the following error:
ERROR: Function SUBSTR requires a character expression as argument 1.
ERROR: Function SUBSTR requires a character expression as argument 1.
This is my data set:
line_item column_item
918 10
230 10
260 10
918 10
918 10
918 10
70 10
80 10
110 10
250 10
35 10
What am I doing wrong? and is there another maybe easier way to add zeroes in fornt of my data?
I hope you can lead me in the right direction.

In SAS you can associate a format with a numeric variable to specify how the value is rendered when output in a report or displayed in a query result.
Example:
Specify a column to be displayed using the Z<n>. format.
select <numeric-var> format=z4.
The underlying column is still numeric.
If you want to convert the numeric result permanently to a character type, use the PUT function.
select PUT(<numeric-expression>, Z4.) as <column-name>

I found a solution by searching for something similar to the Oracle solution by #d r and I found the following solution to the problem:
put(line_item, z4.) AS PAD_line_item,
put(column_item, z4.) AS PAD_column_item,
resulting in:
line_item column_item
0918 0010
0230 0010
0260 0010
0918 0010
0918 0010
0918 0010
0070 0010
0080 0010
0110 0010
0250 0010
0035 0010
I hope this will help someone in the future with leading zeroes.

Oracle
Select
LPAD(1, 4, '0') "A",
LPAD(12, 4, '0') "B",
LPAD(123, 4, '0') "C",
LPAD(1234, 4, '0') "D",
LPAD(12345, 4, '0') "E"
From Dual
--
-- R e s u l t
--
-- A B C D E
-- ---- ---- ---- ---- ----
-- 0001 0012 0123 1234 1234

Add the value to 10,000; Cast the result to a VARCHAR(5) (or longer); Get SUBSTR(2,4) out of that.
SELECT
SUBSTR((line_item + 10000)::VARCHAR(5),2,4) AS s_line_item
, SUBSTR((column_item + 10000)::VARCHAR(5),2,4) AS s_column_item
FROM indata;
-- out s_line_item | s_column_item
-- out -------------+---------------
-- out 0918 | 0010
-- out 0230 | 0010
-- out 0260 | 0010
-- out 0918 | 0010
-- out 0918 | 0010
-- out 0918 | 0010
-- out 0070 | 0010
-- out 0080 | 0010
-- out 0110 | 0010
-- out 0250 | 0010
-- out 0035 | 0010

Related

SQL query for Bill of Materials to get levels of components

I have got data that contains
parent_id
child_id
parent_desc
child_desc
123
24
AA
BB
123
81
AA
ZZ
24
32
BB
EE
32
45
EE
DD
45
57
DD
FF
57
62
FF
GG
62
7
GG
FA
81
9
ZZ
GA
What I want to achieve is to have a BOM explosion of it.
What I have come up is the below code:
create table test
( SurrogateKey bigint, ForeignKey bigint,mat_desc varchar,comp_desc varchar );
insert into test
values
( 123, 24,'AA','BB'),
(123,81,'AA','ZZ'),
( 24, 32,'BB','EE'),
( 32, 45,'EE','DD'),
( 45, 57,'DD', 'FF'),
( 57, 62,'FF','GG'),
( 62, 7,'GG','FA'),
(81,9,'ZZ','GA');
With traversal as
( SELECT test.SurrogateKey OriginKey,
ForeignKey,mat_desc,comp_desc
FROM test
WHERE SurrogateKey = 123 -- this first portion of the query generates the beginning set of records.
UNION ALL
SELECT traversal.OriginKey,
test.ForeignKey,traversal.mat_desc,test.comp_desc
FROM test
INNER JOIN traversal
ON test.SurrogateKey = traversal.ForeignKey -- we join back to the result set generated in the previous iteration of the recursion until no more nodes to travel to
)
select * from traversal
That is giving me a result:
parent_id
child_id
parent_desc
child_desc
123
24
AA
BB
123
81
AA
ZZ
123
32
AA
EE
123
9
AA
GA
123
45
AA
DD
123
57
AA
FF
123
62
AA
GG
123
7
AA
FA
But what I would like to achieve is to add column to see on which level the child is so thirst three rows would look like this, and so on
parent_id
child_id
parent_desc
child_desc
level
123
24
AA
BB
1
123
81
AA
ZZ
1
123
32
AA
EE
2
123
9
AA
GA
123
45
AA
DD
123
57
AA
FF
123
62
AA
GG
123
7
AA
FA
Maybe someone has got idea, how to solve this. Maybe some window function, or how to come up with some counter to have it using recursive cte
Thank you all in advance
If I understand correctly, you want to enumerate the rows based on the tree-depth. You correctly recognize that you can do this with a recursive CTE.
The syntax for recursive CTEs varies depending on the databases, but the idea is:
with recursive cte as (
select t.SurrogateKey, t.ForeignKey, t.mat_desc, t.comp_desc, t.mat_desc as orig_mat_desc, 1 as lev
from test t
where not exists (select 1 from test t2 where t2.comp_desc = t.mat_desc)
union all
select t.SurrogateKey, t.ForeignKey, t.mat_desc, t.comp_desc, cte.orig_mat_desc, 1 + lev
from cte join
test t
on cte.comp_desc = t.mat_desc
)
select *
from cte;
Here is a db<>fiddle.

SQL query to update gaps in dataset in DB2

I have the following problem with my SQL update, or better said: I do not know how to do it.
I have to update a dataset on DB2.
So does my dataset look like.
NUM_CUS COD_ENTITY BRN_OPEN COD_PRODSERV NUM_ACCOUNT KEY_ENTITY KEY_PARTIC PARTSEQ
11111111 0100 0010 98 60607998 0100 T 01
20000264 0100 0010 98 60607998 0100 Y 02
Now the row: NUM_CUS = '20000264' has to be updated, especially the field PARTSEQ.
It has to be updated to PARTSEQ = '01'.
The row with NUM_CUS: '11111111' and KEY_PARTIC = 'T' is the 'primary row'!
But it could also be that we have 3 rows where there is a gap in PARTSEQ, like here
NUM_CUS COD_ENTITY BRN_OPEN COD_PRODSERV NUM_ACCOUNT KEY_ENTITY KEY_PARTIC PARTSEQ
11111111 0100 0010 98 60607998 0100 T 01
22222222 0100 0010 98 60607998 0100 Y 03
20000264 0100 0010 98 60607998 0100 Y 04
Then PARTSEQ: 03 should be updated to 01, and PARTSEQ: 04 must be updated to 02.
Can somebody tell me how it is possible to updated the field to the appropriate numbers.
if only the first row has KEY_PARTIC = 'T', you can use ROW_NUMBER function like that :
create table temp as
select NUM_CUS,PARTSEQ ,ROW_NUMBER ( )
OVER ( PARTITION BY NUM_CUS ORDER BY PARTSEQ asc) as rank
From <Table_name>
WHERE KEY_PARTIC ='Y';
Then Update PARTSEQ in your table by rank value of Temp table.
Try this:
UPDATE
(
SELECT PARTSEQ, LPAD(ROW_NUMBER() OVER (ORDER BY PARTSEQ), 2, '0') PARTSEQ_NEW
FROM MYTAB
WHERE KEY_PARTIC <> 'T'
)
SET PARTSEQ = PARTSEQ_NEW
WHERE PARTSEQ <> PARTSEQ_NEW;

Alphanumeric Sorting in PostgreSQL 9.4

I've a table in PostgreSQL 9.4 database in which one of the column contains data both integer and alphabets in following format.
1
10
10A
10A1
1A
1A1
1A1A
1B
1C
1C1
2
65
89
Format is, it starts with a number then an alphabet then number then alphabet and it goes on. I want to sort the field like below,
1
1A
1A1
1A1A
1B
1C
1C1
2
10
10A
10A1
65
89
But when sorting 10 comes before 2. Please suggest a possible query to obtain desired result.
Thanks in advance
Try this
SELECT *
FROM table_name
ORDER BY (substring(column_name, '^[0-9]+'))::int -- cast to integer
,coalesce(substring(column_name, '[^0-9_].*$'),'')

Getting bits from a packed word

I have a 16 bit word that could be anywhere from 1 to 16 data values. They are decoded by knowing the MSB and lsb of the 16 bit word and grabbing those bits.
I'm using VB and I just don't know how to do this.
Example
I have a word that is
&HA6F2
1010 0100 1111 0010
I know my data is LSB 3 to MSB 9. Bit ordering is left to right
So the data is 010011
How do I get this in VB code? I want to work in bytes because after I get the packed bits then I have to do type casts on it (signed_fixed, integer, 2's complement, etc)
Thanks
You should use mask (bitwise AND, see And keyword). And also probably bitwise-right-shift (see >> operator)
Conceptually:
1010 0100 1111 0010 '= the data
0001 1111 1100 0000 '= 1FC0 the mask
-------------------- And
0000 0100 1100 0000 '= 04C0
-------------------- >> 6
0000 0000 0001 0011 '= 0013 now your value is in the right most
In the code
Dim newData As Integer = (rawData And &H1FC0) >> 6

Sorting of 2 different sets of values of single row of a table

I have the below table,
A B C
-------- ---------- -----------
Akhil Kerala 0008 – 0030
Athul Kerala 15
Basil Delhi 0031 – 0059
Rahul Chennai 32
Kishore New York 0060 – 0090
Anoop Mumbai 45
I have to sort the entries according to the column C, the sorted order of the column should be like,
15
32
45
0008 – 0030
0031 – 0059
0060 – 0090
Kindly advice. Thanks in advance.
Oracle SQL:
select t.*,
to_number(decode(instr(c,' '),5,null,c)) atr1,
decode(instr(c,' '),5,c,null) atr2
from TEST_TAB t
order by atr1, atr2
If the table has many rows and the query will be frequently executed then you should add this index:
create index sort_idx on TEST_TAB (
to_number(decode(instr(c,' '),5,null,c)),
decode(instr(c,' '),5,c,null)
);
If you use e.g. MSSQL database then replace DECODE with CASE statement and INSTR with CHARINDEX.