Is there a way to perform an ALTER SESSION SET time_zone='America/New_York' within a stored procedure/package? I want to change the session TZ to NY then return it back to what it was before.
SQL> begin
2 execute immediate 'alter session SET TIME_ZONE=''America/New_York''';
3 end;
4 /
PL/SQL procedure successfully completed
SQL> select sessiontimezone from dual
2 /
SESSIONTIMEZONE
---------------------------------------------------------------------------
America/New_York
SQL>
Related
I have a view in Snowflake that uses session variables (date ranges) within it. I want to call the view from a procedure and define the session variables based on the arguments passed to the procedure. Unfortunately the below isn't working....any ideas?
CREATE PROCEDURE TEST_PROCEDURE(DATE_FROM_a DATE, DATE_TO_a DATE)
RETURNS TABLE()
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
SET DATE_FROM = :DATE_FROM_a;
res resultset default (SELECT TOP 100 * FROM v_TEST);
BEGIN
return table(res);
END;
$$
;
The way it's written in your test, it's not actually executing the SET command statement. You can move the SET command statement to after the BEGIN. That will set the session variable. Note that setting session variables in stored procedures is only supported when executing with callers rights.
create or replace table v_test (s string);
CREATE or replace PROCEDURE TEST_PROCEDURE(DATE_FROM_a DATE, DATE_TO_a DATE)
RETURNS TABLE()
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
res resultset default (SELECT TOP 100 * FROM v_TEST);
BEGIN
SET DATE_FROM = :DATE_FROM_a;
return table(res);
END;
$$
;
call test_procedure('2012-12-12', '2020-05-01');
select $DATE_FROM;
I made a procedure that uses a cursor to generate a report. It is designed to return products with p_qoh > avg(p_qoh).
When i run the cursor on its own outside of the procedure, APEX tells me
PLS-00204: function or pseudo-column 'AVG' may be used inside a SQL
statement only
How is this not inside a SQL statement? Im new to SQL just a required class as a comp sci major.
Heres the whole block. If you run just the cursor you will see what I mean.
CREATE OR REPLACE PROCEDURE prod_rep
IS
CURSOR cur_qoh IS
SELECT p_qoh, p_descript, p_code
FROM xx_product;
TYPE type_prod IS RECORD(
prod_qoh xx_product.p_qoh%TYPE,
prod_code xx_product.p_code%TYPE,
prod_descr xx_product.p_descript%TYPE);
rec_prod type_prod;
BEGIN
OPEN cur_qoh;
LOOP
FETCH cur_qoh INTO rec_prod;
EXIT WHEN cur_qoh%NOTFOUND;
IF rec_prod.prod_qoh > avg(rec_prod.prod_qoh) THEN
DBMS_OUTPUT.PUT_LINE(rec_prod.prod_code||' -> '||rec_prod.prod_desc);
END IF;
END LOOP;
CLOSE cur_qoh;
END;
UPDATE: working block
BEGIN
FOR cur_r IN (SELECT p_qoh, p_descript, p_code FROM xx_product
WHERE p_qoh > (SELECT avg(p_qoh) FROM xx_product))
LOOP
DBMS_OUTPUT.PUT_LINE(cur_r.p_code||' -> '|| cur_r.p_descript);
END LOOP;
END;
Well, yes - this is (PL/)SQL, but you just can't use AVG that way. Have a look: this is an example based on Scott's schema.
Average salary is
SQL> select avg(sal) from emp;
AVG(SAL)
----------
2077,08333
In order to select salaries higher than the average one, you'd use a subquery. Let's call this query the "A" query (for future reference):
SQL> select ename, sal
2 from emp
3 where sal > (select avg(sal) from emp);
ENAME SAL
---------- ----------
JONES 2975
BLAKE 2850
CLARK 2450
KING 5000
FORD 3000
SQL>
Also, no need to declare that much things - a simple cursor FOR loop is easier to maintain:
SQL> create or replace procedure prod_rep as
2 begin
3 for cur_r in (select ename, sal from emp
4 where sal > (select avg(sal) from emp))
5 loop
6 dbms_output.put_line(cur_r.ename ||' '|| to_char(cur_r.sal, '9990'));
7 end loop;
8 end;
9 /
Procedure created.
SQL> begin prod_rep; end;
2 /
JONES 2975
BLAKE 2850
CLARK 2450
KING 5000
FORD 3000
PL/SQL procedure successfully completed.
SQL>
See? No need to declare a cursor (OK, you do use that SELECT in a loop), type & record of that type, open the cursor, worry when to exit a loop, close the cursor.
Your code, however, doesn't make much sense in Apex environment. There's no DBMS_OUTPUT there, and it is rather unusual to create a report (either a classic or interactive one) using a procedure; I've never done that. I've used a function (which is a PL/SQL code) that returns a SQL query and based reports on that.
Your problem is a simple one, so - use the Wizard, create a report and - as its source - use the "A" query (I mentioned earlier). That's all you should do.
At that point you're into PL/SQL, not SQL.
You could use the analytic function AVG into your SQL query to get the average:
CURSOR cur_qoh IS
SELECT p_qoh, p_descript, p_code, AVG(p_goh) OVER () as p_goh_avg
FROM xx_product;
You can add your new field to type_prod:
TYPE type_prod IS RECORD(
prod_qoh xx_product.p_qoh%TYPE,
prod_code xx_product.p_code%TYPE,
prod_descr xx_product.p_descript%TYPE,
prod_avg xx_product.p_qoh%TYPE)
;
And then you can use your average into the LOOP:
IF rec_prod.prod_qoh > rec_prod.prod_avg THEN
It doesn't make sense to use AVG inside a PL/SQL loop. PL/SQL is procedural, at that point you're not dealing with the whole set of data: you manage only one row at a time. Whereas SQL deals with sets of data.
Using the analytic function, you get the average of the column on every row, so you can manage it inside the PL/SQL loop.
I have a table which has a clob column. And in the clob column I have a package which I would like to be compiled without manually intervention.Can anyone tell me if this is possible or not in PLSQL.
Note: The package in the clob column is not already present in the database. This is something new which I want to be compiled.
Not sure what you mean by "without manual intervention", but yes you can create an object e.g. package from data stored in a CLOB column. for example:
insert into mytable (id, clob_col) values
(1, 'create or replace package p1 as procedure proc1; end;');
commit;
Then
declare
clob_val clob;
begin
select clob_col into clob_val
from mytable
where id = 1;
execute immediate clob_val;
end;
Of course, a package has two parts, the specification and the body. So you ideally need to store these separately (e.g. 1 row for the spec and another for the body). If they were within the same CLOB value then you would need to parse the CLOB value and extract them singly before running the execute immediate.
If there were several PL/SQL procedures in a table, you'd use a loop. Here's an example:
SQL> create table test (id number, col clob);
Table created.
SQL> insert into test values
2 (1, 'create or replace package pkg_test as ' ||
3 ' function today return date; ' ||
4 'end;'
5 );
1 row created.
SQL> insert into test values
2 (2, 'create or replace package body pkg_test as ' ||
3 ' function today return date is ' ||
4 ' begin ' ||
5 ' return sysdate; ' ||
6 ' end; ' ||
7 ' end;'
8 );
1 row created.
SQL> declare
2 cursor c1 is
3 select id, col
4 from test
5 order by id;
6 c1r c1%rowtype;
7 begin
8 open c1;
9 loop
10 fetch c1 into c1r;
11 exit when c1%notfound;
12
13 execute immediate(c1r.col);
14 end loop;
15 close c1;
16 end;
17 /
PL/SQL procedure successfully completed.
SQL> select pkg_test.today from dual;
TODAY
----------------
30.01.2018 12:50
SQL>
WooHoo! It works!
I've created one of many stored procedures as part of an ETL process and one of the queries within a stored procedure isn't executing.
The environment is SQL Server 2012 SP2.
The bizarre thing is this -
Run the select part of the insert (affected query) - returns rows
Run the insert (affected query) - inserts rows
Run the whole stored procedure via SSMS - inserts rows
Run via SSIS - all other queries run barring the one of concern!
There are no conditions in my stored procedure e.g. if x = True the Return and no debug code is in there either e.g. return. There are also no transactions and the table I am reading from is a staging table populated prveiously by a data flow.
The query:
INSERT INTO Person.CustomerLinks
(PersonID, SystemID, CustomerID_bin, CustomerActive)
SELECT i.PersonID
, s.SystemDefID
, i.CustomerID_bin
, 0
FROM Staging.IdentifyOutput i
JOIN Config.SystemDef s ON s.OutputType = i.OutputType
WHERE i.CustomerID_bin IS NOT NULL
AND i.OutputType IN ('L', 'X')
AND i.PersonID > 0
AND i.FileDuplicate = 1
AND i.PreferredRecord = 1
AND NOT EXISTS ( SELECT 1
FROM Person.CustomerLinks cl
WHERE cl.PersonID = i.PersonID
AND cl.CustomerID_bin = i.CustomerID_bin)
The procedure has a Try Catch block and the Catch will raise an error and no error is raised.
The only other non ETL code in the procedure is -
SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
But I put this in all of my procedures in this application as I am not concerned about dirty reads as they won't happen.
I placed tsql directly after the insert to write to my audit system and ##RowCount was 0. Yet if I run the select now I get over 1.5 million rows back.
Any suggestions?
If you are using a Execute T-SQL task then please try replacing it with the Execute SQL Task.
I don't know what caused it, but I moved the specific SQL into another stored procedure and it worked. In reality, it warranted being in its own stored procedure by right as it was only semi related to the procedure in question.
I have a table with 3 column's in a table on a MS SQL 2008 Database
ID
ToolID
Count
Can someone toss me a script that will create a stored procedure that accepts the param ToolID and increases its value by 1?
All of my efforts have failed.
try:
CREATE PROCEDURE IncrementToolCount
(
#ToolID int
)
AS
SET NOCOUNT ON
UPDATE Tools_Usage SET [Count]=ISNULL([Count],0)+1 WHERE ToolID=#ToolID
GO