My DB2 version is LUW v11.1.
I am running select queries on big tables and insert to new tables, so I try to use "NOT LOGGED INITIALLY" when creating new tables to avoid generating large size of log. But it seems that the NLI option is not working.
The following is my sql code:
create table diabetes_v3_2.comm_outpatient_prescription_drugs_t2dm
as (select * from commercial.outpatient_prescription_drugs)
with no data
not logged initially;
insert into diabetes_v3_2.comm_outpatient_prescription_drugs_t2dm
select * from commercial.outpatient_prescription_drugs
where enrolid in (
select enrolid from diabetes_v3_2.t2dm_cohort_filter_age_enrollment
);
create table diabetes_v3_2.comm_outpatient_services_t2dm
as (select * from commercial.outpatient_services)
with no data
not logged initially;
insert into diabetes_v3_2.comm_outpatient_services_t2dm
select * from commercial.outpatient_services
where enrolid in (
select enrolid from diabetes_v3_2.t2dm_cohort_filter_age_enrollment
);
I run the script as db2 -tvf script.sql. But I still got the "SQL0964C The transaction log for the database is full" error:
/* Generate cohort data for the cohort after * filtering according to age and continuous * enrollment criteria. */ /* facility header */ /* inpatient admissions */ /* inpatient services */ /* outpatient prescription drugs */ create table diabetes_v3_2.comm_outpatient_prescription_drugs_t2dm as (select * from commercial.outpatient_prescription_drugs) with no data not logged initially
DB20000I The SQL command completed successfully.
insert into diabetes_v3_2.comm_outpatient_prescription_drugs_t2dm select * from commercial.outpatient_prescription_drugs where enrolid in ( select enrolid from diabetes_v3_2.t2dm_cohort_filter_age_enrollment )
Number of rows affected : 275423901
DB20000I The SQL command completed successfully.
/* outpatient services */ create table diabetes_v3_2.comm_outpatient_services_t2dm as (select * from commercial.outpatient_services) with no data not logged initially
DB20000I The SQL command completed successfully.
insert into diabetes_v3_2.comm_outpatient_services_t2dm select * from commercial.outpatient_services where enrolid in ( select enrolid from diabetes_v3_2.t2dm_cohort_filter_age_enrollment )
DB21034E The command was processed as an SQL statement because it was not a
valid Command Line Processor command. During SQL processing it returned:
SQL0964C The transaction log for the database is full. SQLSTATE=57011
Why is this?
To use NOT LOGGED INITIALLY properly, the application doing the changes should NOT have AUTOCOMMIT enabled. Having AUTOCOMMIT OFF also helps define the scope of the transactions:
For CLP, you can turn AUTOCOMMIT OFF using the environment variable DB2OPTIONS :
export DB2OPTIONS=+c
If you execute a script containing update SQL statements, such as inserts, and DB2OPTIONS is not set, you can execute the script using:
db2 +c -tvf input_script.sql -z output_script.out
Make sure you add explicit COMMIT statements in your scripts to ensure that they occur at reasonable points.
Related
When running the following Python code and SQL query on a Teradata Vantage Express server:
#!/usr/bin/env python3
import teradatasql
query = """CREATE VOLATILE TABLE target_table AS (
select * FROM MY_DB.MY_TABLE
)
WITH DATA ON COMMIT PRESERVE ROWS;
SELECT * FROM target_table;"""
con = teradatasql.connect(host="localhost", user="dbc", password="dbc")
cur = con.cursor()
cur.execute(query)
I get the following error:
teradatasql.OperationalError: [Version 17.20.0.7] [Session 2988] [Teradata Database] [Error 3932] Only an ET or null statement is legal after a DDL Statement.
However, when using bteq (Teradata's CLIv2 db connector), and running the same query it works like a charm and doesn't throw any error:
BTEQ -- Enter your SQL request or BTEQ command:
CREATE VOLATILE TABLE target_table AS (
select * FROM MY_DB.MY_TABLE
)
WITH DATA ON COMMIT PRESERVE ROWS;
CREATE VOLATILE TABLE target_table AS (
select * FROM MY_DB.MY_TABLE
)
WITH DATA ON COMMIT PRESERVE ROWS;
*** Table has been created.
*** Total elapsed time was 1 second.
BTEQ -- Enter your SQL request or BTEQ command:
SELECT TOP 1 * FROM target_table;
SELECT TOP 1 * FROM target_table;
*** Query completed. One row found. 9 columns returned.
*** Total elapsed time was 1 second.
customer_id customer_token customer_branch customer_num
-------------- ------------------------------ --------------- ------------
8585 452004 83 808038
BTEQ -- Enter your SQL request or BTEQ command:
Any idea?
Note that no useful Google entries were found for either Python based JDBC drivers (e.g. teradatasql) or Node.js based drivers.
In the bteq examples you’ve given there are individual queries being executed; each query is separated by a “;”. However, in the Python code you have combined 2 queries into a single string and are trying to execute that string as a single query - which won’t work.
You need to write the Python code to run each query separately, in the same way that the bteq code does. For example:
query = """CREATE VOLATILE TABLE target_table AS (
select * FROM MY_DB.MY_TABLE
)
WITH DATA ON COMMIT PRESERVE ROWS;”””
con = teradatasql.connect(host="localhost", user="dbc", password="dbc")
cur = con.cursor()
cur.execute(query)
query = “””SELECT * FROM target_table;"""
cur.execute(query)
I have a job that runs on my server to track the last login on my sql server so I can audit inactive users.
First I enabled track successful logins on the server
I created a table called TRACK_LOGIN and run this daily:
INSERT INTO dbadb.dbo.TRACK_LOGIN (logontime, logon, loginname) EXEC XP_READERRORLOG 0, 1, [LOGIN SUCCEEDED FOR USER]
Now that that information is in the TRACK_LOGIN table I query DISTINCT out of that table and put it in another table with this query:
SELECT DISTINCT SUBSTRING(LOGINNAME,PATINDEX('%''%',LOGINNAME)+1,PATINDEX('%.%',LOGINNAME)-PATINDEX('%''%',LOGINNAME))FROM TRACK_LOGIN
I would also like to query the column logontime along with the distinct login so I have a list daily of who logs in and what time they login?
Please help modify the select statement above to include distinct logins along with their last logontime.
This is intended on allowing me to look back at my users last login and eliminate those on the server that are not used.
I understand that you have already put some real effort into make this work, but I would still suggest to go with a different approach that yields a much cleaner result:
Logon triggers
This will allow you to insert the right type of data into your table and will not force you to parse back log entries.
This example here shows a different use case, but I think you will have no issue to port it to your own problem.
CREATE TRIGGER MyLogonTrigger ON ALL SERVER FOR LOGON
AS
BEGIN
IF SUSER_SNAME() <> 'sa'
INSERT INTO Test.dbo.LogonAudit (UserName, LogonDate, spid)
VALUES (SUSER_SNAME(), GETDATE(), ##SPID);
END;
GO
ENABLE TRIGGER MyLogonTrigger ON ALL SERVER;
Ok to track logins I did this, I abounded the first method and implemented this:
First I created a table called logonaudit:
CREATE TABLE LogonAudit
(
AuditID INT NOT NULL CONSTRAINT PK_LogonAudit_AuditID
PRIMARY KEY CLUSTERED IDENTITY(1,1)
, UserName NVARCHAR(255)
, LogonDate DATETIME
, spid INT NOT NULL
);
I then had to grant insert on that table:
GRANT INSERT ON dbadb.dbo.LogonAudit TO public;
I created another table called auditloginresults:
create table auditLoginResults
(
AuditID INT,
Username NVARCHAR(255),
LogonDate DATETIME,
SPID INT
);
I then created a trigger to log all logins and times to the first table LogonAudit. I had to create a logon called login_audit and allow it to insert into my tables. I then had to use the origional_login() to log the users login, if you dont do this it will block all logins that are not sa
CREATE TRIGGER MyLogonTrigger
ON ALL SERVER WITH EXECUTE AS 'login_audit'
FOR LOGON
AS
BEGIN
INSERT INTO DBADb.dbo.LogonAudit (UserName, LogonDate, spid)
VALUES (ORIGINAL_LOGIN(), GETDATE(), ##SPID);
END;
Now I created a job (you will need to create a job to run at a specific time with this code, This is not the code for the job just the code you would run in your job) to query the first table LogonAudit and put the results into the auditloginResults table, after that step I cleaned out the first table LogonAudit by running another step to delete data in the first table. Im not going to post the job to keep the threat clean but here is what is run in the job
The create job step 1--------------------------------------------------------
INSERT INTO DBADb.dbo.auditLoginResults
SELECT I.*
FROM DBADb.[dbo].[LogonAudit] AS I
INNER JOIN
(SELECT UserName, MAX([logondate]) AS MaxDate
FROM DBADb.[dbo].[LogonAudit]
GROUP BY UserName
) AS M ON I.logondate = M.MaxDate
AND I.UserName = M.UserName
`
-----NOW create job to purge the logonaudit table step 2
DELETE FROM dbadb.dbo.auditLoginResults;
-----now create a stored procedure to execute this will query the auditloginreaults and provide you the last login of everyone that has ever logged into the database
SELECT I.*
FROM DBADb.[dbo].[auditLoginResults] AS I
INNER JOIN
(SELECT UserName, MAX([logondate]) AS MaxDate
FROM DBADb.[dbo].[ auditLoginResults]
GROUP BY UserName
) AS M ON I.logondate = M.MaxDate
AND I.UserName = M.UserName
I need to create a stored procedures in wich i have to create a table from select statements in which I have to insert parameters.
Here is my query :
CREATE TABLE DBL_JW AS
SELECT * FROM (
SELECT m.IDM,
m2.IDM AS dups_key
FROM members_tbl m
LEFT OUTER JOIN members_tbl m2
ON ( m.IDM != m2.IDM
AND m.DBIRTH = m2.DBIRTH
AND utl_match.jaro_winkler_similarity(m.SNAME,m2.SNAME) > 90
AND utl_match.jaro_winkler_similarity(m.FNAME,m2.FNAME) > 95))
Where dups_key IS NOT NULL;
I've tried to write this stored procedures :
CREATE OR REPLACE PROCEDURE JW_DBL_POT
(
P_SNAME IN NUMBER
, P_FNAME IN NUMBER
, P_RC OUT SYS_REFCURSOR
) AS
BEGIN
OPEN P_RC
EXECUTE IMMEDIATE
CREATE TABLE DBL_JW AS
SELECT * FROM (
SELECT m.IDM,
m2.IDM AS dups_key
FROM members_tbl m
LEFT OUTER JOIN members_tbl m2
ON ( m.IDM != m2.IDM
AND m.DBIRTH = m2.DBIRTH
AND utl_match.jaro_winkler_similarity(m.SNAME,m2.SNAME) > P_SNAME
AND utl_match.jaro_winkler_similarity(m.FNAME,m2.FNAME) > P_FNAME ))
Where dups_key IS NOT NULL;
END JW_DBL_POT;
I'm facing this errors :
- PLS-00103: Encountered the symbol “CREATE”
even removing the EXECUTE IMMEDIATE instruction, I have the same error. How can I manage it ?
Thx
If you absolutely had to store this information in a table, it sounds like it would only be needed temporarily as part of the process of fixing the data.
Rather than creating a table each time you run the code and then dropping it after you're done with it (which is what I assume your plan is for this table!), why not create a Global Temporary Table (GTT) once, and then use that to store data on a per session basis - ie. only your session can see the data that's been stored there during that session.
Sorry I'm a bit new to this so just trying to get my head around linking everything up.
At the moment I have a normal query - SELECT FROM WHERE which basically finds about 2000 records that I need to update which link across several tables.
Can someone tell me how I can link this simple query to something else so I can basically execute several stored procedures, all in the same script? But only affecting the records returned by my simple query?
Apologies, that probably sounds as clear as mud!
*EDIT - MORE DETAIL *
So here is my Select query:
SELECT [MembershipTermID]
,[MemberStatusProgKey]
,[StartDate]
,[EndDate]
,[AdditionalDiscount]
,[EntryDateTime]
,[UpdateDateTime]
,[MembershipID]
,[AgentID]
,[PlanVersionID]
,[ForceThroughReference]
,[IsForceThrough]
,[NextTermPrePaid]
,[IsBillingMonthly]
,[CICSMEMBERNUM]
,[CICSHISTORY]
,[TMPSeqNoColumn]
,[LastPaymentDate]
,[PaidToDate]
,[IsIndeterminate]
,DATEDIFF(MONTH, PaidToDate, GETDATE()) as MonthsDifference
,dbo.FullMonthsSeparation (PaidToDate, GETDATE())
FROM [Apollo].[dbo].[MembershipTerm]
WHERE MemberStatusProgKey='DORMANT'
AND IsBillingMonthly=1
AND dbo.FullMonthsSeparation (PaidToDate, GETDATE()) >= 2
So using the rows that this returns I want to exec several stored procedures to update everything I need to in the database which would be affected by changing these rows. An example of one stored procedure is below, I think I will need to execute about 10 of these if not more:
USE [Apollo]
GO
/****** Object: StoredProcedure [dbo].[spCancellationDetailInsert] Script Date: 01/10/2012 10:21:50 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/* ************************* INSERT *************************/
/* Auto Generated 11/29/2006 7:28:53 PM by Object Builder */
/* ************************* INSERT *************************/
ALTER Procedure [dbo].[spCancellationDetailInsert]
#StampUser char (10),
#CancellationDetailID int,
#RefundAmount float,
#OldEndDate datetime,
#EffectiveDate datetime,
#CancelDate datetime,
#ReasonCodeProgKey nvarchar (50)
As
/* insert CancellationDetail record */
Insert [CancellationDetail]
(
RefundAmount,
OldEndDate,
EffectiveDate,
CancelDate,
ReasonCodeProgKey
)
Values
(
#RefundAmount,
#OldEndDate,
#EffectiveDate,
#CancelDate,
#ReasonCodeProgKey
)
If ##Error <> 0 GoTo InsertErrorHandler
/* save the key of the new row created by the insert */
Select #CancellationDetailID = Scope_Identity()
/* add audit record */
Insert CancellationDetailAudit
(StampUser,
StampDateTime,
StampAction,
CancellationDetailID,
RefundAmount,
OldEndDate,
EffectiveDate,
CancelDate,
ReasonCodeProgKey)
Values
(#StampUser ,
GetDate() ,
'I',
#CancellationDetailID,
#RefundAmount,
#OldEndDate,
#EffectiveDate,
#CancelDate,
#ReasonCodeProgKey)
If ##Error <> 0 GoTo AuditInsertErrorHandler
Select
CancellationDetailID = #CancellationDetailID
Return (0)
InsertErrorHandler:
Raiserror ('SQL Error whilst inserting CancellationDetailrecord: Error Code %d',17,1,##Error)
With Log
Return (99)
AuditInsertErrorHandler:
Raiserror ('SQL Error whilst inserting audit record for CancellationDetailInsert: Error Code %d',17,1,##Error)
With Log
Return (99)
If you're asking what I think you are -
Stored procedures can contain (pretty much) any valid SQL statement. This includes returning multiple results sets, performing multiple updates and calling other stored procedures.
For example:
CREATE PROCEDURE usp_Sample AS
SELECT * FROM INFORMATION_SCHEMA.COLUMNS
SELECT * FROM INFORMATION_SCHEMA.TABLES
UPDATE Users SET Active = 0 WHERE ExpiredDate < GetDate()
SELECT Active, COUNT(*) FROM Users GROUP BY Active
EXEC usp_Sample2
GO
Obviously that's a rather artificial example, but assuming all the objects existed it'd run perfectly well.
In order to perform more queries at the same time you just need to append them after your select.
So you can do
Select *
From table1
Select *
From table2
Select *
From table3
as many times as you want and they'll all execute independently.
If you want to UPDATE based on a SELECT you usually do something like:
UPDATE table1
WHERE ID IN (SELECT ID FROM TABLE2)
with regards to your stored procedures it would help if you posted more details.
I wrote this query:
SELECT * INTO #nima FROM Region r
Every time I execute this queries:
SELECT OBJECT_NAME(OBJECT_ID('tempdb..#nima'))
--or
SELECT OBJECT_NAME(OBJECT_ID('#nima'))
I get NULL, but when I execute above select I get error that #nima alreadty exist
Try just using the OBJECT_ID function to determine if the temp table exists:
SELECT object_id('tempdb..#nima')
Or if you wish to retrieve the object name, you will need to specify the database id using the DB_ID function for the temp database:
SELECT OBJECT_NAME(OBJECT_ID('tempdb..#nima'), DB_ID('tempdb'))
This gives the internal id of #nima as expected in tempdb
SELECT OBJECT_ID('tempdb..#nima'))
OBJECT_NAME takes a local database ID. There will be no object (except by rare chance) with that ID locally because the ID comes from tempdb
Demo (untested!)
USE tempdb
SELECT OBJECT_NAME(OBJECT_ID('tempdb..#nima')) --#nima + system generated stuff
USE MyDB
SELECT OBJECT_NAME(OBJECT_ID('tempdb..#nima')) --null
-- Now we add DBID for tempdb
SELECT OBJECT_NAME(OBJECT_ID('tempdb..#nima'), 2) -- #nima + system generated stuff