Get all data contain inscrease number Regexp_like - Oracle - sql

I have a table like this:
enter image description here
Now, I have get all rows formatnbr = 101 using regexp_like(nbr, expression). I'm using regexp_like (nbr, '^\d((\d)1(\1)2(\1)3)') but I have to write 7 expression with 'OR' in where clause:
select * from tbl where regexp(nbr, '^\d((\d)1(\1)2(\1)3)') or regexp(nbr, '^\d((\d)2(\1)3(\1)4)') or ...
How do I using 1 format likely in description column: regexp_like(nbr, '^\dxyx(y+1)x(y+2)') to select? Help me please!
Output:
enter image description here
create table tbl
(
formatnbr NUMBER not null,
nbr VARCHAR2(7),
description VARCHAR2(50)
);
insert into tbl(formatnbr, nbr, description) values (100, '8123456', 'Dx(x+1)(x+2)(x+3)(x+4)(x+5)');
insert into tbl(formatnbr, nbr, description) values (101, '8111213', 'Dxyx(y+1)x(y+2)');
insert into tbl(formatnbr, nbr, description) values (100, '7456789', 'Dx(x+1)(x+2)(x+3)(x+4)(x+5)');
insert into tbl(formatnbr, nbr, description) values (101, '9232425', 'Dxyx(y+1)x(y+2)');
insert into tbl(formatnbr, nbr, description) values (101, '5565758', 'Dxyx(y+1)x(y+2)');
insert into tbl(formatnbr, nbr, description) values (100, '0456789', 'Dx(x+1)(x+2)(x+3)(x+4)(x+5)');
insert into tbl(formatnbr, nbr, description) values (101, '1454647', 'Dxyx(y+1)x(y+2)');
commit;
Thanks,

For:
Dx(x+1)(x+2)(x+3)(x+4)(x+5) you can list the possible values as:
012345|123456|234567|345678|456789
Dxyx(y+1)x(y+2) you can list the possible y values and use backreferences to match the x values as
(\d)(0(\1)1(\1)2|1(\1)2(\1)3|2(\1)3(\1)4|3(\1)4(\1)5|4(\1)5(\1)6|5(\1)6(\1)7|6(\1)7(\1)8|7(\1)8(\1)9)
So your inserts would be:
create table tbl
(
formatnbr NUMBER not null,
nbr VARCHAR2(7),
description VARCHAR2(110)
);
insert into tbl(formatnbr, nbr, description)
SELECT 100, '8123456', '012345|123456|234567|345678|456789' FROM DUAL UNION ALL
SELECT 101, '8111213', '(\d)(0(\1)1(\1)2|1(\1)2(\1)3|2(\1)3(\1)4|3(\1)4(\1)5|4(\1)5(\1)6|5(\1)6(\1)7|6(\1)7(\1)8|7(\1)8(\1)9)' FROM DUAL UNION ALL
SELECT 100, '7456789', '012345|123456|234567|345678|456789' FROM DUAL UNION ALL
SELECT 101, '9232425', '(\d)(0(\1)1(\1)2|1(\1)2(\1)3|2(\1)3(\1)4|3(\1)4(\1)5|4(\1)5(\1)6|5(\1)6(\1)7|6(\1)7(\1)8|7(\1)8(\1)9)' FROM DUAL UNION ALL
SELECT 101, '5565758', '(\d)(0(\1)1(\1)2|1(\1)2(\1)3|2(\1)3(\1)4|3(\1)4(\1)5|4(\1)5(\1)6|5(\1)6(\1)7|6(\1)7(\1)8|7(\1)8(\1)9)' FROM DUAL UNION ALL
SELECT 100, '0456789', '012345|123456|234567|345678|456789' FROM DUAL UNION ALL
SELECT 101, '1454647', '(\d)(0(\1)1(\1)2|1(\1)2(\1)3|2(\1)3(\1)4|3(\1)4(\1)5|4(\1)5(\1)6|5(\1)6(\1)7|6(\1)7(\1)8|7(\1)8(\1)9)' FROM DUAL;
db<>fiddle here

Related

To find passengers travelling more than thrice on the same route in PL/SQL

Here I am creating three tables, one for storing the Train Info. Another for holding onto the Passenger info and the other one to hold the ticket Info.
create table T_Train_Info(
route_no integer primary key,
source varchar2(50),
destination varchar2(50)
)
create table T_Pay_Info(
pax_id integer primary key,
pax_name varchar2(50),
dob date,
gender varchar2(5)
)
create table T_Tkt_Info(
pax_id integer,
route_no integer,
journey_date date,
seat_no varchar2(5),
primary key(pax_id, route_no, journey_date)
)
In the Train_Info table, I am inserting two unique routes with the same source and destination as there can be different routes for the same source and destination. And filling the other tables in the same manner. In the ticket table, I am repeating values because I aim to find the passenger travelling thrice on the same route.
insert into T_Train_Info values(1, 'Chennai', 'Pune');
insert into T_Train_Info values(2, 'Chennai', 'Pune');
insert into T_Train_Info values(3, 'Bangalore', 'Kolkata');
insert into T_Tkt_Info values(100, 1, to_date('11/03/2022', 'DD/MM/YYYY'), 22);
insert into T_Tkt_Info values(100, 1, to_date('14/08/2022', 'DD/MM/YYYY'), 23);
insert into T_Tkt_Info values(100, 1, to_date('29/08/2022', 'DD/MM/YYYY'), 24);
insert into T_Tkt_Info values(102, 3, to_date('22/08/2022', 'DD/MM/YYYY'), 24);
insert into T_Tkt_Info values(100, 1, to_date('27/08/2022', 'DD/MM/YYYY'), 24);
insert into T_Tkt_Info values(100, 2, to_date('28/08/2022', 'DD/MM/YYYY'), 24);
insert into T_Pay_Info values(100, 'A', to_date('11/03/2022', 'DD/MM/YYYY'), 'F');
insert into T_Pay_Info values(101, 'B', to_date('23/09/2023', 'DD/MM/YYYY'), 'M');
insert into T_Pay_Info values(102, 'A', to_date('11/03/2022', 'DD/MM/YYYY'), 'F');
insert into T_Pay_Info values(103, 'D', to_date('23/09/2023', 'DD/MM/YYYY'), 'M');
insert into T_Pay_Info values(104, 'A', to_date('11/03/2022', 'DD/MM/YYYY'), 'F');
insert into T_Pay_Info values(105, 'A', to_date('23/09/2023', 'DD/MM/YYYY'), 'M');
Here's my procedure which keeps returning the error saying 'exact fetch returns more than requested number of rows' at the select statement. What am I doing wrong here?
create or replace procedure pr_pass_route_details(x in T_Train_Info.Source%type, y in T_Train_Info.Destination%type) is
pr_name T_Pay_Info.Pax_Name%type;
begin
for i in (select pax_id from t_tkt_info group by pax_id,route_no having count(*) >=3) loop
select pax_name into pr_name from t_pay_info where pax_id = i.pax_id and T_Train_Info.Source=x and T_Train_Info.Destination=y;
dbms_output.put_line(pr_name);
end loop;
end pr_pass_route_details;
i’m not sure why you’ve written a SP to do this as you can achieve this with a simple query:
SELECT
pax_id,
route_no,
COUNT(journey_date)
FROM T_Tkt_Info
GROUP BY
pax_id,
route_no
HAVING COUNT(journey_date) = 3

Is there any function for insert more than one row with trigger group by some result?

CREATE TABLE TABLE_1 (
ID NUMBER(10),
ID_DOCUMENT NUMBER(10),
ITEM_ID NUMBER(10),
SUPLLIER NUMBER(10)
);
Insert into TABLE_1 (ID, ID_DOCUMENT, ITEM_ID, SUPLLIER) Values (1, 1, 11, 25);
Insert into TABLE_1 (ID, ID_DOCUMENT, ITEM_ID, SUPLLIER) Values (2, 1, 87, 31);
Insert into TABLE_1 (ID, ID_DOCUMENT, ITEM_ID, SUPLLIER) Values (3, 1, 93, 31);
Insert into TABLE_1 (ID, ID_DOCUMENT, ITEM_ID, SUPLLIER) Values (4, 1, 41, 25);
Insert into TABLE_1 (ID, ID_DOCUMENT, ITEM_ID, SUPLLIER) Values (5, 1, 58, 40);
When I insert into table_1 I have to insert the result into two other tables:
create table doc
(
id number(10),
suplier number(10),
date_doc date
);
create table doc_rows
(
id number(10),
id_doc number(10), -- (references doc.id)
item_id number(10)
);
I want to create 3 new records in table doc (because into table_1 we have 3 unique suppliers) and for every new doc I have to insert his items into table doc_rows
-- Create tables
CREATE TABLE TABLE_1 (
ID int identity (1,1) ,
ID_DOCUMENT int,
ITEM_ID int,
SUPLLIER int
);
create table doc
(
id int identity (1,1),
suplier int,
date_doc date
);
create table doc_rows
(
id int identity (1,1),
id_doc int, -- (references doc.id)
item_id int
);
--Create triggers
GO
CREATE TRIGGER trgTABLE_1_Insert ON TABLE_1
FOR INSERT
AS
declare #SUPLLIER int
select #SUPLLIER = SUPLLIER from inserted
if not exists (select 1 from doc where suplier=#SUPLLIER )
Begin
insert into doc (suplier,date_doc)
select #SUPLLIER,GETDATE()
insert into doc_rows (id_doc,item_id)
SELECT (select id from doc where suplier = #SUPLLIER) id_doc ,
(SELECT top 1 ITEM_ID from TABLE_1 where SUPLLIER = #SUPLLIER) item_id
End
Go
-- insert statement
Insert into TABLE_1 ( ID_DOCUMENT, ITEM_ID, SUPLLIER) Values ( 1, 11, 25);
Insert into TABLE_1 ( ID_DOCUMENT, ITEM_ID, SUPLLIER) Values ( 1, 87, 31);
Insert into TABLE_1 ( ID_DOCUMENT, ITEM_ID, SUPLLIER) Values ( 1, 93, 31);
Insert into TABLE_1 ( ID_DOCUMENT, ITEM_ID, SUPLLIER) Values ( 1, 41, 25);
Insert into TABLE_1 ( ID_DOCUMENT, ITEM_ID, SUPLLIER) Values ( 1, 58, 40);
--fianl output
SELECT * from TABLE_1
SELECT * from doc
SELECT * from doc_rows

PL/SQL update all records except with max value

Please help with SQL query. I've got a table:
CREATE TABLE PCDEVUSER.tabletest
(
id INT PRIMARY KEY NOT NULL,
name VARCHAR2(64),
pattern INT DEFAULT 1 NOT NULL,
tempval INT
);
Let's pretend it was filled with values:
INSERT INTO TABLETEST (ID, NAME, PATTERN, TEMPVAL) VALUES (1, 'A', 1, 10);
INSERT INTO TABLETEST (ID, NAME, PATTERN, TEMPVAL) VALUES (2, 'A', 1, 20);
INSERT INTO TABLETEST (ID, NAME, PATTERN, TEMPVAL) VALUES (3, 'A', 2, 10);
INSERT INTO TABLETEST (ID, NAME, PATTERN, TEMPVAL) VALUES (5, 'A', 2, 20);
INSERT INTO TABLETEST (ID, NAME, PATTERN, TEMPVAL) VALUES (4, 'A', 2, 30);
And I need to update all records (grouped by pattern) with NO MAX value TEMPVALUE. So as result I have to update records with Ids (1, 3, 5). Records with IDs (2, 4) has max values in there PATTERN group.
HELP PLZ
This select statement will help you get the IDs you need :
SELECT
*
FROM
(SELECT
id
,name
,pattern
,tempval
,MAX(tempval) OVER (PARTITION BY pattern) max_tempval
FROM
tabletest
)
WHERE 1=1
AND tempval != max_tempval
;
You should be able to build an update statement around that easily enough
Something like this:
update tabletest t
set ????
where t.tempval < (select max(tempval) from tabletest tt where tt.pattern = t.pattern);
It is unclear what values you want to set. The ???? is for the code that sets the values.

Insert same data multiple times

I have an insert statement similar to this:
insert into table (id, name, descr) values (4, 'asdf', 'this is not a word');
I need to insert this same statement with multiple ids. Right now I have:
insert into table (id, name, descr) values (4, 'asdf', 'this is not a word');
insert into table (id, name, descr) values (6, 'asdf', 'this is not a word');
insert into table (id, name, descr) values (7, 'asdf', 'this is not a word');
insert into table (id, name, descr) values (9, 'asdf', 'this is not a word');
Am I just going to have to run this, or is there a more condensed version?
Use a select . . . insert:
insert into table(id, name, descr)
select i.id, 'asdf', 'this is not a word'
from (select 4 as id from dual union all
select 6 from dual union all
select 7 from dual union all
select 9 from dual
) i;
You can use the INSERT ALL statement
INSERT ALL
INTO table (id, name, descr) VALUES (4, 'asdf', 'this is not a word')
INTO table (id, name, descr) VALUES (6, 'asdf', 'this is not a word')
INTO table (id, name, descr) VALUES (7, 'asdf', 'this is not a word')
INTO table (id, name, descr) VALUES (9, 'asdf', 'this is not a word')
SELECT * FROM dual;
INSERT INTO [TableName] (id, name, descr) VALUES
(4, 'asdf', 'this is not a word'),
(6, 'asdf', 'this is not a word'),
(7, 'asdf', 'this is not a word'),
(9, 'asdf', 'this is not a word')
For the sake of argument, one could create a more permanent solution if that ID is also the primary_key by creating a sequence, adding a BEFORE INSERT trigger to the table to increment the ID using the sequence automatically, then loop, inserting however many rows you want and let the ID increment itself:
-- Create the table
CREATE TABLE SEQ_TEST
(
ST_ID NUMBER,
ST_NAME VARCHAR2(50 BYTE),
ST_DESC CHAR(100 BYTE)
);
-- Create the sequence
CREATE SEQUENCE SEQ_TEST_SEQ
START WITH 1
MAXVALUE 9999999999999999999999999999
MINVALUE 0
NOCYCLE
NOCACHE
ORDER;
-- Create the before insert trigger
CREATE OR REPLACE TRIGGER SEQ_TEST_BI
BEFORE INSERT
ON SEQ_TEST
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
BEGIN
if :old.ST_ID is null then
:new.ST_ID := SEQ_TEST_SEQ.nextval;
end if;
END SEQ_TEST_BI;
-- insert 25 rows using an anonymous block. Note the ID is NULL
-- which causes the trigger to increment ID
-- based on the sequence.
begin
for i in 1..25
loop
-- NOTE - Technically you could omit the 'ST_ID' and NULL and it would
-- still work, but I prefer to keep them here to show this action
-- of inserting NULL is intentional and show that all columns are
-- accounted for in the insert.
insert into SEQ_TEST (ST_ID, ST_NAME, ST_DESC) values (NULL, 'asdf', 'this is not a word');
end loop;
end;
commit;
-- Prove it.
select * from seq_test;

Update / Merge table with summing values

I have a schema:
http://sqlfiddle.com/#!4/e9917/1
CREATE TABLE test_table (
id NUMBER,
period NUMBER,
amount NUMBER
);
INSERT INTO test_table VALUES (1000, 1, 100);
INSERT INTO test_table VALUES (1000, 1, 500);
INSERT INTO test_table VALUES (1001, 1, 200);
INSERT INTO test_table VALUES (1001, 2, 300);
INSERT INTO test_table VALUES (1002, 1, 900);
INSERT INTO test_table VALUES (1002, 1, 250);
I want to update the amount field by adding amounts of records which has same (id, period) pair. like after op :
ID| period| amount
1000 1 600
1001 1 200
1001 2 300
1002 1 1150
I Couldn't figure out how :(
EDIT:
In actual case this table is populated by insertion operation from other 2 tables:
CREATE TABLE some_table1(
id NUMBER,
period NUMBER,
amount NUMBER
);
INSERT INTO some_table1 VALUES (1000, 1, 100);
INSERT INTO some_table1 VALUES (1000, 1, 500);
INSERT INTO some_table1 VALUES (1001, 1, 200);
INSERT INTO some_table1 VALUES (1001, 2, 300);
INSERT INTO some_table1 VALUES (1002, 1, 900);
INSERT INTO some_table1 VALUES (1002, 1, 250);
CREATE TABLE some_table2(
id NUMBER,
period NUMBER,
amount NUMBER
);
INSERT INTO some_table2 VALUES (1000, 1, 30);
INSERT INTO some_table2 VALUES (1000, 1, 20);
INSERT INTO some_table2 VALUES (1001, 1, 15);
INSERT INTO some_table2 VALUES (1001, 2, 20);
INSERT INTO some_table2 VALUES (1002, 1, 50);
INSERT INTO some_table2 VALUES (1002, 1, 60);
Dublicates occures when two insertions done:
INSERT INTO TEST_TABLE (id,period,amount) SELECT id,period,amount from some_table1
INSERT INTO TEST_TABLE (id,period,amount) SELECT id,period,amount from some_table2
new sqlfiddle link: http://sqlfiddle.com/#!4/cd45b/1
May be it can be solved during insertion from two table..
A script like this would do what you want:
CREATE TABLE test_table_summary (
id NUMBER,
period NUMBER,
amount NUMBER
);
INSERT INTO test_table_summary (id, period, amount)
SELECT id, period, SUM(amount) AS total_amount FROM test_table
GROUP BY id, period;
DELETE FROM test_table;
INSERT INTO test_table (id, period, amount)
SELECT id, period, total_amount FROM test_table_summary;
DROP TABLE test_table_summary;
But you should actually decide if test_table is to have a primary key and the total amount or all the detail data. It's not a good solution to use one table for both.
By what you have added, then I'd say you can use the Oracle MERGE INTO statement:
MERGE INTO test_table t
USING (SELECT id, period, amount FROM some_table1) s
ON (t.id=s.id AND t.period=s.period)
WHEN MATCHED THEN UPDATE SET t.amount=t.amount+s.amount
WHEN NOT MATCHED THEN INSERT (t.id, t.period, t.amount)
VALUES (s.id, s.period, s.amount);
Beware though... this will work only if test_table already has no duplicate id, period rows to begin with. So if your table is already messed up, you still have to reinitialize it properly a first time (and maybe add a unique id, period key to avoid problems in the future).