PL/SQL count(*) behaves differently in SQL - sql

I have an empty table.
If I execute
select count(*) from table;
it returns 0;
However in PL/SQL, Sql*Plus
declare
c number;
begin
select count(*) into c from table;
dbms_output.put_line(c);
end;
Returns 572.
What's going on?
------------------------------------------SOLVED----------------------------------
So I had to do
delete from table;
in Sql*Plus, not in Toad.
However, I ran commit in both of them..

Commit or rollback transactions. It seems that you have been working with the table. Without commit/rollback In different sessions you will have different results.

Are you sure the SQL table has rows in it? The syntax looks correct for the SQL select. I imagine "table" will be your table name like: tblProducts? "Table" is a reserved keywork in MS SQL

Try to use i.e.:
DECLARE
c NUMBER(10) := 0;
and then:
SELECT COUNT(1) INTO c FROM table;

Related

Can I transfer SQL Query into a FUNCTION?

Currently, I have some SQL queries which looks like this:
Drop Table X;
Create Table X(id INTEGER);
Insert Into X
select ..
from..
where a.name = GIVENNAME;
Select SUM(..)
from ..
..
order by date desc;
And I want to put all these into a SQL Function, where I can choose the Parameter "GIVENNAME" when I call the function.
Is there a way to make this possible?
I would know how to do it in JSON/Java, but I have really no clue how to make it as a Function in SQL (using Oracle).
Edit:
After pointing out some things, I want to add my current code:
DROP TABLE TEMPTABLE;
CREATE TABLE TEMPTABLE
(mitID INTEGER);
INSERT INTO TEMPTABLE
select m.mitid
from mitarbeiter m
inner join abteilungen a on m.abt = a.abtid
where a.abtname = #GIVENNAME;
select SUM(g.kosten)
from gehaelter g
left outer join gehaelter k
on g.mitarbeiter = k.mitarbeiter
and g.vondatum < k.vondatum
where k.mitarbeiter is null AND g.mitarbeiter in (select * from TEMPTABLE)
order by g.vondatum desc;
I'm currently more interested in a working solution than a nice & clean one
Fortunately you can have both:
create or replace function get_sum_kosten
( p_givenname in abteilungen.abtname%type )
return number
as
return_value number;
begin
select SUM(g.kosten)
into return_value
from gehaelter g
left outer join gehaelter k
on g.mitarbeiter = k.mitarbeiter
and g.vondatum < k.vondatum
where k.mitarbeiter is null
AND g.mitarbeiter in (select m.mitid
from mitarbeiter m
inner join abteilungen a on m.abt = a.abtid
where a.abtname = P_GIVENNAME
)
;
return return_value;
end;
Possible? Yes. Recommended? No.
For any DDL, you'd have to use dynamic SQL (EXECUTE IMMEDIATE). If queries are complex, those commands will be difficult to maintain.
INSERT is a DML, but you can't use it in a function, unless it is an autonomous transaction (and you'll have to commit (or rollback) within the function).
If it were a procedure, you'd - at least - avoid the last problem I mentioned. If you're returning something, use an OUT parameter.
Can't you use a (global) temporary table, instead? Create it once, use it many times. I understand that your code might be very complex and maybe it really can't fit into a single SELECT statement, but you should - at least - try to do that job in an Oracle spirit (i.e. it is not MS SQL Server).
example of procedure
https://www.sitepoint.com/stored-procedures-mysql-php/
like this
DELIMITER $$
CREATE PROCEDURE `avg_sal`(out avg_sal decimal)
BEGIN
select avg(sal) into avg_sal from salary;
END

How to obtain only one specific NEXTVAL result in an Oracle query?

In my stored proc, I run a query like soi :
SELECT NETWORKOWNER.BUS_SEQ.NEXTVAL#LEGACYSMITH.WORLD
FROM TBLDECIDERCONTRACT#LEGACYSMITH.WORLD
WHER PROVID = 28938
How would obtaon only one NEXTVAL result?
Using dual:
SELECT NETWORKOWNER.BUS_SEQ.NEXTVAL#LEGACYSMITH.WORLD FROM dual
Or more generally: make sure your FROM and WHERE clauses result in just one row found - then NEXTVAL will be executed just once.
In addition, you can always get just a single NEXTVAL execution by invoking it natively in PL/SQL, as in:
DECLARE
l_seq INTEGER;
BEGIN
l_seq := my_sequence.NEXTVAL;
END;

Repeating SQL queries

I am running same query for different values. Such as I am querying the table for aa, bb, cc, dd, ee ... Is there any way like as function and use parameters rather than duplication my codes 10 times only for one variable changes.
I am pretty new, and don't know what to name of my solution. I do appreciate any ideas, or let me know if you need more details.
I am using toad for oracle, and need oracle sql solution.
You can write a simple query like this
select * from table where value in ('aa','bb','cc','dd','ee')
IF need to function you can use below sample :
FUNCTION GET_values( Any arguments to that query)
RETURN VARCHAR2
IS
BEGIN
SELECT value
INTO v_value
FROM table
WHERE condition;
RETURN v_value;
END GET_values;
You can use a cursor for the solution.
declare
cursor c1(value1 varchar) is
select columns from tab1
where column1= value1;
l_columns varchar2;
begin
OPEN c1(aa);
fetch c1 into l_columns ;
close c1;
end;

Select from table that does not exist

I have a question regarding ORACLE, I wrote a PLSQL CODE that checks if a table exists, if it exists then I select something from this table..pseudocode is like:
if (table exists)
Select from table where....
the problem is that I always get an error if the table does not exist, even if the if condition is never met and the select statement is never executed.
I think it is because my code is checked at compile time: "select from.." and then it prints an error if the table does not exist. How can I solve such an issue?.. here is how my code looks like (I used generic names):
DECLARE
v_table_exists NUMBER;
BEGIN
SELECT NVL(MAX(1), 0)
INTO v_table_exists
FROM ALL_TABLES
WHERE TABLE_NAME = 'TABLE_TEST';
IF v_table_exists = 1 THEN
INSERT INTO MY_TABLE(COLUMN1, COLUMN2, COLUMN3, COLUMN4)
SELECT 1234,
5678,
T.COLUMN_TEST1,
T.COLUMN_TEST2
FROM TABLE_TEST T
WHERE T.FLAG = 1;
END IF;
END;
The issue is exactly in the fact that your procedure con not be compiled as it refers to a non existing object; you may need some dynamic SQL for this; for example:
create or replace procedure checkTable is
vCheckExists number;
vNum number;
begin
-- check if the table exists
select count(1)
into vCheckExists
from user_tables
where table_name = 'NON_EXISTING_TABLE';
--
if vCheckExists = 1 then
-- query the table with dynamic SQL
execute immediate 'select count(1) from NON_EXISTING_TABLE'
into vNum;
else
vNum := -1;
end if;
dbms_output.put_line(vNum);
end;
The procedure compiles even if the table does not exist; if you call it now, you get:
SQL> select count(1) from NON_EXISTING_TABLE;
select count(1) from NON_EXISTING_TABLE
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> exec checkTable;
-1
PL/SQL procedure successfully completed.
Then, if you create the table and call the procedure again:
SQL> create table NON_EXISTING_TABLE(a) as select 1 from dual;
Table created.
SQL> exec checkTable;
1
PL/SQL procedure successfully completed.
The same way I showed a SELECT, you can do an UPDATE or whatever SQL query you need; if you do something different from a SELECT, the INTO clause has to be removed.
For example, say you need to insert into a different table, the above code should be edited this way:
if vCheckExists = 1 then
execute immediate 'insert into target(a, b, c) select a, 1, 100 from NON_EXISTING_TABLE';
end if;
Everything will need to be done in Dynamic SQL (DBMS_SQL) or EXECUTE_IMMEDIATE otherwise your code will never compile (or package will be invalided) if table does not exists.
DBMS_SQL Example
EXECUTE_IMMEDIATE Example
According to this article, in Oracle Database Server static SQL is indeed checked at compile time to ensure referenced objects exist.
So I advise you to use dynamic SQL instead of static SQL, through a varchar for example.

plsql - get first row - which one is better?

LV_id number;
Cursor CR_test Is
select t.id
from table1 t
where t.foo = p_foo
order by t.creation_date;
Open CR_test;
Fetch CR_test
Into LV_id;
Close CR_test;
or this one :
select x.id
from(select t.id
from table1 t
where t.foo=p_foo
order by t.creation_date) x
where rownum = 1
Both above make similar result but i need known about which one is more efficient!
This is Tom Kyte's mantra:
You should do it in a single SQL statement if at all possible.
If you cannot do it in a single SQL Statement, then do it in PL/SQL.
If you cannot do it in PL/SQL, try a Java Stored Procedure.
If you cannot do it in Java, do it in a C external procedure.
If you cannot do it in a C external routine, you might want to seriously think about why it is you need to do it…
http://tkyte.blogspot.com/2006/10/slow-by-slow.html
Easiest way to find out in this case is to test your queries.
Make sure to test this yourself, indexes and data in your table may produce different results with your table.
Without any index, it looks like there is a better approach using analytic function DENSE_RANK:
SELECT MIN(id) KEEP (DENSE_RANK FIRST ORDER BY creation_date)
INTO lv_id
FROM table1
WHERE foo = p_foo;
I used the following code to test the time consumed by your queries (execute this block several times, results may vary):
DECLARE
p_foo table1.foo%TYPE := 'A';
lv_id table1.id%TYPE;
t TIMESTAMP := SYSTIMESTAMP;
BEGIN
FOR i IN 1 .. 100 LOOP
-- Query here
END LOOP;
dbms_output.put_line(SYSTIMESTAMP - t);
END;
Results:
Using cursor, fetching first row:
2.241 s
Using query with ROWNUM:
1.483 s
Using DENSE_RANK:
1.168 s