How to create ot replace table - teradata

Is there any way in teradata to
CREATE OR REPLACE VOLATILE TABLE
AS
(
SELECT
)
I need to make sure that it does not stop if the table already exists

As a Volatile Table is only visible within the current session you should know which tables have been created.
Otherwise i would simply try a DROP TABLE first and ignore a possible "object does not exist" error.

Short answer: No. Volatile table definitions are not stored in the data dictionary table DBC.Tables. Unlike a Global Temporary table the instantiation of a volatile table is also not tracked by a dictionary table in DBC.TempTables.
Longer answer: You can but it depends on where your SQL is executing.
You can check simply check for the existence of the table using something like SELECT 1 FROM {VolatileTableName} WHERE 1=0; or SELECT 'X' FROM {VolatileTableName] GROUP BY 1; and trap the error if the object doesn't exist. If you don't get an error the object exists. Without knowing where your code is running (BTEQ, Stored Procedure, Macro) it is difficult to explain the appropriate error handling.

Related

Need to get data from a table using database link where database name is dynamic

I am working on a system where I need to create a view.I have two databases
1.CDR_DB
2.EMS_DB
I want to create the view on the EMS_DB using table from CDR_DB. This I am trying to do via dblink.
The dblink is created at the runtime, i.e. DB Name is decided at the time user installs the database, based on the dbname dblink is decided.
My issue is I am trying to create a query like below to create a view from a table which name is decided at run time. Please see below query :
select count(*)
from (SELECT CONCAT('cdr_log#', alias) db_name
FROM ems_dbs a,
cdr_manager b
WHERE a.db_type = 'CDR'
and a.ems_db_id = b.cdr_db_id
and b.op_state = 4 ) db_name;
In this query cdr_log#"db_name" is the runtime table name(db_name get's created at runtime).
When I'm trying to run above query, I'm not getting the desired result. The result of the above query is '1'.
When running only the sub-query from the above query :
SELECT CONCAT('cdr_log#', alias) db_name
FROM ems_dbs a,
cdr_manager b
WHERE a.db_type = 'CDR'
and a.ems_db_id = b.cdr_db_id
and b.op_state = 4;
i'm getting the desired result, i.e. cdr_log#cdrdb01
but when i'm trying to run the full query, getting result as '1'.
Also, when i'm trying to run as
select count(*) from cdr_log#cdrdb01;
I'm getting the result as '24' which is correct.
Expected Result is that I should get the same output similar to the query :
select count(*) from cdr_log#cdrdb01;
---24
But the desired result is coming as '1' using the full query mentioned initially.
Please let me know a way to solve the above problem. I found a way to do it via a procedure, but i'm not sure how can I invoke this procedure.
Can this be done as part of sub query as I have used above?
You're not going to be able to create a view that will dynamically reference an object over a database link unless you do something like create a pipelined table function that builds the SQL dynamically.
If the database link is created and named dynamically at installation time, it would probably make the most sense to create any objects that depend on the database link (such as the view) at installation time too. Dynamic SQL tends to be much harder to write, maintain, and debug than static SQL so it would make sense to minimize the amount of dynamic SQL you need. If you can dynamically create the view at installation time, that's likely the easiest option. Even better than directly referencing the remote object in the view, particularly if there are multiple objects that need to reference the remote object, would probably be to have the view reference a synonym and create the synonym at install time. Something like
create synonym cdr_log_remote
for cdr#<<dblink name>>
create or replace view view_name
as
select *
from cdr_log_remote;
If you don't want to create the synonym/ view at installation time, you'd need to use dynamic SQL to reference the remote object. You can't use dynamic SQL as the SELECT statement in a view so you'd need to do something like have a view reference a pipelined table function that invokes dynamic SQL to call the remote object. That's a fair amount of work but it would look something like this
-- Define an object that has the same set of columns as the remote object
create type typ_cdr_log as object (
col1 number,
col2 varchar2(100)
);
create type tbl_cdr_log as table of typ_cdr_log;
create or replace function getAllCDRLog
return tbl_cdr_log
pipelined
is
l_rows typ_cdr_log;
l_sql varchar(1000);
l_dblink_name varchar(100);
begin
SELECT alias db_name
INTO l_dblink_name
FROM ems_dbs a,
cdr_manager b
WHERE a.db_type = 'CDR'
and a.ems_db_id = b.cdr_db_id
and b.op_state = 4;
l_sql := 'SELECT col1, col2 FROM cdr_log#' || l_dblink_name;
execute immediate l_sql
bulk collect into l_rows;
for i in 1 .. l_rows.count
loop
pipe row( l_rows(i) );
end loop;
return;
end;
create or replace view view_name
as
select *
from table( getAllCDRLog );
Note that this will not be a particularly efficient way to structure things if there are a large number of rows in the remote table since it reads all the rows into memory before starting to return them back to the caller. There are plenty of ways to make the pipelined table function more efficient but they'll tend to make the code more complicated.

Include a hashtag in dbGetQuery()

I'm trying to use RJDBC to connect to a SAP HANA database and query for a temporary table, which is stored with a #-prefix:
test <- dbGetQuery(jdbcConnection,
"SELECT * FROM #CONTROL_TBL")
# Error in [...]: invalid table name: Could not find table/view #CONTROL_TBL in schema USER
If I execute the SQL statement in HANA, it works perfectly fine. I'm also able to query for permanent tables. Therefore I assume that R doesn't pass over the hashtag. Inserting escapes like "SELECT * FROM \\#CONTROL_TBL" however didn't solve my problem.
It's not possible to query for the data of a local or global temporary table from a different session, since they are by definition session-specific. In the case of a global temporary table one can query for the metadata of the table because they are shared across sessions.
Source: Tutorial for HANA temporary tables
You have to double-quote the table because it contains special characters, see SAP Help, identifiers for details.
test <- dbGetQuery(jdbcConnection,
'SELECT * FROM "#CONTROL_TBL"')
See also related discussion on stackoverflow.
Ok, local temporary tables are always only visible to the session in which they've been defined, while global temporary tables are visible just like normal tables, but the data is session private.
So, if you created the local temp. table (name starts with #) in a different session, then no wonder it cannot be found.
For your example, the question is: why do you need a temporary table in the first place?
Instead of that, you could e.g. define a view or a table function to select data from.

sqlite trigger causes "no such column" exception

I'm a newbie with sql triggers and am getting an ESQLiteException on what seems like a simple example. When I try to modify the "memberTag" column in an existing row, I get the exception "no such column: memberTag". If I drop the trigger, the exception goes away and the row gets updated.
I'm using SQLite and I'm using the "SQLite Expert Personal" app to do this experimenting.
I have this table:
CREATE TABLE [znode] (
[description] CHAR NOT NULL,
[memberTag] CHAR);
and this trigger:
CREATE TRIGGER [memberTagTrigger]
AFTER UPDATE
ON [znode]
FOR EACH ROW
WHEN length(memberTag)=0
BEGIN
update znode
set memberTag = null;
END;
My update experiment data is something like this:
description memberTag
one x
two (null)
And when I try to change (null) to "y" using SQLite Expert Personal, it throws the exception.
The problem is in the WHEN clause: the database does not know where memberTag comes from, because there are two possible rows, the old one, and the new one.
Use either OLD.memberTag or NEW.memberTag.
(There is another problem: the UPDATE will change all rows in the table, because you forgot the WHERE clause.)

SQLite - create table if not exists

What is the create table statement in SQLite meant to return?
I have observed create table if not exists returning both a 0 and 1 when the table does in fact exist. Is the return value a reliable indication of whether the table does exist or not? I would expect the statement to return a 0 if the table already exists and a 1 when it does not, similar to an insert statement.
Changes returns the number of affected rows.
This values is meaningless for CREATE TABLE statements.
There is no easy way to determine whether the CREATE TABLE IF NOT EXISTS statement did the creation or not.
You should check beforehand with PRAGMA table_info.
The if not exists syntax makes the command succeed even if the table already exists. It just doesn't do anything.
I'm not sure what you're referring to with "returns 1" unless you're talking about the command-line client. In that case, if you just remove the if not exists from your create statement, the command will return 1 (indicating failure) if the table exists.

Accessing a TEMP TABLE in a TRIGGER on a VIEW

I need to parameterize a view, and I am doing so by creating a TEMP TABLE which has the parameters for the view.
CREATE TEMP TABLE parms (parm1 INTEGER, parm2 INTEGER);
CREATE VIEW tableview AS ...
The VIEW is rather complex, but it basically uses these two parameters to kick start a recursive CTE, and there isn't any other way that I have found to express the view without these parameters.
The parameters must be stored in a temporary table because each connection should be able to have its own view with different parameters.
In any case, this works fine for creating the view itself, so long as I create the same TEMP TABLE at the start of any queries that use the view, e.g.:
CREATE TEMP TABLE parms (parm1 INTEGER, parm2 INTEGER);
INSERT INTO parms (parm1,parm2) VALUES (5,66);
SELECT * FROM tableview;
I am able to do the same thing to create a trigger to allow inserts on the view:
CREATE TEMP TABLE parms (parm1 INTEGER, parm2 INTEGER);
CREATE TRIGGER tableinsert INSTEAD OF INSERT ON tableview ...
However, when I try to do an actual INSERT (re-creating the TEMP TABLE first as before) I get an error:
no such table: main.parms
If I create a non-temporary table, I do not get this error, but then I have the problem that different connections can't have their own separate views.
I have review the documentation for triggers, and it mentions caveats of using temporary triggers on a non-temporary table, but I don't see anything regarding the reverse.
I did find a reference elsewhere that indicated that "the table... must exist in the same database as the table or view to which the trigger is attached". I thought a temporary table was part of the current database, is this not true? Is there some way to make this true?
I also tried accessing the parms table as temp.parms in the TRIGGER, but got the error:
qualified table names are not allowed on INSERT, UPDATE, and DELETE
statements within triggers
If I can't use a temporary table, is there some way to work around it to accomplish the same thing?
Update: Ok, so it seems to be an SQLite limitation. After digging around a bit in the SQLite source code, it seems to be pretty trivial to allow SELECT access to a temporary table in a trigger. However, allowing UPDATE access appears to be a lot harder.
Temporary objects are created in a separate database named temp, so they are not accessible from triggers in other databases.
The remaining mechanism to get a connection-specific value into a trigger is to use a user-defined function.

Resources