Show row number column from result set in oracle sql view - sql

I want to add an extra column so if I get, let's say, 4 rows in the result this column will have values 1,2,3,4.
I've tried ROWNUM, but since this is a view it shows the actual row number in the whole view, and that's not what I want.
Here is a sample schema:
CREATE TABLE TEST (RID NUMBER, RVAL VARCHAR2(100 BYTE));
INSERT INTO TEST (RID, RVAL) VALUES (1, 'ONE');
INSERT INTO TEST (RID, RVAL) VALUES (2, 'TWO');
INSERT INTO TEST (RID, RVAL) VALUES (3, 'THREE');
INSERT INTO TEST (RID, RVAL) VALUES (4, 'FOUR');
CREATE OR REPLACE VIEW VTEST AS
SELECT ROWNUM AS NUMROW, RID, RVAL FROM TEST;
Here are two sample queries. The first shows the result I want. The second how I want to get it (with a simple select against the view)
SELECT ROWNUM,RID,RVAL FROM TEST WHERE RID = 3 OR RID = 4;
SELECT * FROM VTEST WHERE RID = 3 OR RID = 4;
Here is the fiddle: http://sqlfiddle.com/#!4/4e816/3

in oracle use ROW_NUMBER oracle docs

Related

delete certain amount of rows with group by is possible?

So I have in one table called "Park" and another table called "WaterSource". The idea is in each line of Park say how much "waterSources" I have and create that amount of lines in the second table. When I change the value of Park to a minor number (like I had 5 and now I want to have 3) I need to delete the "last" rows of "water source" for the last 2 "Parks".
I need to do something like this,
BEGIN
declare #x int;
set #x = 1;
while #x > 0
BEGIN
delete top (#diff) from [WaterSource]
where [IdView] = #IdView
order by [Park] DESC;
set #x = ##ROWCOUNT;
END
END
I don't know how to do this because the only parameter in these second table is IdView and I just want to "group" all lines for "Park" order by Park Id desc and delete all.
http://www.sqlfiddle.com/#!9/2cbe3fb/1
So my idea is if I change parks number to 1 the lines with idPark 2 should all be deleted and Park 2 will be deleted also. I always delete by the last to the first.
Based on the sample provided I assume that SQL Server is the database engine. The key to my solution is creating a temporary table with a rank or row number column that is created by the windowed function ROW_NUMBER() (More info on windowed functions here: http://www.sqlservertutorial.net/sql-server-window-functions/)
DROP TABLE IF EXISTS #ranker
DECLARE #ParkId INT = 2
DECLARE #newNumWaterSources INT = (SELECT numWaterSources FROM Parks WHERE id = #ParkId)
SELECT
ws.id,
ROW_NUMBER() OVER(ORDER BY ws.id) AS rn
INTO #ranker
FROM WaterSources ws
WHERE idPark = #ParkId
DELETE FROM WaterSources
WHERE idPark = #ParkId
AND id IN
(SELECT id FROM #ranker WHERE rn > #newNumWaterSources)
There are many ways to automate this so that the two variables are populated with the most relevant values. You may want to play around with using an AFTER UPDATE TRIGGER to query the deleted table for the park table id.
This solution would only work if the id column in the WaterSources table is unique. So you would need to change the insert to WaterSources in your fiddle to the following:
INSERT INTO WaterSources VALUES (1, 1, 37);
INSERT INTO WaterSources VALUES (2, 1, 37);
INSERT INTO WaterSources VALUES (3, 1, 37);
INSERT INTO WaterSources VALUES (4, 2, 37);
INSERT INTO WaterSources VALUES (5, 2, 37);
INSERT INTO WaterSources VALUES (6, 2, 37);

Insert into table from select only when select returns valid rows

I want to insert into table from select statement but it is required that insert only happens when select returns valid rows. If no rows return from select, then no insertion happens.
insert into products (name, type) select 'product_name', type from prototype where id = 1
However, the above sql does insertion even when select returns no rows.
It tries to insert NULL values.
I know the following sql can check if row exists
select exists (select true from prototype where id = 1)
How to write a single SQL to add the above condition to insert to exclude the case ?
You are inserting the wrong way. See the example below, that doesn't insert any row since none matches id = 1:
create table products (
name varchar(10),
type varchar(10)
);
create table prototype (
id int,
name varchar(10),
type varchar(10)
);
insert into prototype (id, name, type) values (5, 'product5', 'type5');
insert into prototype (id, name, type) values (7, 'product7', 'type7');
insert into products (name, type) select name, type from prototype where id = 1
-- no rows were inserted.

Select lines where nested table column meets a condition

v is defined as follows: create or replace type v is table of number and emp is a table which contains a column of type v.
I want to select the lines where v.count is 3, but I will get a compilation error. Is it because v.count is PL/SQL code?
I tried putting the code inside an anonymous block but it still didn't work.
Is using cursors the only solution?
SELECT *
FROM emp
WHERE V.COUNT = 3;
Thanks.
I think you're looking for cardinality():
CARDINALITY returns the number of elements in a nested table. The return type is NUMBER. If the nested table is empty, or is a null collection, then CARDINALITY returns NULL.
So you can do:
SELECT *
FROM emp
WHERE cardinality(V) = 3;
Quick demo:
create or replace type v is table of number
/
create table emp (id number, v v)
nested table v store as v_tab;
insert into emp (id, v) values (1, v(1));
insert into emp (id, v) values (2, v(1,2));
insert into emp (id, v) values (3, v(1,2,3));
insert into emp (id, v) values (4, v(1,2,3,4));
column v format a30
set feedback 1
SELECT *
FROM emp
WHERE cardinality(V) = 3;
ID V
---------- ------------------------------
3 V(1, 2, 3)
1 row selected.
I like Alex's cardinality answer, here is another approach:
create or replace type num_type as table of number;
create table table_with_num_type
(
ids num_type,
val varchar2(100)
)
nested table ids store as ids_tab ;
insert into table_with_num_type(ids, val) values (num_type(1,2,3), 'TEST1');
insert into table_with_num_type(ids, val) values (num_type(4,5,6,7), 'TEST2');
commit;
select t.val, count(t2.column_value) as num_count
from table_with_num_type t, table(t.ids) t2
group by t.val
having count(t2.column_value) = 3;
Result:
VAL NUM_COUNT
TEST1 3

How to insert conditionally in Oracle?

I've read here that the syntax looks like this:
INSERT
WHEN ([Condition]) THEN
INTO [TableName] ([ColumnName])
VALUES ([VALUES])
ELSE
INTO [TableName] ([ColumnName])
VALUES ([VALUES])
SELECT [ColumnName] FROM [TableName];
But I don't want to provide values from another table. I just want to type them, so I've got:
INSERT
WHEN EXISTS (SELECT 1 FROM FOO WHERE NAME = 'JOE')
THEN
INTO BAR (NAME, AGE)
VALUES ('JOE', 50)
and this produces exception: ORA-00928: missing SELECT keyword.
I want to perform an insert if given value is found in another table.
Using with select works. Your query wasn't working because there is a problem with values keyword when inserting conditionally.
INSERT
WHEN EXISTS (SELECT 1 FROM FOO WHERE NAME = 'JOE')
THEN
INTO BAR (NAME, AGE)
SELECT 'JOE', 50 FROM DUAL
So, I've found an indirect way here and solution for my question would be:
INSERT INTO BAR (NAME, AGE)
SELECT 'JOE', 50
FROM DUAL
WHERE EXISTS (SELECT 1 FROM FOO WHERE NAME = 'JOE')
but it doesn't explain why I have to use SELECT statement in INSERT WHEN

Why this oracle query returning empty result set?

I have two database tables with some demo data like shown below
Create table demo(uuid int, addressname varchar(50));
insert into demo values(1, 'intersportprofi');
insert into demo values(2, 'intersportprofi');
insert into demo values(3, 'intersportprofi');
insert into demo values(4, 'intersportmarket');
insert into demo values(5, 'intersportmarket');
insert into demo values(6, 'intersportmarket');
create table demo_av(uuid int, testid int, name varchar(50), value varchar(50));
insert into demo_av values(1, 1, 'sport','football basketball cricket');
insert into demo_av values(2, 1, 'brand','reebok addidas nike');
insert into demo_av values(3, 2, 'sport','football basketball ');
insert into demo_av values(4, 2, 'brand','reebok addidas ');
I wrote the following query to get the results from those tables, but oracle returning empty result set.
SELECT d.addressname FROM demo d, demo_av dv
WHERE d.uuid = dv.testid AND d.addressname='intersportprofi'
AND REGEXP_LIKE( dv.value, 'reebok') AND REGEXP_LIKE( dv.value, 'cricket')
Why? where i am doing wrong ? Any help will be greatly appriciated
Change this:
AND REGEXP_LIKE( dv.value, 'reebok') AND REGEXP_LIKE( dv.value, 'cricket')
To this:
AND (REGEXP_LIKE( dv.value, 'reebok') OR REGEXP_LIKE( dv.value, 'cricket'))
Because:
You have no record in the "demo_av" table that matches with "reebok" AND "cricket". The operator you need is "OR" and the parantheses are necessary because of existing of the first condition.
UPDATE
Here is the capture screen of the results:
Cheers
Based on your comments, I think you want a query that will search over multiple rows with same testid. This can be done with joins or like this:
SELECT DISTINCT d.addressname
FROM demo AS d
WHERE d.addressname = 'intersportprofi'
AND EXISTS
( SELECT *
FROM demo_av AS dv
WHERE d.uuid = dv.testid
AND dv.value LIKE '%reebok%'
)
AND EXISTS
( SELECT *
FROM demo_av AS dv
WHERE d.uuid = dv.testid
AND dv.value LIKE '%cricket%'
) ;