http://msdn.microsoft.com/en-us/library/ms190346.aspx
It says here in the section under the statement start/end offset that you can use that in conjunction with dm_exec_sql_text to get the currently executing cursor statement. What would be the command for that?
I have a fairly large SP that froze when it reached a cursor logic loop 'while (##fetch_status =0) and I'd like to see if it is the exact executing statement I think it is, and I'd also like to see the parameters for this statement so I can see exactly why the cursor either never exited, or just why the statement inside the loop won't complete. Thanks!
start with this
SELECT * FROM(SELECT session_id,
COALESCE(OBJECT_NAME(s2.objectid),'Ad-Hoc') AS ProcName,
(SELECT TOP 1 SUBSTRING(s2.TEXT,statement_start_offset / 2+1 ,
( (CASE WHEN statement_end_offset = -1
THEN (LEN(CONVERT(NVARCHAR(MAX),s2.TEXT)) * 2)
ELSE statement_end_offset END) - statement_start_offset) / 2+1))
AS sql_statement
FROM sys.dm_exec_requests AS s1
CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS s2 ) x
WHERE sql_statement
NOT like 'SELECT * FROM(SELECT session_id,COALESCE(%'
Related
I have a requirement to check if a cursor was able to get some rows from table A. If yes, then do nothing else pull rows from table B.
Currently there are two stored procedures for now.
I am trying to do this in one stored procedure.
I tried using %ROWCOUNT but it doesn't work(because it will return 0) without changing the location of the cursor.
The issue is that my output is the cursor so I don't want to make any changes to.
If I do a fetch, then it shows error also that the return type has changed.
Any idea how to do this, like even if create a copy the cursor so that the fetch and row count could be done on the copy instead of the output cursor.
Pseudo Example
create or replace PROCEDURE "proc"
(
output OUT SYS_REFCURSOR,
)
.
BEGIN
.
.
OPEN output for select * from A
END
BEGIN
//check if output was empty then
OPEN output for select * from B
.
.
END
Update:
I did as suggested
....
BEGIN
...
OPEN output for
with
A as (select ...),
,B as (select ...),
,C as (select ...),
,D as (select ...)
select * from A
union
select * from B where not exists(select null from A)
union
select * from C where not exists(select null from B)
union
select * from D where not exists(select null from C)
END;
Since I know for sure that either one these tables will have data, I also tried the below
....
BEGIN
...
OPEN output for
with
A as (select ...)
,B as (select ...)
,C as (select ...),
,D as (select ...)
select * from A
union
select * from B
union
select * from C
union
select * from D
END;
But it gives me error now that
Error(64,7): PL/SQL: ORA-01789: query block has incorrect number of result columns
The table structure foe these 4 is diff. So they might return diff columns.
Would join make sense if 3 out of 4 are empty?
It's much better to implement your requirement in the same cursor, because it will use the same point-in-time read consistency: in your approach second open opens cursor for a different time than your first cursor and really data in A and B can change already.
This approach is better:
create or replace PROCEDURE "proc"( output OUT SYS_REFCURSOR,...)
....
BEGIN
...
OPEN output for
with
A as (select ...)
,B as (select ...)
select * from A
union all
select * from B where not exists(select null from A)
END;
Another possible solution is to create pipelined table instead, like:
create or replace function ... return {collection type} PIPELINED as
...flag boolean := true;
begin
....
for i in (select * from A) loop
flag:=false;
pipe row(...)
end loop;
if flag then
for i in (select * from B) loop
flag:=false;
pipe row(...)
end loop;
end if;
end;
/
But as you can see both query are opened at different time too.
I am at a complete loss as to where my issue is. Earlier on I wrote a procedure that compiled fine, however now I notice that if I take the exact code (even copy/paste from the procedure itself), and try to run it again, SQL Developer essentially freezes and it never compiles.
The SQL itself is certainly not the cleanest, and I am aware that I've made it a little more complex than a better programmer would, however if it compiled earlier it should compile again, no? Below is the P/L SQL in case that may help...
create or replace PROCEDURE insert_comments AS
v_blob BLOB; v_record number;
BEGIN
SELECT blob_content INTO v_blob from xlsx_files;
for x in
(select id into v_record from
(SELECT to_number(id) id, name FROM
(WITH xlsx AS
(SELECT
ROW_NR,
COL_NR,
CASE CELL_TYPE
WHEN 'S'
THEN STRING_VAL
WHEN 'N'
THEN TO_CLOB(NUMBER_VAL)
WHEN 'D'
THEN TO_CLOB(TO_CHAR(DATE_VAL, 'DD-MON-YYYY'))
ELSE
TO_CLOB(FORMULA)
END CELL_VAL
FROM
(SELECT * FROM
TABLE(as_read_xlsx_clob.read(v_blob ))
--as_read_xlsx_clob is a function from the As_read_XLSX_CLOB package
)
)
/*The below statement works as a roundabout way of pivoting
the table. Since the data in the file may contain CLOBs, you
can't use the PIVOT function since CLOBs do not support
aggregation. I have commented out the original SQL that used
PIVOT*/
SELECT id_table.id, name_table.name FROM
(SELECT row_nr, cell_val id FROM
(SELECT * FROM xlsx WHERE row_nr > 1) id_table
where id_table.col_nr=1
) id_table
inner join
(SELECT row_nr, cell_val name FROM
(SELECT *
FROM xlsx
--PIVOT (MAX(TO_CHAR(CELL_VAL))
FOR COL_NR IN (1 AS ROW_WID,2 AS NAME)
) ad
WHERE row_nr >1
) name_table
where name_table.col_nr = 2
) name_table
ON id_table.row_nr = name_table.row_nr
)
)
)
loop
v_record := x.id;
INSERT INTO comment_test(id, name)
(SELECT to_number(id) id, name
FROM
(WITH xlsx AS
(SELECT
ROW_NR,
COL_NR,
CASE CELL_TYPE
WHEN 'S'
THEN STRING_VAL
WHEN 'N'
THEN TO_CLOB(NUMBER_VAL)
WHEN 'D'
THEN TO_CLOB(TO_CHAR(DATE_VAL, 'DD-MON-YYYY'))
ELSE TO_CLOB(FORMULA)
END CELL_VAL
FROM
(SELECT * FROM
TABLE(as_read_xlsx_clob.read(v_blob ))
--as_read_xlsx_clob is a function from the As_read_XLSX_CLOB package
)
)
/*The below statement works as a roundabout way of
pivoting the table. Since the data in the file may
contain CLOBs, you can't use the PIVOT function since
CLOBs do not support aggregation. I have commented out
the original SQL that used PIVOT*/
SELECT id_table.id, name_table.name FROM
(SELECT row_nr, cell_val id FROM
(SELECT * FROM xlsx WHERE row_nr > 1) id_table
where id_table.col_nr=1
) id_table
inner join
(SELECT row_nr, cell_val name FROM
(SELECT *
xlsx
--PIVOT (MAX(TO_CHAR(CELL_VAL))
FOR COL_NR IN (1 AS ROW_WID,2 AS NAME)
) ad
WHERE row_nr >1
) name_table
where name_table.col_nr = 2
) name_table
ON id_table.row_nr = name_table.row_nr)
where to_number(id) = v_record
);
end loop;
delete from xlsx_files;
END;
Per William Robertson's comments, the issue was there was another session which was using the procedure. This session was killed and I was able to recompile.
I recently had a problem with some query that massively updated one of my tables and I'm trying to discover what could possibly gone wrong.
I need to know if there is any way to retrieve last ran queries with at least username, and if possibly the #Parameters values.
I searched a lot on the web and found some solutions like:
SELECT
c.session_id, s.host_name, s.login_name, s.status,
st.text, s.login_time, s.program_name, *
FROM
sys.dm_exec_connections c
INNER JOIN
sys.dm_exec_sessions s ON c.session_id = s.session_id
CROSS APPLY
sys.dm_exec_sql_text(most_recent_sql_handle) AS st
WHERE
text LIKE '%YOURPROCHERE%'
ORDER BY
last_read desc
SELECT
SQLTEXT.text, STATS.last_execution_time, *
FROM
sys.dm_exec_query_stats STATS
CROSS APPLY
sys.dm_exec_sql_text(STATS.sql_handle) AS SQLTEXT
WHERE
STATS.last_execution_time > GETDATE()-1
AND sqltext.text LIKE '%YOURPROCHERE%'
ORDER BY
STATS.last_execution_time DESC
But none of those statements helped me out, they didn't returned any results that matches the hour of the error.
I found one query that matches the run hour with my problem and the exact query text that was run. But it does not show me the user and I can't figure out how to look for the username based on the table.
Query:
SELECT *
FROM
(SELECT
COALESCE(OBJECT_NAME(s2.objectid),'Ad-Hoc') AS ProcName,
execution_count,s2.objectid, s1.sql_handle,
s1.plan_handle, s1.query_plan_hash,
(SELECT TOP 1
SUBSTRING(s2.TEXT,statement_start_offset / 2+1 ,
((CASE WHEN statement_end_offset = -1
THEN (LEN(CONVERT(NVARCHAR(MAX),s2.TEXT)) * 2)
ELSE statement_end_offset
END) - statement_start_offset) / 2 + 1)) AS sql_statement,
last_execution_time
FROM
sys.dm_exec_query_stats AS s1
CROSS APPLY
sys.dm_exec_sql_text(sql_handle) AS s2
) x
WHERE
sql_statement NOT like 'SELECT COALESCE(OBJECT_NAME(s2%' AND sql_statement like '%YOURQUERYHERE%'
--and OBJECTPROPERTYEX(x.objectid,'IsProcedure') = 1
ORDER BY
last_execution_time DESC
Any help would be appreciated. Thanks.
You could try looking in the SQL Blackbox Trace that is enabled by default. It captures some of the previous queries executed on the server. It does have a limit and on a busy production server, it's often limited to minutes of data.
DECLARE #filename nvarchar(512);
SELECT #filename = CAST(value as nvarchar(512))FROM fn_trace_getinfo(1) where property = 2;
SELECT * FROM
fn_trace_gettable (#filename, DEFAULT) WHERE TextData IS NOT NULL;
I am having 3 sys_refcursor for 3 different query inside a same loop.
I want to combine the o/p of these 3 cursor and insert into a table.
I am using the below code.here "l_ssc" and "l_nwo" are records.
SELECT shipper_short_code bulk collect
INTO l_ssc
FROM prepayment_ssc
ORDER BY shipper_short_code;
SELECT DISTINCT pmd_client_owner_nwo bulk collect
INTO l_nwo
FROM pp_meter_data ORDER pmd_client_owner_nwo;
FOR i IN 1.. l_ssc.count
LOOP
FOR j IN 1.. l_nwo.count
LOOP
l_query_a70 := 'select * from USER_PAYS_SI_A70 where shipper_short_code =''' || l_ssc(i).ssc ||''' and NWO_SHORT_CODE =''' ||l_nwo(j).nwo ||'''''';
l_query_O35 := 'select * from USER_PAYS_SI_O35 where NWO_SHORT_CODE=''' || l_nwo(j).nwo ||'';
l_query_R21 := 'select * from user_pays_si where SHIPPER_SHORT_CODE =''' || l_ssc(i).ssc ||''' and CLIENT_OWNER=''' || l_nwo(j).nwo ||'';
OPEN o_cursor1 FOR l_query_a70;
OPEN o_cursor2 FOR l_query_035;
OPEN o_cursor3 FOR l_query_r21;
END LOOP;
END LOOP;
/
You will run 3 queries per iteration of the loops, and this is nested inside two loops. So you will run 3 * l_ssc.count * l_nwo.count queries.
A basic principle in writing good plsql is to let the database do the processing for you.
Finding another way to write the queries into one and letting the database do the work of the loops will create a better solution.
I don’t have your tables but a rough stab at the query could be:
select * from (
select upsa.*
from USER_PAYS_SI_A70 upsa
where upsa.shipper_short_code in (SELECT shipper_short_code FROM prepayment_ssc)
and upsa.NWO_SHORT_CODE in (SELECT DISTINCT pmd_client_owner_nwo FROM pp_meter_data)
union all
select upso.*
from USER_PAYS_SI_O35 upso
where upso.NWO_SHORT_CODE in (SELECT DISTINCT pmd_client_owner_nwo FROM pp_meter_data)
union all
select ups.*
from user_pays_si ups
where ups.SHIPPER_SHORT_CODE in (SELECT shipper_short_code FROM prepayment_ssc)
and ups.CLIENT_OWNER in (SELECT DISTINCT pmd_client_owner_nwo FROM pp_meter_data)
) so_far
order by so_far.SHIPPER_SHORT_CODE, so_far.NWO_SHORT_CODE
This won’t work but with some experimentation I am sure you can build a single query which gets the required results.
Lets say I have many sql statements like this one:
select *
from [A]
where a in (
select a
from [B]
where b = 'c'
)
order by d;
Since my database is huge, I just need to determine how many rows this query will fetch. Of course I can really fetch all rows and count it but my intention is to avoid fetching since that would be a big overhead.
I have tried to extend query as follows:
select count (*)
from (
select *
from [A]
where a in (
select a
from [B]
where b = 'c'
)
order by d
) as table;
That works fine for some tables but for some (like this one in example) SQL server throws this:
The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified.
Consider that I'm not allowed to change any original query, I can just extend it...
Any idea?
Thanks.
EDIT: I'm pretty sure there is some solution related to ##ROWCOUNT field, but not sure how to use it...
Just remove the order by in the subquery. It doesn't affect the number of rows:
select count(*)
from (select *
from [A]
where a in (select a from [B] where b = 'c')
) as table;
Actually, this is better written as:
select count(*)
from [A]
where a in (select a from [B] where b = 'c')
That is, just replace the select * with select count(*).
Finally, if you have to keep the queries the same, then use top 100 percent:
select count(*)
from (select top 100 percent *
from [A]
where a in (select a from [B] where b = 'c')
order by d
) as table;
This does require changing the original queries, but in a way that does not affect what they output and does allow them to be used as ctes/subqueries.
You are allowed to use order by in subqueries when you also use top.
EDIT:
If you are using dynamic SQL, you might have to do something like:
#sql = 'select count(*) from (' +
(case when #sql not like 'SELECT TOP %'
then stuff(#sql, 1, 7, 'SELECT top 100 percent')
else #sql
end) +
+ ')';
The logic could be a bit more complicated if your SQL is not well formatted.