DB2 SQL statement - is it possible to A) declare a temporary table B) populate it with data then C) run a select statement against it? - sql

I have read only access to a DB2 database and i want to create an "in flight/on the fly" or temporary table which only exists within the SQL, then populate it with values, then compare the results against an existing table.
So far I am trying to validate the premise and have the following query compiling but failing to pick anything up with the select statement.
Can anyone assist me with what I am doing wrong or advise on what I am attempting to do is possible? (Or perhaps a better way of doing things)
Thanks
Justin
--Create a table that only exists within the query
DECLARE GLOBAL TEMPORARY TABLE SESSION.TEMPEVENT (EVENT_TYPE INTEGER);
--Insert a value into the temporary table
INSERT INTO SESSION.TEMPEVENT (EVENT_TYPE) VALUES ('1');
--Select all values from the temporary table
SELECT * FROM SESSION.TEMPEVENT;
--Drop the table so the query can be run again
DROP TABLE SESSION.TEMPEVENT;

If you look at the syntax diagram of the DECLARE GLOBAL TEMPORARY TABLE statement, you may note the following block:
.-ON COMMIT DELETE ROWS---.
--●--+-------------------------+--●----------------------------
'-ON COMMIT PRESERVE ROWS-'
This means that ON COMMIT DELETE ROWS is default behavior. If you issue your statements with the autocommit mode turned on, the commit statement issued automatically after each statement implicitly, which deletes all the rows in your DGTT.
If you want DB2 not to delete rows in DGTT upon commit, you have to explicitly specify the ON COMMIT PRESERVE ROWS clause in the DGTT declaration.

Related

There is already an object named '#tmptable' in the database

I´m trying to execute stored procedure but I get an issue of an existing temporal table, but I just create one time and use into another part of code
SELECT ...
INTO #tmpUnidadesPresupuestadas
FROM proce.table1
--Insertar in table src..
INSERT INTO table (
....)
SELECT
....
FROM
#tmpUnidadesPresupuestadas
I get this message:
There is already an object named
'#tmpUnidadesPresupuestadas' in the database.
How can I solve it? Regards
A temp table lives for the entirety of the current session. If you run this statement more than once, then the table will already be there. Either detect that and truncate it, or before selecting into it drop it if it exists:
DROP TABLE IF EXISTS #tmpUnidadesPresupuestadas
If prior to SQL Server 2016, then you drop as such:
IF OBJECT_ID('tempdb.dbo.#tmpUnidadesPresupuestadas', 'U') IS NOT NULL
DROP TABLE #tmpUnidadesPresupuestadas;
Without seeing more of the code, it's not possible to know if the following situation is your problem, but it could be.
When you have mutually exclusive branches of code that both do a SELECT...INTO to the same temp table, a flaw causes this error. SELECT...INTO to a temp table creates the table with the structure of the query used to fill it. The parser assumes if that occurs twice, it is a mistake, since you can't recreate the structure of the table once it already has data.
if #Debug=1
select * into #MyTemp from MyTable;
else
select * into #MyTemp from MyTable;
While obviously not terribly meaningful, this alone will show the problem. The two paths are mutually exclusive, but the parser thinks they may both get executed, and issues the fatal error. You extend that, wrapping each branch in a BEGIN...END, and add the drop table (conditional or not) and the parser will still give the error.
To be fair, in fact both paths COULD be executed, if there were a loop or GOTO so that one time around #Debug = 1, and the other time it does not, so it may be asking too much of a parser. Unfortunately, I don't know of a workaround, and using INSERT INTO instead of SELECT INTO is the only way I know to avoid the problem, even though that can be terribly onerous to name all the columns in a particularly column-heavy query.
I am a bit unclear as to what you are attempting. I assume you don't want to drop the table at this point. I believe the syntax you may be looking for is
Insert Into
Insert into #tmpUnidadesPresupuestadas (Col1, col2, ... colN)
Select firstcol, secondcol... nthCol
From Data
If you do indeed wish to drop the table, the previous answers have that covered.
This might be useful for someone else, keep in mind that If more than one temporary table is created inside a single stored procedure or batch, they must have different names. If you use the same name you won't be able to ALTER the PROCEDURE.
https://learn.microsoft.com/en-us/previous-versions/sql/sql-server-2012/ms174979(v=sql.110)#temporary-tables
Make sure the stored procedure and the table doesn't have same name.
Add logic to delete if exists. Most likely you ran it previously. The table remains from the previous running of the stored procedure. If you log out and log in then run it, that would likely clear it. But the cleanest way is to check if it exists and delete it if it does. I assume this is MsSql.
At first you should check if temp table is already exist if yes then delete it then create a empty table then use insert statement. refer below example.
IF OBJECT_ID('tempdb..#TmpTBL') IS NOT NULL
DROP TABLE #TmpTBL;
SELECT TOP(0) Name , Address,PhoneNumber
INTO #TmpTBL
FROM EmpDetail
if #Condition=1
INSERT INTO #TmpTBL (Name , Address,PhoneNumber)
SELECT Name , Address,PhoneNumber FROM EmpDetail;
else
INSERT INTO #TmpTBL (Name , Address,PhoneNumber)
SELECT Name , Address,PhoneNumber FROM EmpDetail;

How to trace SQL statements for a specific table?

I'm currently working with DB2 v10.5 and I need to log all SQL Statements that occurr on a specific table (A). For instance, if an INSERT occur on table A, I need to "grab" that SQL Statement and log it into another table (A_LOGGER).
The solution I've reached was to create a TRIGGER (for each CRUD operation) over table A that looks into the table SYSIBMADM.SNAPDYN_SQL and try to save the last executed statement on table A.
Example for the INSERT Statement:
CREATE OR REPLACE TRIGGER OPERATIONS_INSERT_TRIGGER
AFTER INSERT ON REPLDEMO.OPERATIONS
REFERENCING NEW AS OBJ
FOR EACH ROW MODE DB2SQL
BEGIN ATOMIC
INSERT INTO REPLDEMO.OPERATIONS_LOGGER (LAST_SQL_STATEMENT)
SELECT STMT_TEXT FROM SYSIBMADM.SNAPDYN_SQL
WHERE 1=1
AND STMT_TEXT LIKE 'INSERT INTO REPLDEMO.OPERATIONS (%'
AND STMT_TEXT NOT LIKE '%?%';
END%
But looking at table SYSIBMADM.SNAPDYN_SQL is not the best solution because you cannot guarantee that you'll get the truly last SQL Statement executed on table A. Moreover, if there's a massive number of sql statements executed over table A in a very short period the TRIGGER will replicate many of the statements already saved on A_LOGGER.
So, my question is: Is there an effective and secure way to get the last SQL Statement executed over a table?
Thanks.

Stored Procedure refuses to delete column that it creates

I've created a Stored Procedure that refreshes the data in a table. It first re-loads the entire table. Next, several filters are applied. (Example: the column 'Model' must equal 'W'; all rows with model 'B' are deleted.) This happens after the table has been loaded (and not during) because I want to log how many rows are deleted because of each individual filter. After the filters have been applied, some columns contain the same value in every row (the other values were deleted in the filtering process). These columns are now useless, so I want to delete them.
This seems to be problematic for SQL Server. When given the command to execute the SP, it indicates that the columns it is supposed to remove in its final step do not currently exist and refuses to run. That is technically correct, the columns currently don't exist, but they will be created by the SP itself.
Some mockup code:
CREATE PROCEDURE dbo.Procedure AS (
DROP TABLE dbo.Table
SELECT * INTO dbo.Table FROM dbo.View
INSERT INTO dbo.Log VALUES (GETDATE(),(SELECT COUNT(1) FROM dbo.Table))
DELETE FROM dbo.Table WHERE Model <> 'W'
INSERT INTO dbo.Log VALUES (GETDATE(),(SELECT COUNT(1) FROM dbo.Table))
ALTER TABLE dbo.Table DROP COLUMN Model
)
Error code when executing:
[2016-09-02 12:25:20] [S0001][207] Invalid column name 'Model'.
How do I circumvent this problem and get the SP to run?
If I understand correctly, you can use dynamic SQL:
exec sp_executesql 'ALTER TABLE dbo.Table DROP COLUMN Model';
Syntax to remove any column from table in SQL Server is
ALTER TABLE TableName DROP COLUMN ColumnName ;
This may be cause for issue.
Can you check one more time for the existency of the column 'Model' exists in the view.
because i have tried with the same scenario and its works for me..

Can a rowid be invalidated right after being inserted in Oracle?

I'm running queries that look something like this:
INSERT INTO foo (...) VALUES (...) RETURNING ROWID INTO :bind_var
SELECT ... FROM foo WHERE ROWID = :bind_var
Essentially, I'm inserting a row and getting its ROWID, then doing a select against that ROWID to get data back from that record. Very occasionally though, the ROWID won't be found.
Ignoring the fact that there's probably a better way to do what I'm trying to do, is it possible for a ROWID to change that quickly assuming that there's no one else using the database?
UPDATE There is a trigger involved. Here's the DDL statement for it:
CREATE OR REPLACE TRIGGER "LOG_ELIG_DEMOGRAPHICS_TRG"
before insert on log_elig_demographics
for each row
begin
select log_elig_demographics_seq.nextval into :new.log_idn from dual;
end;
Essentially, it's just a trigger that is set up to help us emulate an IDENTITY/AUTO INCREMENT field. Is there something wrong with this trigger?
A ROWID won't change unless:
you move the table (ALTER TABLE t MOVE), from one tablespace to another for example
the row switches from one partition to another (partitioned table with ENABLE ROW MOVEMENT)
you update the primary key of an INDEX ORGANIZED table.
When a row moves from one block to another in a standard (HEAP) table, because it grows so large it can't fit into its original block for example, it will be migrated. Oracle will leave a pointer to the new block and move the row. The row will keep its original ROWID.
ROWIDs can be relied upon, they are used in replication to refresh materialized views for example.
Your INSERT should be:
INSERT INTO foo
(primary_key,
...)
VALUES
(log_elig_demographics_seq.nextval,
...)
RETURNING primary_key INTO :bind_var
There's no need for the trigger.
I agree with Walter.
Instead of
INSERT INTO foo (...) VALUES (...) RETURNING ROWID INTO :bind_var
SELECT ... FROM foo WHERE ROWID = :bind_var
...why not do the following?
SELECT primaryKey_seq.nextVal
INTO bind_var
FROM dual;
INSERT INTO foo (primaryKeyColumn,...)
VALUES (bind_var,...);
SELECT ... FROM foo WHERE primaryKeyColumn = bind_var;
A couple of other things may be happening.
Firstly, the INSERT may be failing. Are you checking for errors/exceptions ? If not, maybe the value in the variable is junk.
Secondly, you could be inserting something that you can select. Virtual Private Database / Row Level Security could be responsible.
Thirdly, if you commit in between the insert and select, a deferred constraint may force a rollback of the insert.
Fourthly, maybe you are doing a rollback.
Is there a trigger on the table that might be reversing the insert?
In my experience, the most likely reason for such an error to happen is that somewhere in between, a rollback has happened. Or, if there has been a commit, another user might have deleted the record.
How is the bind variable declared? In SQLPlus, you can't use a ROWID type, so there is type conversion going on. I wonder if it's possible that this is munging the ROWID value some of the time.

Need some help with Sql Server and a simple Trigger

I wish to make a trigger but i'm not sure how to grab the data for whatever caused the trigger.
I have a simlpe table.
FooId INT PK NOT NULL IDENTITY
Name VARCHAR(100) NOT NULL
I wish to have a trigger so that when an UPDATE, INSERT or DELETE occurs, i then do the following.
Pseduocode
IF INSERT
Print 'Insert' & Name
ELSE IF UPDATE
Print 'Update' & FooId & Name
ELSE IF DELETE
Print 'Delete' & FooId & Name
Now, I know how to make a trigger for a table.
What i don't know how to do is figure out the values based on what the trigger type is.
Can anyone help?
Edit: Not sure if it helps, but db is Sql Server 2008
the pseudo table "inserted" contains the new data, and "deleted" table contains the old data.
You can do something like
create trigger mytrigger on mytable for insert, update, delete
as
if ( select count(*) from inserted ) > 0
-- insert or update
select FooId, Name from inserted
else
-- delete
select FooId, Name from deleted
To clarify all the comments made by others, on an insert, the inserted table contains data and deleted is empty. On a delete, the situation is reversed. On an update, deleted and inserted contain the "before" and "after" copy of any updated rows.
When you are writing a trigger, you have to account for the fact that your trigger may be called by a statement that effects more than one row at a time.
As others have pointed out, you reference the inserted table to get the values of new values of updated or inserted rows, and you reference the deleted table to get the value of deleted rows.
SQL triggers provide an implicitly-defined table called "inserted" which returns the affected rows, allowing you to do things like
UPDATE mytable SET mytimestamp = GETDATE() WHERE id IN (SELECT id FROM inserted)
Regarding your code sample, you'll want to create separate INSERT, UPDATE and DELETE triggers if you are performing separate actions for each.
(At least, this is the case in SQL Server... you didn't specify a platform.)
On 2008, there is also MERGE command. How do you want to handle it?
Starting from 2008, there are four commands you can modify a table with:
INSERT, UPDATE, DELETE, and MERGE:
http://blogs.conchango.com/davidportas/archive/2007/11/14/SQL-Server-2008-MERGE.aspx
http://sqlblogcasts.com/blogs/grumpyolddba/archive/2009/03/11/reasons-to-move-to-sql-2008-merge.aspx
What do you want your trigger to do when someone issues a MERGE command against your table?