how to get the integer column to integer list in informix - informix

To read an integer column into integer list
create function somedum()
returning int
define s LIST(INTEGER NOT NULL);
select id into s from informix.emptest;
end function
create table emptest(id int)
insert into emptest(id)values(7)
when I execute the above function
iam getting error as attached image

The Informix documentation on inserting elements into a LIST seems misleading to me, as my first impression of the example ( Insert into a LIST ) also led me to use the SELECT INTO syntax and get the same error:
-9634 No cast from integer to set(integer not null)
The SELECT INTO syntax can be used to copy/insert an entire LIST, not elements into the LIST.
To insert an element into the LIST ( or generally manipulate it's elements ) we need to use the Informix virtual table interface, in this case using the TABLE syntax to create a virtual table from the LIST which then can be used to do the usual insert/select/update/delete operations ( Collection-Derived Table ).
CREATE FUNCTION somedum()
RETURNING LIST( INTEGER NOT NULL ) AS alist;
DEFINE my_list LIST( INTEGER NOT NULL );
INSERT INTO TABLE( my_list ) SELECT id FROM emptest;
RETURN my_list;
END FUNCTION;
Executing the function we get:
EXECUTE FUNCTION somedum();
alist LIST{7 }

Related

bigquery sql table function with string interpolation

I am trying to write a BigQuery SQL function / stored procedure / table function that accepts as input:
a INT64 filter for the WHERE clause,
a table name (STRING type) as fully qualified name e.g. project_id.dataset_name.table_name
The idea is to dynamically figure out the table name and provide a filter to slice the data to return as a table.
However if try to write a Table Function (TVF) and I use SET to start dynamically writing the SQL to execute, then I see this error:
Syntax error: Expected "(" or keyword SELECT or keyword WITH but got keyword SET at [4:5]
If I try to write a stored procedure, then it expects BEGIN and END and throws this error:
Syntax error: Expected keyword BEGIN or keyword LANGUAGE but got keyword AS at [3:1]
If I try to add those, then I get various validation errors basically because I need to remove the WITH using CTEs (Common Table Expression), and semicolons ; etc.
But what I am really trying to do is using a table function:
to combine some CTEs dynamically with those inputs above (e.g. the input table name),
to PIVOT that data,
to then eventually return a table as a result of a SELECT.
A bit like producing a View that could be used in other SQL queries, but without creating the view (because the slice of data can be decided dynamically with the other INT64 input filter).
Once I dynamically build the SQL string I would like to EXECUTE IMMEDIATE that SQL and provide a SELECT as a final step of the table function to return the "dynamic table".
The thing is that:
I don't know before runtime the name of this table.
But I have all these tables with the same structure, so the SQL should apply to all of them.
Is this possible at all?
This is the not-so-working SQL I am trying to work around. See what I am trying to inject with %s and num_days:
CREATE OR REPLACE TABLE FUNCTION `my_dataset.my_table_func_name`(num_days INT64, fqn_org_table STRING)
AS (
-- this SET breaks !!!
SET f_query = """
WITH report_cst_t AS (
SELECT
DATE(start) as day,
entity_id,
conn_sub_type,
FROM `%s` AS oa
CROSS JOIN UNNEST(oa.connection_sub_type) AS conn_sub_type
WHERE
DATE(start) > DATE_SUB(CURRENT_DATE(), INTERVAL num_days DAY)
AND oa.entity_id IN ('my-very-long-id')
ORDER BY 1, 2 ASC
),
cst AS (
SELECT * FROM
(SELECT day, entity_id, report_cst_t FROM report_cst_t)
PIVOT (COUNT(*) AS connection_sub_type FOR report_cst_t.conn_sub_type IN ('cat1', 'cat2','cat3' ))
)
""";
-- here I would like to EXECUTE IMMEDIATE !!!
SELECT
cst.day,
cst.entity_id,
cst.connection_sub_type_cat1 AS cst_cat1,
cst.connection_sub_type_cat2 AS cst_cat2,
cst.connection_sub_type_cat3 AS cst_cat3,
FROM cst
ORDER BY 1, 2 ASC
);
This might not be satisfying but since Procedural language or DDL are not allowed inside Table functions currently, one possible way around would be simply using PROCEDURE like below.
CREATE OR REPLACE PROCEDURE my_dataset.temp_procedure(filter_value INT64, table_name STRING)
BEGIN
EXECUTE IMMEDIATE FORMAT(CONCAT(
"SELECT year, COUNT(1) as record_count, ",
"FROM %s ",
"WHERE year = %d ",
"GROUP BY year ",
"; "
), table_name, filter_value);
END;
CALL my_dataset.temp_procedure(2002, 'bigquery-public-data.usa_names.usa_1910_current');

Getting invalid identifier and SQL ignored errors in stored procedure in Oracle

I am trying to create a stored procedure in order to insert some data into some table in Oracle 11g.
For this purpose, I need to read the last amount from the latest insert for that user, and then add it to my new value and save the changes as a new row and if any kind of exception is occurred just rollback. This is what I have come up with so far:
CREATE OR REPLACE PROCEDURE MYTESTDB.INSERT_INTO_TESTBANK
(
ID IN TBLTESTBANK.ID%TYPE,
USERID IN TBLTESTBANK.USERID%TYPE,
TYPE IN TBLTESTBANK.TYPE%TYPE,
AMOUNT IN TBLTESTBANK.AMOUNT%TYPE,
DATETIMESTAMP IN TBLTESTBANK.DATETIMESTAMP%TYPE,
TRANSACTION_ID IN TBLTESTBANK.IDTRANS%TYPE,
TOTAL_MONEY IN TBLTESTBANK.TOTALMONEY%TYPE,
COMPUTED_HASH IN TBLTESTBANK.HASH%TYPE
)
IS
BEGIN
DECLARE
LastAmount TBLTESTBANK.TOTALMONEY%TYPE;
BEGIN
SELECT TBLTESTBANK.TOTALMONEY INTO LASTAMOUNT
FROM
(
SELECT TBLTESTBANK.ID
FROM TBLTESTBANK tblbnk
WHERE tblbnk.USERID = USERID
order by max(tblbnk.DATETIMESTAMP)
)
where ROWNUM<2;
EXCEPTION WHEN NO_DATA_FOUND
THEN LastAmount := 0;
END;
LastAmount := LastAmount+ AMOUNT;
INSERT INTO TBLTESTBANK (ID, USERID, TYPE, LastAmount,
DATETIMESTAMP, IDTRANS, TOTALMONEY, HASH
)
VALUES (ID, USERID, TYPE, AMOUNT, DATETIMESTAMP, TRANSACTION_ID, TOTAL_MONEY, COMPUTED_HASH);
COMMIT;
EXCEPTION WHEN OTHERS
THEN
ROLLBACK;
END;
/
Whenever I try to test it, I get a red wiggly line under the first SELECT , and then he TESTBANK.ID in the inner select statements. For the select command it says, sql statement is ignored, and for the TESTBANK.ID it says invalid identifier!
It also doesn't let me add two variables, and keeps saying LastAmount must be declared.
And these are the errors I get :
Error(19,7): PL/SQL: SQL Statement ignored
Error(22,16): PL/SQL: ORA-00904: "TBLTESTBANK"."ID": invalid identifier
Error(32,3): PLS-00201: identifier 'LASTAMOUNT' must be declared
Error(32,3): PL/SQL: Statement ignored
Error(34,3): PL/SQL: SQL Statement ignored
Error(34,47): PL/SQL: ORA-00904: "LASTAMOUNT": invalid identifier
You have two problems:
In your select statement:
SELECT TBLTESTBANK.ID
FROM TBLTESTBANK tblbnk
WHERE tblbnk.USERID = USERID
order by max(tblbnk.DATETIMESTAMP)
You have given the table TBLTESTBANK the alias tblbnk therefor you must use the alias throughout the statement:
SELECT tblbnk.ID -- use the correct alias here
FROM TBLTESTBANK tblbnk
WHERE tblbnk.USERID = USERID
order by max(tblbnk.DATETIMESTAMP)
Second:
in the INSERT statement you have to list columns not values.
INSERT INTO TBLTESTBANK (ID, USERID, TYPE, LastAmount,
DATETIMESTAMP, IDTRANS, TOTALMONEY, HASH
)
should be:
INSERT INTO TBLTESTBANK (ID, USERID, TYPE, AMOUNT, --- column name instead of variable name
DATETIMESTAMP, IDTRANS, TOTALMONEY, HASH
)
And then of course you need to use LastAmount in the values part, not AMOUNT
In general it's not a good idea to have variables with the same name as columns of tables that you use in the procedure. It's easy to shadow a variable with a column. You should rename the variables to avoid any problems there.
Edit (I didn't notice this at first).
You also have an error in the structure of the code. A stored procedure (or function) does not have a DECLARE section:
Your declaration needs to look like this:
CREATE OR REPLACE PROCEDURE MYTESTDB.INSERT_INTO_TESTBANK
(
....
)
IS
-- no DECLARE
-- variables right after the IS keyword
LastAmount TBLTESTBANK.TOTALMONEY%TYPE;
BEGIN
...
END;
You can try below select query to get latest record.
SELECT TB.TOTALMONEY INTO LASTAMOUNT
FROM
TESTBANK TB
WHERE
TB.USERID=USERID
AND
DATETIMESTAMP= (SELECT MAX (TB2.DATETIMESTAMP) FROM TESTBANK TB2
WHERE TB2.USERID=USERID);

Is it possible to have a DB uniqueness constraint across columns of two tables?

I have a mysql DB with rails, and a column "shorthand" (string) that I'd like to make unique across multiple tables. Is there a way I can do this without making a third table?
Expression
id
shorthand
...
etc
Variable
id
shorthand
...
etc
I want the values in the 'shorthand' columns of both tables to be unique between each other ie. a record shorthand value "xyz" in Expression would be rejected if a Variable with shorthand value "xyz" were to exist in the DB already.
Any thoughts appreciated, even "you have to use a third table" :)
Here an example using a third table:
-- TEMP SCHEMA for testing
DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;
CREATE TABLE shorthand
( shorthand varchar NOT NULL PRIMARY KEY
, one_or_two varchar NOT NULL
);
CREATE TABLE table_one
( one_id INTEGER NOT NULL PRIMARY KEY
, shorthand varchar NOT NULL REFERENCES shorthand(shorthand)
ON DELETE CASCADE ON UPDATE CASCADE
DEFERRABLE INITIALLY DEFERRED
, etc_one varchar
);
CREATE TABLE table_two
( two_id INTEGER NOT NULL PRIMARY KEY
, shorthand varchar NOT NULL REFERENCES shorthand(shorthand)
ON DELETE CASCADE ON UPDATE CASCADE
DEFERRABLE INITIALLY DEFERRED
, etc_two varchar
);
-- Trigger function for BOTH tables
CREATE FUNCTION set_one_or_two( ) RETURNS TRIGGER
AS $func$
BEGIN
IF (TG_OP = 'INSERT') THEN
INSERT INTO shorthand (shorthand, one_or_two)
VALUES(new.shorthand, TG_TABLE_NAME)
;
ELSEIF (TG_OP = 'UPDATE') THEN
UPDATE shorthand SET shorthand = new.shorthand
WHERE shorthand = old.shorthand
;
ELSEIF (TG_OP = 'DELETE') THEN
DELETE FROM shorthand
WHERE shorthand = old.shorthand
;
END IF;
RETURN NULL;
END
$func$ LANGUAGE plpgsql
;
-- Triggers for I/U/D
CREATE CONSTRAINT TRIGGER check_one
AFTER INSERT OR UPDATE OR DELETE
ON table_one
FOR EACH ROW
EXECUTE PROCEDURE set_one_or_two ( )
;
CREATE CONSTRAINT TRIGGER check_two
AFTER INSERT OR UPDATE OR DELETE
ON table_two
FOR EACH ROW
EXECUTE PROCEDURE set_one_or_two ( )
;
-- Some tests (incomplete)
INSERT INTO table_one (one_id,shorthand,etc_one) VALUES (1, 'one' , 'one' );
INSERT INTO table_two (two_id,shorthand,etc_two) VALUES (1, 'two' , 'two' );
SELECT * FROM shorthand;
\echo this should fail
INSERT INTO table_one (one_id,shorthand,etc_one) VALUES (11, 'two' , 'eleven' );
SELECT * FROM shorthand;
UPDATE table_one SET shorthand = 'eleven' WHERE one_id = 1;
SELECT * FROM shorthand;
I think this older article does exactly what you are looking for (simulating multi table constraints):
http://classes.soe.ucsc.edu/cmps180/Winter04/constraints.html
You might also like to investigate postgres CREATE CONSTRAINT TRIGGER using a function similar to the check_nojoin() function in the article.
http://www.postgresql.org/docs/9.0/static/sql-createconstraint.html
Once you have the exact SQL you need you can put it in your rails migration with execute "the required SQL"
An alternative approach is to use a third table 'shorthands' with columns 'shorthand' and 'src'. Define shorthand as the unique primary key on that table. On each of your other two tables define 'src' as a single char field defaulting to 'A' and 'B' on each table respecitively. Add a foreign key constraint on each of your two tables consisting of both 'shorthand' and 'src' and referencing table 'shorthands'. When inserting or updating rows in either of your two tables you need to ensure the 'shorthands' table is updated either explicity as part of your transaction or via a trigger and set both 'shorthand', and 'src' to the respective table ie 'A' or 'B'.
What the foreign key constraints do is ensure that the shorthand value exists in the shorthand's table for the respective src table but because of the uniqueness constraint on just the 'shorthand' column in the shorthand's table if the other table has already defined the shorthand value a key violation will occur thus guaranteeing uniqueness across two (or even more) tables.
Whatever you do, it is best to put the referential integrity into the database, not in orm/active record validations.

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
;

Stored Procedures reading a value of Min()

I am trying to find the minimum value of a primary key column of type (int) in a particular Table
A portion of my Stored Procedure Code:
IF NOT EXISTS
(
SELECT *
FROM Table
)
BEGIN
SELECT *
FROM Table
END
ELSE
BEGIN
SELECT Min(ColumnOne)
FROM Table
END
This is my main code after reading:
if (!reader.Read())
return "EMPTY TABLE";
else
return reader.GetInt32(0).ToString();
My ExecuteReader has no problem but when I got an exception at the statement
reader.GetInt32(0).ToString()
I believe I extract the information wrongly when my tables have more than one entry. What is the correct function I should call from reader to get the number??
i didn't get your Question.
AS you specify min() Value in Question And you wrote max() Function in T-SQL Script.
You Can try below if you want to retrieve next Val of a Column
Select isnull(max(ColumnOne),0)+1 FROM Table
Above Query will return you
1 in case Table is empty
else max current Value+1(Next Available Value)
from Table.

Resources