Calling a Sybase stored procedure from another stored procedure - stored-procedures

I'm calling a Sybase Stored Proc X that returns data that is used by a servlet.
Within Stored Proc X, Stored Proc get_business_day is called in the following manner:
exec get_business_day #CBDate, -1, #prevBusDay output
So, the result of calling this (in DBArtisan) is:
6/25/2010 12:00:00.000 AM
1 row(s) affected.
The issue is that I do not need this above row to be outputted when executing X, as the output I get (in DBArtisan) is:
6/25/2010 12:00:00.000 AM
-2817773441.669999
This will obviously affect the results obtained by the servlet as it expects only the value -2817773441.669999.
Is there any way to suppress the output of get_business_day appearing when calling X?
Thx
Agnyata

here is the what you want to do:
main proc:
...
create table #tmp(
CBDate datetime
)
EXEC get_business_day #CBDate, -1
select CBDate from #tmp
-- use it
drop table #tmp
-- before end
get_business_day:
create table #tmp(
CBDate datetime
)
go
create proc get_business_day
as
-- find the value to be inserted into #day
insert into #tmp select #day
go
drop table #tmp
go

try capturing the result set in a temp table, something like this:
CREATE TABLE #BadResultSet (DateOf datetime)
INSERT INTO #BadResultSet (DateOf)
EXEC get_business_day #CBDate, -1, #prevBusDay output

Related

Bigquery - parametrize tables and columns in a stored procedure

Consider an enterprise that captures sensor data for different production facilities. per facility, we create an aggregation query that averages the values to 5min timeslots. This query exists out of a long list of with-clauses and writes data to a table (called aggregation_table).
Now my problem: currently we have n queries running that exactly run the same logic, the only thing that differs are table names (and sometimes column names but let's ignore that for now).
Instead of managing n different scripts that are basically the same, I would like to put it in a stored procedure that is able to work like this:
CALL aggregation_query(facility_name) -> resolve the different tables for that facility and then use them in the different with clauses
On top of that, instead of having this long set of clauses that give me the end-result, I would like to chunk them up in logical blocks that are parametrizable, So for example, if I call the aforementioned stored_procedure for facility A, I want to be able to pass / use this table name in these different functions, where the output can be re-used in the next statement (like you would do with with clauses).
Another argument of why I want to chunk this up in re-usable blocks is because we have many "derivatives" on this aggregation query, for example to manage historical data, to correct data or to have the sensor data on another aggregation level. As these become overly complex, it is much easier to manage them without having to copy paste and adjust these every time.
In the current set-up, it could be useful to know that I am only entitled to use plain BigQuery, As my team is not allowed to access the CI/CD / scheduling and repository. (meaning that I cannot solve the issue by having CI/CD that deploys the n different versions of the procedure and functions)
So in the end, I would like to end up with something like this using only bigquery:
CREATE OR REPLACE PROCEDURE
`aggregation_function`()
BEGIN
DECLARE
tablename STRING;
DECLARE
active_table_name STRING; ##get list OF tables CREATE TEMP TABLE tableNames AS
SELECT
table_catalog,
table_schema,
table_name
FROM
`catalog.schema.INFORMATION_SCHEMA.TABLES`
WHERE
table_name = tablename;
WHILE
(
SELECT
COUNT(*)
FROM
tableNames) >= 1 DO ##build dataset + TABLE name
SET
active_table_name = CONCAT('`',table_catalog,'.',table_schema,'.' ,table_name,'`'); ##use concat TO build string AND execute
EXECUTE IMMEDIATE '''
INSERT INTO
`aggregation_table_for_facility` (timeslot, sensor_name, AVG_VALUE )
WITH
STEP_1 AS (
SELECT
*
FROM
my_table_function_step_1(active_table_name,
parameter1,
parameter2) ),
STEP_2 AS (
SELECT
*
FROM
my_table_function_step_2(STEP_1,
parameter1,
parameter2) )
SELECT * FROM STEP_2
'''
USING active_table_name as active_table_name;
DELETE
FROM
tableNames
WHERE
table_name = tablename;
END WHILE
;
END
;
I was hoping someone could make a snippet on how I can do this in Standard SQL / Bigquery, so basically:
stored procedure that takes in a string variable and is able to use that as a table (partly solved in the approach above, but not sure if there are better ways)
(table) function that is able to take this table_name parameter as well and return back a table that can be used in the next with clause (or alternatively writes to a temp table)
I think below code snippets should provide you with some insights when dealing with procedures, inserts and execute immediate statements.
Here I'm creating a procedure which will insert values into a table that exists on the information schema. Also, as a value I want to return I use OUT active_table_name to return the value I assigned inside the procedure.
CREATE OR REPLACE PROCEDURE `project-id.dataset`.custom_function(tablename STRING,OUT active_table_name STRING)
BEGIN
DECLARE query STRING;
SET active_table_name= (SELECT CONCAT('`',table_catalog,'.',table_schema,'.' ,table_name,'`')
FROM `project-id.dataset.INFORMATION_SCHEMA.TABLES`
WHERE table_name = tablename);
#multine query can be handled by using ''' or """
Set query =
'''
insert into %s (string_field_0,string_field_1,string_field_2,string_field_3,string_field_4,int64_field_5)
with custom_query as (
select string_field_0,string_field_2,'169 BestCity',string_field_3,string_field_4,55677 from %s limit 1
)
select * from custom_query;
''';
# querys must perform operations and must be the last thing to perform
# pass parameters using format
execute immediate (format(query,active_table_name,active_table_name));
END
You can also use a loop to iterate trough records from a working table so it will execute the procedure and also be able to get the value from the procedure to use somewhere else.ie:A second procedure to perform a delete operation.
DECLARE tablename STRING;
DECLARE out_value STRING;
FOR record IN
(SELECT tablename from `my-project-id.dataset.table`)
DO
SET tablename = record.tablename;
LOOP
call `project-id.dataset`.custom_function(tablename,out_value);
select out_value;
END LOOP;
END FOR;
To recap, there are some restrictions such as the possibility to call procedures inside a execute immediate or to use execute immediate inside an execute immediate, to count a few. I think these snippets should help you dealing with your current situation.
For this sample I use the following documentation:
Data Manipulation Language
Dealing with outputs
Information Schema Tables
Execute Immediate
For...In
Loops

SQL Server 2017 Stored Procedure wants table variable declared but it already exists

Been a while since I have done any sereious T-SQL. I thought I had this right but I am receiving an error that I cannot figure out the cause of. This is for a stored procedure that is not complex. The code is below:
--======================================================
-- Create Natively Compiled Stored Procedure Template
--======================================================
USE Viper;
GO
-- Drop stored procedure if it already exists
IF OBJECT_ID('API.newCategory','P') IS NOT NULL
DROP PROCEDURE API.newCategory;
GO
CREATE PROCEDURE API.newCategory
-- Add the parameters for the stored procedure here
#Category varchar(20) = null
WITH NATIVE_COMPILATION, SCHEMABINDING
AS BEGIN ATOMIC WITH
(
TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'us_english'
)
--Insert statements for the stored procedure here
DECLARE #tmp int = 0;
IF #Category IS NOT NULL
AND #Category != ''
SET #tmp = ISNULL(
(SELECT idCategory
FROM Products.Category
WHERE Category = #Category),0);
IF #tmp = 0
INSERT INTO Products.Category (Category)
OUTPUT inserted.idCategory INTO #tmp
VALUES (#Category);
ELSE
UPDATE Category
SET active = 1
WHERE idCategory = #tmp;
RETURN #tmp;
END;
GO
The error message that I am receiving is:
Msg 1087, Level 16, State 1, Procedure newCategory, Line 22 [Batch
Start Line 11]
Must declare the table variable "#tmp".
I hope someone can point me in the right direction. I am sure that it is something stupidly simple, I just can't see it right now. A bit rusty I'm afraid.
Just to be clear, the operational goal of the SP is to:
1/ Check that there is actually a Category supplied to work with
2/ If there is then try and get its primary key id (idCategory)
3/ If there is no PK for the Category then insert it and return the idCategory into #tmp
4/ If there is a PK then make sure the active column is set to 1
5/ return #tmp as the result (either the PK or 0)
Cheers and thanks for any help
The Frog
Your problem is in this statement:
IF #tmp = 0
INSERT INTO Products.Category (Category)
OUTPUT inserted.idCategory INTO #tmp
VALUES (#Category);
You are doing an OUTPUT INTO where what you are output into your previously declare #tmp which is declared as an int. OUTPUT statements can only be against tables, temp tables or table variables.
A workaround could be to declare a table variable #catTab: DECLARE #catTab AS TABLE(CatID int) and OUTPUT into that variable followed by a: SELECT #tmp = CatID FROM #catTab. That should do it.

Informix external table pass file name as parameter

I have a stored procedure in Informix that uses external tables to unload data to a disk file from a select statement. Is it possible to give the DISK file name as a parameter to the stored procedure? My stored procedure is as follows:
create procedure spUnloadData(file_name_param varchar(64))
create temp table temp_1(
col_11 smallint
) with no log;
INSERT INTO temp_1 select col1 from data_table;
CREATE EXTERNAL TABLE temp1_ext
SAMEAS temp_1
USING (
--DATAFILES ("DISK:/home/informix/temp.dat")
DATAFILES("DISK:" || file_name_param )
);
INSERT INTO temp1_ext SELECT * FROM temp_1;
DROP TABLE temp1_ext ;
DROP TABLE temp_1;
END PROCEDURE;
I am trying to pass in the DISK filename as a parameter(from my shell script, timestamped).
Any help is appreciated.
NH
You would have to use Dynamic SQL in the stored procedure — for example, the EXECUTE IMMEDIATE statement.
You create a string containing the text of the SQL and then execute it. Adapting your code:
CREATE PROCEDURE spUnloadData(file_name_param VARCHAR(64))
DEFINE stmt VARCHAR(255); -- LVARCHAR might be safer
CREATE TEMP TABLE temp_1(
col_11 SMALLINT
) WITH NO LOG;
INSERT INTO temp_1 select col1 from data_table;
LET stmt = 'CREATE EXTERNAL TABLE temp1_ext ' ||
'SAMEAS temp_1 USING DATAFILES("DISK:' ||
TRIM(file_name_param) ||
'")';
EXECUTE IMMEDIATE stmt;
INSERT INTO temp1_ext SELECT * FROM temp_1;
DROP TABLE temp1_ext;
DROP TABLE temp_1;
END PROCEDURE;
Untested code — the concept should be sound, though.
This assumes you are using a reasonably current version of Informix; the necessary feature is in 12.10, and some version 11.70 versions too, I believe.
I made slight changes to my code to unload data(as Informix default '|' separated fields). Instead of using a temp table, I was able to select columns directly into an external table dynamically.

Informix trigger to change inserted values

I would like to change a couple of column values before they get inserted.
I am using Informix as database.
I have a table consisting of 3 columns: Name (NVARCHAR), Type (INT), Plan (NVARCHAR).
Every time a new record is inserted, I would like to check the Name value before inserting it. If the Name starts with an F, I would like to set the Type value to 1 and the Plan Name to "Test"
In short, what I want the trigger to do is:
For every new insertion, first check if Name value starts with F.
If yes, set the Type and Plan to 1 and "Test" then insert.
If no, insert the values as-is.
I have looked up the CREATE TRIGGER statement with BEFORE and AFTER. However, I would like to have a clearer example. My case would probably involve BEFORE though.
The answer of #user3243781 get close, but did not work because it returns the error:
-747 Table or column matches object referenced in triggering statement.
This error is returned when a triggered SQL statement acts on the
triggering table, or when both statements are updates, and the column
that is updated in the triggered action is the same as the column that
the triggering statement updates.
So the alternative is handle with the NEW variable directly.
For that you need to use a procedure with the triggers reference resource, which means the procedure will able to act like the trigger by self.
Below is my example which I run with dbaccess over a Informix v11.70.
This resource is available only for versions +11 of the engine, as far I remember.
create table teste ( Name NVARCHAR(100), Type INT , Plan NVARCHAR(100) );
Table created.
create procedure check_name_values()
referencing new as n for teste ;;
define check_type integer ;;
define check_plan NVARCHAR ;;
if upper(n.name) like 'F%' then
let n.type = 1;;
let n.plan = "Test";;
end if
end procedure ;
Routine created.
;
create trigger trg_tablename_ins
insert on teste
referencing new as new
for each row
(
execute procedure check_name_values() with trigger references
);
Trigger created.
insert into teste values ('cesar',99,'myplan');
1 row(s) inserted.
insert into teste (name) values ('fernando');
1 row(s) inserted.
insert into teste values ('Fernando',100,'your plan');
1 row(s) inserted.
select * from teste ;
name cesar
type 99
plan myplan
name fernando
type 1
plan Test
name Fernando
type 1
plan Test
3 row(s) retrieved.
drop table if exists teste;
Table dropped.
drop procedure if exists check_name_values;
Routine dropped.
create trigger trg_tablename_ins
insert on tablename
referencing new as new
for each row
(
execute procedure check_name_values
(
new.name,
new.type,
new.plan
)
);
create procedure check_name_values
(
name NVARCHAR,
new_type integer,
new_plan NVARCHAR,
)
define check_type integer ;
define check_plan NVARCHAR ;
let check_type = 1;
let check_plan = "Test";
if name = 'F%'
then
insert into tablename (name,type,plan) values (name,check_type,check_plan);
else
insert into tablename (name,type,plan) values (name,new_type,new_plan);
end if ;
end procedure ;
Here is my version an adaptation of an old example I found in the informix usenet group.
It is possible to update columns in a trigger statement but not very straight forward. You have to use stored procedures an the into statement with the execute procedure command.
It worked here for IBM Informix Dynamic Server Version 12.10.FC11WE.
drop table if exists my_table;
drop sequence if exists my_table_seq;
create table my_table (
id INTEGER
NOT NULL,
col_a char(32)
NOT NULL,
col_b char(20)
NOT NULL,
hinweis char(64),
uslu char(12)
DEFAULT USER
NOT NULL,
dtlu DATETIME YEAR TO SECOND
DEFAULT CURRENT YEAR TO SECOND
NOT NULL
)
;
create sequence my_table_seq
increment 1
start 1;
drop procedure if exists get_user_datetime();
create function get_user_datetime() returning char(12),datetime year to second;
return user, current year to second;
end function
;
drop trigger if exists ti_my_table;
create trigger ti_my_table insert on my_table referencing new as n for each row (
execute function get_user_datetime() into uslu, dtlu
)
;
drop trigger if exists tu_my_table;
create trigger tu_my_table update on my_table referencing new as n for each row (
execute function get_user_datetime() into uslu, dtlu
)
;
insert into my_table values (my_table_seq.nextval, "a", "b", null, "witz", mdy(1,1,1900)) ;
SELECT *
FROM my_table
WHERE 1=1
;

Share table variable between Stored procedure in SQL Server

Is it possible to store the results of a call to exec sp_executesql in a 'table parameter'. The parameter value is used in another SQL Stored procedure (SQL 2000/2005)
Best you can do is insert the values into a temp table (using an INSERT EXEC pattern) and then use that temp table in the second proc down the chain ...
If you are wanting to store the results of some process in a table variable, I would suggest making it a table-value function instead of a sproc. That way you can then use the end-result of the first function in whatever other processing you are doing
Select * from MyTableValueFunction()

Resources