Query to select rows that don't partially match - sql

I have the following table
STORE_ID|PRICE_1|PRODUCT_ID
--------+-------+----------
1052| 4.99|5157917035
1052| 4.99|5157917035
1052| 4.99|5157917036
1052| 4.99|5157917036
1052| 4.99|5157917037
As you can see these product IDs starts with "5157817". Is there a way to select only part of the value, in this case ignoring the last 3 digits and then filter out rows that are not distinct

Is there a way to select only part of the value
Sure; usually, we use substr function. If column's datatype is one of the CHAR family, just apply it directly. Otherwise, if it is a NUMBER, first convert it to a string (using the to_char function).
For example:
SQL> create table test (col_n number, col_c varchar2(10));
Table created.
SQL> insert into test values (5157917035, '5157917035');
1 row created.
SQL> select substr(to_char(col_n), 1, 7) sub_n,
2 substr(col_c, 1, 7) sub_c
3 from test;
SUB_N SUB_C
---------------------------- ----------------------------
5157917 5157917
SQL>
I didn't quite understand what result you expect out of data set you posted, but - if you ran e.g.
select DISTINCT store_id,
price_1,
substr(product_id, 1, 7)
from your_table
you'd get only one row.

Related

How to update oracle list column with sequence number

Hi I have the oracle data table like that
seq_no
name
place
1
Rian
Us
1
Moli
Us
1
Molina
Us
and i want to update automaticly the seq_no to be like that
seq_no
name
place
1
Rian
Us
2
Moli
Us
3
Molina
Us
If you have a table:
CREATE TABLE table_name (seq_no, name, place) AS
SELECT 1, 'Rian', 'Us' FROM DUAL UNION ALL
SELECT 1, 'Moli', 'Us' FROM DUAL UNION ALL
SELECT 1, 'Molina', 'Us' FROM DUAL;
and a sequence:
CREATE SEQUENCE your_sequence;
Then you can update the existing rows to the sequence values using:
UPDATE table_name
SET seq_no = your_sequence.NEXTVAL;
Then the table would contain:
SEQ_NO
NAME
PLACE
1
Rian
Us
2
Moli
Us
3
Molina
Us
Then when you want to INSERT more rows, you can use:
INSERT INTO table_name (seq_no, name, place)
VALUES (your_sequence.NEXTVAL, 'New Name', 'New Place');
and the row:
SEQ_NO
NAME
PLACE
4
New Name
New Place
Would be added with the next sequence number.
Alternatively, you could write a trigger to get the next sequence number or, from Oracle 12, use an IDENTITY column.
db<>fiddle here
What does "automatically" mean?
You could have created table so that SEQ_NO is automatically populated by a database trigger (can't use an identity column as you're on 11g).
Or, if you want to update the table, a simple option is
update your_table set seq_no = rownum;

How to parse integer values from regex and sum in BigQuery

I have a column that contains complex string and I am trying to extract out values from this string column. Here is the temp table and values -
with temp as (
select 1 as event_id, ';t-Tew00;1;1.00;252=100.00,;SM-R190;1;1.00;252=200.00,;SM-G998B/DS;1;6347.00;252=300.00,;EF-PG99P;1;249.00;252=400.00' as event_list union all
select 2 as event_id, ';asdI-Tww5300;1;1.00;252=99.00,,;EP-TA845;.252=49.00' as event_list union all
select 3 as event_id, ';asdI-Tww5300;1;1.00;252=10.00,,;EP-TA845;,.252=20.00,:etw:1002:2020,'
)
select *
from temp
I want to extract out all the double/int values after the appearance of 252= in the event_list column. For instance, in the first record, I would like to extract the values 100.00,200.00,300.00 and 400.00
I would like to add a separate column in the output that will add all such values together. So the output column for first record would be 1000.00. Likewise, 99+49 for 2nd record and 10+20 for 3rd record.
If no such appearance of 252= appears then output must be 0.
How can I achieve this in BigQuery
Try below
select event_id,
(
select ifnull(sum(cast(value as float64)), 0)
from unnest(regexp_extract_all(event_list, r'252=(\d*.?\d*)')) value
) as total_252
from temp
if aplied to sample data in your question - output is

Oracle APEX 5.1 - How to sort selected values in a Shuttle control

I have a shuttle control with a list of countries. So the user can select multiple countries, example: UK, France, Portugal. The order depends on how the user selects or moves the choices (see pic)
.
These are stored as UK:France:Portugal in the underlying table.
The problem is that I need these countries to be stored alphabetically because UK:France:Portugal is not the same as France:Portugal:UK. I know that in an ideal world these are saved in separate rows, but unfortunately this is not an option for me.
Is there a way to sort the selected values within the shuttle (on the right) alphabetically, maybe through a dynamic action when selecting countries?
If not, as an alternative, can we have a Post Calculation Computation to sort and store these values?
Thanks!
I don't know Apex-solution, but I can suggest Oracle-solution.
Here's an example: table test stores information about countries:
SQL> create table test (id number, countries varchar2(30));
Table created.
A database trigger sorts values in the countries column. How? It splits colon-separated values string into rows (that's what the regexp and connect by do), and then merges them back into another colon-separated values string (using listagg), but this time sorted (order by 1):
SQL> create or replace trigger trg_biu_cou
2 before insert or update on test
3 for each row
4 begin
5 select listagg(regexp_substr(:new.countries, '[^:]+', 1, level), ':') within group (order by 1)
6 into :new.countries
7 from dual
8 connect by level <= regexp_count(:new.countries, ':') + 1;
9 end;
10 /
Trigger created.
OK, let's see it work:
SQL> insert into test (id, countries) values (1, 'UK:France:Portugal');
1 row created.
SQL> select * from test;
ID COUNTRIES
---------- ------------------------------
1 France:Portugal:UK
SQL> update test set countries = 'New Zealand:Croatia:Hungary' where id = 1;
1 row updated.
SQL> select * from test;
ID COUNTRIES
---------- ------------------------------
1 Croatia:Hungary:New Zealand
SQL>
Might be OK; give it a try.

Oracle Sequence wastes/reserves values (in INSERT SELECT)

I've been struggling with sequences for a few days. I have this Origin data table called "datos" with the next columns:
CENTRO
CODV
TEXT
INCIDENCY
And a Destiny data table called "anda" with the following:
TIPO = 31 (for all rows)
DESCRI = 'Site' (for all rows)
SECU = sequence number generated with Myseq.NEXTVAL
CENTRO
CODV
TEXT
The last three columns must be filled in with data from "datos" table.
When I execute my query, it all works fine, my table is filled and the sequence generates its values. But, in the INSERT INTO SELECT, I have the following conditions:
Every row in origin "datos" must not already be in the destiny "anda", so it won't be duplicated, and every row in "datos" must have the INCIDENCY flag value to 'N' or NULL.
If each row matches the conditions, it should be filled.
The thing is, that the query works fine and I have been trying with many different values. Here comes the problem:
When a row has its INCIDENCY value set to 'Y' (so it must not be copied into destiny table), it doesn't appear, but the sequence DOES consumes one value, and when I check Myseq.NEXTVAL its value is higher.
How can I prevent the sequence to add any value when it doesn't match the conditions? I've read that Oracle first reserves all the possible values returning from the SELECT query, but I can't find how to prevent it.
Here's the SQL:
INSERT INTO anda (TIPO, DESCRI, SECU, CENTRO, CODV, TEXT)
SELECT( 31 TIPO,
'Site' DESCRI,
Myseq.NEXTVAL,
datos.CENTRO,
datos.CODV,
datos.TEXT
FROM datos
WHERE (CENTRO, CODV) NOT IN
(SELECT CENTRO, CODV
FROM anda)
AND (datos.INCIDENCY = 'N' OR datos.INCIDENCY IS NULL)
)
Thanks in advance!!
Definition of MySeq
CREATE SEQUENCE CREATE SEQUENCE "BBDD"."MySeq" MINVALUE 800000000000
MAXVALUE 899999999999 INCREMENT BY 1 START WITH 800000000000 CACHE 20 ORDER NOCYCLE ;
You might be able to trick Oracle into doing this with a CTE:
INSERT INTO anda (TIPO, DESCRI, SECU, CENTRO, CODV, TEXT)
WITH toinsert as (
SELECT d.*
FROM datos d
WHERE (CENTRO, CODV) NOT IN (SELECT CENTRO, CODV FROM anda) AND
(d.INCIDENCY = 'N' OR d.INCIDENCY IS NULL)
)
SELECT 31 as TIPO, 'Site' as DESCRI, Myseq.NEXTVAL,
d.CENTRO, d.CODV, d.TEXT
FROM toinsert d;
I'm not quite sure if that will work. A more guaranteed approach is to use a before insert trigger (or identity column if you are using 12c+). You would increment the value in the trigger.
However, I do agree with Hugh Jones. You should be confident using the sequence to add a unique value to each row and this value will be increasing. Gaps can appear for other reasons, such as deletes. Also, I know that SQL Server can create gaps when doing parallel inserts; I'm not sure if that also happens with Oracle.
I don't believe you have a real problem(the gaps are not really an issue) but you can put a before insert (at row level) trigger on anda table and set sequ there with your sequence generated value.
But keep in mind that this will keep consecutive only the sequ number in a statement. You'll get gaps anyway for other reasons.
UPDATE: as Alex Poole has commented, the insert itself does not generate gaps.
See a test below:
> drop sequence tst_fgg_seq;
sequence TST_FGG_SEQ dropped.
> drop table tst_fgg;
table TST_FGG dropped.
> drop table tst_insert_fgg;
table TST_INSERT_FGG dropped.
> create sequence tst_fgg_seq start with 1 nocycle;
sequence TST_FGG_SEQ created.
> create table tst_fgg as select level l from dual connect by level < 11;
table TST_FGG created.
> create table tst_insert_fgg as
select tst_fgg_seq.nextval
from tst_fgg
where l between 3 and 5;
table TST_INSERT_FGG created.
> select * from tst_insert_fgg;
NEXTVAL
----------
1
2
3
> insert into tst_insert_fgg
select tst_fgg_seq.nextval
from tst_fgg
where l between 3 and 5;
3 rows inserted.
> select * from tst_insert_fgg;
NEXTVAL
----------
1
2
3
4
5
6
6 rows selected

How to split the columns?

Name Nameid
P,q,r,s,t One
A,b,c Two
D,e Three
This is my source table, but i want my target table like this
Name Nameid
P One
Q One
R One
S One
T One
A Two
B Two
C Two
D three
In a case like this, I think it would be more elegant to store the data in a different way.
If you are inserting your rows from a program, try splitting your string there, and insert a few more rows instead.
Let me give you a pseudo code example.
number = "One"
many_letters = "P,Q,R,S,T".split(",")
for(letter in many_letters) {
insert_values(letter, number)
}
Here's one way, lifted from here:
SQL> CREATE TABLE t (name VARCHAR2(20), nameid VARCHAR2(10));
Table created.
SQL> INSERT INTO t VALUES ('P,q,r,s,t','One');
1 row created.
SQL> INSERT INTO t VALUES ('A,b,c' ,'Two');
1 row created.
SQL> INSERT INTO t VALUES ('D,e' ,'Three');
1 row created.
SQL> SELECT nameid
2 , REGEXP_SUBSTR (name, '[^,]+', 1, LEVEL) AS token
3 FROM t
4 CONNECT BY PRIOR nameid = nameid
5 AND REGEXP_INSTR (name, '[^,]+', 1, LEVEL) > 0
6 AND PRIOR DBMS_RANDOM.STRING ('p', 10) IS NOT NULL
7 ;
NAMEID TOKEN
---------- --------------------
One P
One q
One r
One s
One t
Three D
Three e
Two A
Two b
Two c
10 rows selected.
SQL>
Sorry I didn't understand the question it was posted. It's been reformatted since.
Oracle does not have a built in Split function, which is what you need here. The following link shows how to create a custom Split function:
http://srinisreeramoju.blogspot.com/2010/03/oracle-custom-split-function.html
Once you've created the types and the function you would simply call it as:
SELECT
Split(Name, ',') AS Name,
NameID
FROM
YourTable