ORDER_BY with collation in SAP HANA - sql-order-by

In my table I've got values with polish diacritics signs. I want to query it and sort the result with the right order. I need collation to do this, but I don't know how to use it in SAP HANA database.
Test table
CREATE COLUMN TABLE TEST_ORDER_BY (
ID BIGINT null,
PL_VALUE VARCHAR (20) null,
DE_VALUE VARCHAR (20) null
);
INSERT INTO TEST_ORDER_BY VALUES(1,'Aaa','Straße');
INSERT INTO TEST_ORDER_BY VALUES(2,'aaa','Strasse');
INSERT INTO TEST_ORDER_BY VALUES(3,'Bbbb','Strase');
INSERT INTO TEST_ORDER_BY VALUES(4,'bbbb','Strasze');
INSERT INTO TEST_ORDER_BY VALUES(5,'Ąaa','Aaa');
INSERT INTO TEST_ORDER_BY VALUES(6,'ąaa','ßStrae');
INSERT INTO TEST_ORDER_BY VALUES(7,'zz','Zzzz');
INSERT INTO TEST_ORDER_BY VALUES(8,'zaąa','aaa');
INSERT INTO TEST_ORDER_BY VALUES(9,'zaąz','bbb');
INSERT INTO TEST_ORDER_BY VALUES(10,'zabz','Strasße');
SQL Query
SELECT id, pl_value
FROM TEST_ORDER_BY
ORDER BY pl_value ASC;
Result
ID PL_VALUE
1 Aaa
3 Bbbb
2 aaa
4 bbbb
10 zabz
8 zaąa
9 zaąz
7 zz
5 Ąaa
6 ąaa
Expected result
ID PL_VALUE
---------- --------------------
1 Aaa
2 aaa
5 Ąaa
6 ąaa
3 Bbbb
4 bbbb
8 zaąa
9 zaąz
10 zabz
7 zz
What I need is a to be followed by ą and same for other diacritics signs like ęóśłżźń.
I found the view M_COLLATIONS in the database (without polish collation) and column COLLATION in TABLE_COLUMNS view, but I don't know how to set it for speciefied column.
What can I do?

Even though the system view is there collations are not supported with HANA so far.(2.03.33)
I assume this view is going to be used with a feature in later HANA version.

Starting with SPS04, specifying collations in an order by clause is supported:
An example would be:
select * from mytable order by col1 COLLATE TURKISH;
https://answers.sap.com/answers/12900664/view.html

Related

FRM-40350 Query Caused No Records to be retrieved

I am new in Oracle forms. I have connected my forms to the database. Then created data block choosing data block wizard. I have choosen of my database table ORDERS. I have inserted values in this ORDERS table in sqlplus. After creating ORDERS data block I run my forms through browser, I click on execute query on menu but it's not fetching the data from my database table. It says,
FRM-40350 Query Caused No REcords to be retrieved . But in sqlplus I have checked that the row created successfully and column is fill in value and my application forms is connected to my database. Then why my execute query not working? How can I fix this?
If you're connected to the same user in both SQLPlus and Forms (you probably are, otherwise Forms wouldn't see that table and you wouldn't be able to base data block on it), you probably didn't COMMIT after inserting row(s) in SQLPlus.
Code you posted should be fixed (invalid datatype, missing column name, don't insert strings into DATE datatype column):
SQL> CREATE TABLE ORDERS(
2 order_id NUMBER(20),
3 customer_id NUMBER(20),
4 order_date DATE, -- NUMBER(20), --> date, not number
5 order_status VARCHAR2(20),
6 order_mode VARCHAR2 (200),
7 SALES_REP_ID NUMBER (20) );
Table created.
SQL> INSERT INTO orders (
2 order_id,
3 customer_id,
4 order_date,
5 order_status,
6 order_mode,
7 sales_rep_id
8 ) VALUES (
9 0001,
10 01,
11 date '2008-02-11', -- not '11-FEB-2008', it is a STRING
12 '5',
13 'direct',
14 158
15 );
1 row created.
This is what you're missing:
SQL> COMMIT;
Commit complete.
SQL>

select from the table name values after _ using oracle sql

Suppose if the table name is ABC_XYZ_123. I want to extract the integer values after _.
The output should be integer values after _.
In the above case, the output should be 123.
I have used the below sql query.
select from table_name like 'XXX_%';
But I am not getting required output. Can anyone help me with this query.
Thanks
Using REGEXP_SUBSTR with a capture group we can try:
SELECT REGEXP_SUBSTR(name, '_(\d+)$', 1, 1, NULL, 1)
FROM yourTable;
The question is somewhat unclear:
it looks as if you're looking for table names that contain number at the end, while
query you posted suggests that you're trying to select those numbers from one of table's columns
I'll stick to
Suppose if the table name is ABC_XYZ_123
If that's so, it is the data dictionary you'll query. USER_TABLES contains that information.
Let's create that table:
SQL> create table abc_xyz_123 (id number);
Table created.
Query selects numbers at the end of table names, for all my tables that end with numbers.
SQL> select table_name,
2 regexp_substr(table_name, '\d+$') result
3 from user_tables
4 where regexp_like(table_name, '\d+$');
TABLE_NAME RESULT
-------------------- ----------
TABLE1 1
TABLE2 2
restore_point-001 001
ABC_XYZ_123 123 --> here's your table
SQL>
Apparently, I have a few of them.

Log all errors for a value into error log if a single row fails

I am trying to maintain data integrity and logging errors to an error table. I've got 3 tables with unique constraints and 1 error table:
create table tbl_one (
pass_no number,
constraint tbl_one_u01 unique (pass_no) );
insert into tbl_one values(10);
insert into tbl_one values(20);
create table tbl_two (
cus_no number,
cus_name varchar2(50),
pass_no number,
constraint tbl_two_u01 unique (cus_no) );
insert into tbl_two values( 101, 'NameX',10);
insert into tbl_two values( 102, 'NameY',10);
insert into tbl_two values( 103, 'NameZ',20);
create table tbl_target (
cus_no number,
pass_no number,
constraint tbl_target_u01 unique (cus_no),
constraint tbl_target_u02 unique (pass_no));
exec dbms_errlog.create_error_log('tbl_target','tbl_target_err');
I am trying to log all ORA-00001 errors to the error table tbl_target_err like this:
begin
insert into tbl_target
select a.pass_no, b.cus_no
from tbl_one a
inner join tbl_two b on b.pass_no = a.pass_no
log errors into tbl_target_err reject limit 10;
end;
The result is:
select * from tbl_target;
-------------------
CUS_NO PASS_NO
101 10
103 20
and the error table:
CUS_NO PASS_NO
102 10
I need all the violated errors to go into the error table. If the value of pass_no 10 is violated then all 10 values should inserted into the error table; not, one into target and one to error table. I don't want to use exists statements because I won't able to log all violated values.
How could I go about doing this?
You can't use the error logging mechanism for this as it isn't designed to support it. It errors at the point it tries to create the duplicate in the table - the first value it tries to insert for pass_no 10 is valid on its own - so it would have to distinguish between data that already existed and multiple values coming from the insert, to start with. So you'd need to roll your own.
One option is to create your own table to hold the duplicates, and use an insert all to decide which values belong in each table:
create table tbl_target_dup (
cus_no number,
pass_no number
);
insert all
when cus_count = 1 and pass_count = 1 then
into tbl_target values (cus_no, pass_no)
else
into tbl_target_dup values (cus_no, pass_no)
select a.pass_no, b.cus_no,
count(*) over (partition by a.pass_no) as pass_count,
count(*) over (partition by b.cus_no) as cus_count
from tbl_one a
join tbl_two b on b.pass_no = a.pass_no;
This allows you to have more columns than those affected by the PK/UK, and insert them only into the real table if you prefer, or a subset into the 'error' table. With just those two columns in each table you get:
select * from tbl_target;
CUS_NO PASS_NO
---------- ----------
103 20
select * from tbl_target_dup;
CUS_NO PASS_NO
---------- ----------
101 10
102 10
SQL Fiddle demo.
You could do the same thing with two inserts based on the same select, one with a subquery checking that both counts are 1, other checking that at least one is not, but this might perform better.

Oracle view not updatable, advice on Instead Of triggers

after migrating a system/database we modified a central table which has been used for interfacing with 15 different systems. We used this migration to add and delete a few fields in this table.
To maintain direct compatibility with the interfacing systems (i.e. only need to change the database-link), a view has been created which shows the exact same columns as the old table had. However, some of these columns are only emulated, so the view contains constructs like these:
(...)
CREATE OR REPLACE VIEW STAFF_DATA_COMPAT AS
SELECT
NVL(knownas_surname,surname) as surname,
first_name
middle_name as mid-name
NULL as ni,
NULL as home_tel_no,
(...)
Obviously, this view is not inherently updatable.
I do understand, that you need INSTEAD OF triggers for all DML (insert, update, delete) statements.
I can see, that a INSTEAD OF INSERT trigger should be quite straightforward (just inserting :NEW.field to the real table, where appropriate and ignoring the others).
But the actual question: How to write the according INSTEAD OF UPDATE/DELETE triggers? For instance, how do I take over the "WHERE" clause of an original DELETE statement? Is there anything else I should worry about, any side-effects when using these triggers?
Btw. It's Oracle 11g.
The INSTEAD OF trigger would look like this (I've assumed you have a primary key column id):
SQL> CREATE OR REPLACE TRIGGER trg_staff_data_cpt_instead_upd
2 INSTEAD OF UPDATE ON staff_data_compat
3 FOR EACH ROW
4 BEGIN
5 UPDATE staff_data_compat_t
6 SET knownas_surname = :new.surname,
7 first_name = :new.first_name,
8 middle_name = :new.mid_name
9 WHERE id = :new.id
10 END;
11 /
Trigger created
Note that some columns may in fact be updatable in the original view. Query the all_updatable_columns view (before creating the trigger) to find out:
SQL> CREATE TABLE staff_data_compat_t AS
2 SELECT object_name knownas_surname,
3 owner surname,
4 object_type first_name,
5 subobject_name middle_name
6 FROM all_objects;
Table created
SQL> CREATE OR REPLACE VIEW staff_data_compat AS
2 SELECT
3 NVL(knownas_surname,surname) as surname,
4 first_name,
5 middle_name mid_name,
6 NULL as ni,
7 NULL as home_tel_no
8 FROM staff_data_compat_t;
View created
SQL> SELECT * FROM all_updatable_columns WHERE table_name = 'STAFF_DATA_COMPAT';
OWNER TABLE_NAME COLUMN_NAME UPDATABLE INSERTABLE DELETABLE
------ ------------------ ------------ --------- ---------- ---------
VNZ STAFF_DATA_COMPAT SURNAME NO NO NO
VNZ STAFF_DATA_COMPAT FIRST_NAME YES YES YES
VNZ STAFF_DATA_COMPAT MID_NAME YES YES YES
VNZ STAFF_DATA_COMPAT NI NO NO NO
VNZ STAFF_DATA_COMPAT HOME_TEL_NO NO NO NO
If you only need to insert/update these columns, you don't need an INSTEAD OF trigger.
INSTEAD OF triggers are implicitly "FOR EACH ROW", so you don't have to find out the WHERE clause, you just do something like this:
begin
delete base_table
where pk = :old.pk;
end;
This also shows one of the drawbacks of INSTEAD OF triggers: they work row-by-row not in sets.

How to generate alphanumeric id in Oracle

In my vb application I want an autogenerated id of alphanumeric characters, like prd100. How can I increment it using Oracle as backend?
Any particular reason it needs to be alphanumeric? If it can just be a number, you can use an Oracle sequence.
But if you want just a random string, you could use the dbms_random function.
select dbms_random.string('U', 20) str from dual;
So you could probably combine these 2 ideas (in the code below, the sequence is called oid_seq):
SELECT dbms_random.string('U', 20) || '_' || to_char(oid_seq.nextval) FROM dual
There are two parts to your question. The first is how to create an alphanumeric key. The second is how to get the generated value.
So the first step is to determine the source of the alpha and the numeric components. In the following example I use the USER function and an Oracle sequence, but you will have your own rules. I put the code to assemble the key in a trigger which is called whenever a row is inserted.
SQL> create table t1 (pk_col varchar2(10) not null, create_date date)
2 /
Table created.
SQL> create or replace trigger t1_bir before insert on t1 for each row
2 declare
3 n pls_integer;
4 begin
5 select my_seq.nextval
6 into n
7 from dual;
8 :new.pk_col := user||trim(to_char(n));
9 end;
10 /
Trigger created.
SQL>
The second step requires using the RETURNING INTO clause to retrieve the generated key. I am using SQL*PLus for this example. I confess to having no idea how to wire this syntax into VB. Sorry.
SQL> var new_pk varchar2(10)
SQL> insert into t1 (create_date)
2 values (sysdate)
3 returning pk_col into :new_pk
4 /
1 row created.
SQL> print new_pk
NEW_PK
--------------------------------
APC61
SQL>
Finally, a word of warning.
Alphanumeric keys are a suspicious construct. They reek of "smart keys" which are, in fact, dumb. A smart key is a value which contains multiple parts. At somepoint you will find yourself wanting to retrieving all rows where the key starts with 'PRD', which means using SUBSTR() or LIKE. Even worse someday the definition of the smart key will change and you will have to cascade a complicated update to your table and its referencing foreign keys. A better ides is to use a surrogate key (number) and have the alphanumeric "key" defined as separate columns with a UNIQUE composite constraint to enforce the business rule.
SQL> create table t1 (id number not null
2 , alpha_bit varchar2(3) not null
3 , numeric_bit number not null
4 , create_date date
5 , constraint t1_pk primary key (id)
6 , constraint t1_uk unique (alpha_bit, numeric_bit)
7 )
8 /
Table created.
SQL>

Resources