Intermittent column does not belong to table exception - sql

I have a stored procedure that gets called hundreds of times per minute. Every once in a rare while I will get an exception that a column does not exist in the query. Here is the exception:
System.Web.HttpUnhandledException: Exception of type 'System.Web.HttpUnhandledException' was thrown. ---> System.ArgumentException: Column 'SubjectID' does not belong to table .
[ArgumentException: Column 'SubjectID' does not belong to table .]
System.Data.DataRow.GetDataColumn(String columnName) +1775157
System.Data.DataRow.get_Item(String columnName) +13
System.Data.DataTableReader.get_Item(String name) +66
Here is the C# that calls the stored proc:
DataTableReader dtr;
dtr = Util.getDepartmentsByTerm(term);
ddlSubject.Items.Add(new ListItem("Select A Subject...", ""));
while (dtr.Read())
{
//The following line throws the exception!
var value = (string)dtr["SubjectID"];
var text = (string)dtr["title"];
var count = (int) dtr["Count"];
//if (!text.Contains("(0)"))
if(count > 0)
ddlSubject.Items.Add(new ListItem(text, value));
}
Pretty simple... here's the stored procedure:
ALTER PROCEDURE [dbo].[selectDepartmentsByTerm]
(
#term nvarchar(50),
#version int
)
AS
SELECT SubjectID, Subject as Title,(select count(distinct courseno)
from RegistrationBlock WITH (NOLOCK)
where RegistrationBlock.Subject = Subjects.SubjectID
and RegistrationBlock.version = #version
and (#term = '' OR RegistrationBlock.term = #term)) as "Count"
FROM Subjects WITH (NOLOCK)
where Version = #version
order by subject
GO

Tom H.'s comment on my question solved this:
I've seen a post that said that this problem can be caused by a corruption in the connection pool. Make sure that your connections are all being closed properly. You can read some more ways to diagnose/fix the problem here: http://www.ksvali.com/2010/08/solution-to-random-error-column-does-not-belong-to-table/

Related

Conversion failed when converting the nvarchar value to data type int sql server

I have a table. There is data in this table and there is a checkbox next to each data. Multiple selection is possible. After the user makes a selection, the id numbers of the selected columns are come in the array. I convert the array to string and send it to the stored procedure and I run the following stored procedure:
Example value for #ResultsIds: 65, 66, 67, 68, 125
#ResultsIds nvarchar(250)
UPDATE MyTable SET [IsVerified] = 1 WHERE Id IN (#ResultsIds)
And I got this error:
Conversion failed when converting the nvarchar value '65, 66, 67, 68, 125' to data type int. Because [Id] column is int data type.
I tried CAST and CONVERT functions of SQL but it didn't work.
SQL Server doesn't do that automatically. Assuming you're on a recent version, you can do this:
declare #ResultsIds nvarchar(250) = '65,66,67,68,125'
UPDATE MyTable
SET [IsVerified] = 1
WHERE Id IN (
select [value]
from string_split(#ResultIDs, ',')
)
declare #ResultsIds nvarchar(250)='65,66,67,68,125'
UPDATE MyTable SET [IsVerified] = 1 WHERE cast(Id as varchar) IN (#ResultsIds)
I solved problem using foreach. I separated the numbers in the string from commas and transferred each number to the array. Then I updated the array one by one by running foreach loop.
public void Verify(DB db, string rows)
{
int[] nums = Array.ConvertAll(rows.Split(','), int.Parse);
foreach (int value in nums)
{
DbCommand cmd = db.GetStoredProcCommand("VerifyProcess");
db.AddInParameter(cmd, "#ResultId", DbType.Int32, value);
db.ExecuteNonQuery(cmd);
}
}

Specifying an upper bound for an int in UPDATE

Given a table, for example Article(Id,Body,Revisions), I would like to increment the Revisions attribute, and, once a certain limit is reached (it's a constant provided by the developer), an error should be thrown. Is this possible to achieve with a single UPDATE ... SET statement in T-SQL?
What I've done:
To increment Revisions attribute by one, I solved as shown here: Is UPDATE command thread safe (tracking revisions) in MS SQL.
Problem
To find a way that is thread safe, which would allow incrementation of Revisions until a certain upper bound is reached.
Context
Since I'm using EF, the ideal solution would be to either thrown an error or specify a flag of some sort. The code I'm using (shown below) is encapsulated into a try-catch:
context.Database.ExecuteSqlCommand("UPDATE dbo.Articles SET Revisions = Revisions + 1 WHERE Id=#p0;", articleId);
You could do this with a WHERE clause in your UPDATE statement, which would do the test. If the test fails, the update will not happen and your call with context.Database.ExecuteSqlCommand will return 0 instead of 1.
In case of a limit of 1000, the update SQL would be:
count = context.Database.ExecuteSqlCommand(
"UPDATE dbo.Articles SET Revisions = Revisions + 1 WHERE Id=#p0 AND Revisions < 1000;", articleId);
Then afterwards you would test whether count == 0 and raise an error message if so.
Use a CHECK constraint. No update statement can violate bounds that are implemented by a CHECK constraint. Not even an update statement issued by a sleep-deprived DBA at the console.
create table article (
id integer primary key,
body nvarchar(max) not null,
-- Allow six versions. (Original plus five revisions.)
revisions integer not null
check (revisions between 0 and 5)
);
insert into article values (1, 'a', 0);
update article
set body = 'b', revisions = 1
where id = 1;
update article
set body = 'c', revisions = 2
where id = 1;
-- Other updates . . .
-- This update will *always* fail with an error.
update article
set body = 'f', revisions = 6
where id = 1;
Kind of whacked but
UPDATE dbo.Articles
SET Revisions = Revisions + 1
WHERE Id=#p0
AND sqrt(Revisions - #MaxRevisions - 2) >= 0;
If Revisions - #Revisions - 2 is negative it will throw an
An invalid floating point operation occurred.
error
If the limit is 100,
UPDATE Article
SET Revisions = LEAST(Revisions + 1, 100)
where Id = #p0

Using newline character and adding several rows of strings into one

I have in my hands an old app on informix server and I'm migrating data into a different database. Both are informix databases. I have a particular problem with one table. Old app used it to support multiline text.
OldTable:
HeaderID int
LineNum int
Descr nvarchar(50,1)
NewTable:
HeaderID int
Descr lvarchar(max)
So, for each HeaderID I have to read the descriptions ordered by line number and put them all together for insert into a new table. There has to be a newline character between each line for conversion to succeed.
Any tips on how to do this?
If you need to do it from SQL then you can use procedure:
CREATE FUNCTION get_text(aHeaderID int)
RETURNING lvarchar;
DEFINE result lvarchar;
DEFINE vcfld lvarchar;
LET result=NULL;
EXECUTE PROCEDURE IFX_ALLOW_NEWLINE('T');
FOREACH cur1
FOR SELECT Descr INTO vcfld FROM OldTable WHERE HeaderID = aHeaderID ORDER BY LineNum
IF result IS NULL THEN
LET result = vcfld;
ELSE
LET result = result || '
' || vcfld;
END IF;
END FOREACH;
RETURN result;
END FUNCTION;
(notice usage of IFX_ALLOW_NEWLINE and line breaking when updating result)
Then you can fill NewTable using:
UPDATE NewTable SET Descr=get_text(HeaderID);
You can use PreparedStatement. This is example in Jython that uses JDBC Informix driver:
db = DriverManager.getConnection(db_url, usr, passwd)
pstm = db.prepareStatement("SELECT vc FROM src ORDER BY id")
rs = pstm.executeQuery()
lines = []
while (rs.next()):
lines.append(rs.getString(1))
pstm = db.prepareStatement("INSERT INTO dest (lvc) VALUES (?)")
pstm.setString(1, '\n'.join(lines))
rs = pstm.execute()
db.close()

Exception ORA-08103: object no longer exists on using setfetchsize of Hibernate

I'm using Hibernate. I need to fetch around 1000000 records and it will cause timeout exception. So I'm using setfetchsize for 6000 records, so that it will distribute the operation in multiple transactions each of 6000 records.
It will take around 21 hours to fetch all.
But meanwhile retrieving records if somebody deletes one of the record which was to be fetched then I get ORA-08103: object no longer exists.
Now I want to skip that object which is deleted while retrieving. How can I do this?
Most likely that a cursor is opened based on a global temporary table(GTT), which had been created with ON COMMIT DELETE ROWS option. And the cause of the ORA-08103: object no longer exists error is commit statement that followed right after the delete statement. Here is a simple example:
SQL> declare
2 type t_recs is table of number;
3 l_cur sys_refcursor; -- our cursor
4 l_rec t_recs;
5
6 begin
7
8 -- populating a global temporary table GTT1 with sample data
9 insert into GTT1(col)
10 select level
11 from dual
12 connect by level <= 1000;
13
14 open l_cur -- open a cursor based on data from GTT1
15 for select col
16 from GTT1;
17
18 -- here goes delete statement
19 -- and
20 commit; <-- cause of the error. After committing all data from GTT1 will be
21 -- deleted and when we try to fetch from the cursor
22 loop -- we'll face the ORA-08103 error
23 fetch l_cur -- attempt to fetch data which are long gone.
24 bulk collect into l_rec;
25 exit when l_cur%notfound;
26 end loop;
27
28 end;
29 /
ORA-08103: object no longer exists
ORA-06512: at line 24
Recreation of global temporary table with on commit preserve rows clause will allow to safely fetch data from a cursor that is based on that table without being afraid of facing ORA-08103: error.
After Struggling one week finally I fixed the Issue:
Solution: Most likely that a cursor is opened based on a global temporary table(GTT), which had been created with ON COMMIT DELETE ROWS option. And the cause of the ORA-08103: object no longer exists error is commit statement that followed right after the delete statement. DBA team didn't agree to change the GTT as on commit preserve rows so finally I added code base in Java Service Layer[Implementing the Spring - Programmatic Transaction]
package com.test;
import java.util.List;
import javax.sql.DataSource;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
public class StudentJDBCTemplate implements StudentDAO {
private DataSource dataSource;
private JdbcTemplate jdbcTemplateObject;
private PlatformTransactionManager transactionManager;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
this.jdbcTemplateObject = new JdbcTemplate(dataSource);
}
public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public void create(String name, Integer age, Integer marks, Integer year){
TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(def);
try {
String SQL1 = "insert into Student (name, age) values (?, ?)";
jdbcTemplateObject.update( SQL1, name, age);
// Get the latest student id to be used in Marks table
String SQL2 = "select max(id) from Student";
int sid = jdbcTemplateObject.queryForInt( SQL2 );
String SQL3 = "insert into Marks(sid, marks, year) " + "values (?, ?, ?)";
jdbcTemplateObject.update( SQL3, sid, marks, year);
System.out.println("Created Name = " + name + ", Age = " + age);
transactionManager.commit(status);
}
catch (DataAccessException e) {
System.out.println("Error in creating record, rolling back");
transactionManager.rollback(status);
throw e;
}
return;
}
public List<StudentMarks> listStudents() {
String SQL = "select * from Student, Marks where Student.id=Marks.sid";
List <StudentMarks> studentMarks = jdbcTemplateObject.query(SQL,
new StudentMarksMapper());
return studentMarks;
}
}

SQL Job Failing but not the stored procedure

EDIT 4/18:
I want to thank everyone who has answered so far. As a test I have set up a new job which has just one step in it,
EXECUTE p_CallLog_GetAbandonedCallsForCallList
This procedure itself runs just fine and reports no errors or warnings but will not run when executed as part of a job. The error I receive when running the job is:
Executed as user: NT AUTHORITY\SYSTEM. OLE DB provider 'SQLOLEDB' reported an error. [SQLSTATE 42000] (Error 7399) [SQLSTATE 01000] (Error 7312) OLE DB error trace
[OLE/DB Provider 'SQLOLEDB' IDBInitialize::Initialize returned 0x80004005: ].
[SQLSTATE 01000] (Error 7300). The step failed.
I have tried changing the run as user selection and every other selection I try results in an error of:
Executed as user: Db2WebCal. Remote access not allowed for Windows NT user activated
by SETUSER. [SQLSTATE 42000] (Error 7410). The step failed.
All of the users I have tried do have a local login setup on the linked server.
The p_CallLog_GetAbandonedCallsForCallList procedure is as follows:
CREATE PROCEDURE [dbo].[p_CallLog_GetAbandonedCallsForCallList]
AS
BEGIN
DECLARE #SrvrName varchar(255)
DECLARE #HoursOld int --only get abandoned call that are fresher than #HoursOld
SET #HoursOld = 2 /*was normal default */
SET #SrvrName = CAST(ServerProperty('MachineName') as varchar(255))
CREATE TABLE #tmpAbandonedCalls
(
[ID] INT NULL,
StartTime DateTime NULL,
CallerIDNumber varchar(255) NULL,
CallerIDCount INT NULL,
Holdtime INT NULL,
DIDNumber varchar(20) NULL,
CustomData varchar(255) NULL,
FromFirstName varchar(100) NULL,
FromLastName varchar(100) NULL,
CallType int NULL
)
IF #SrvrName <> 'ROME' BEGIN
INSERT INTO #tmpAbandonedCalls
SELECT
cl.[ID],
cl.StartTime,
cl.CallerIDNumber,
LastAbandonedCallID.cnt as CallerIDCount,
cl.HoldTime,
right(cl.DIDNumber,10) as DIDNumber,
REPLACE(right(left(cl.CustomData,charindex(';',cl.CustomData) - 1), len(left(cl.CustomData,charindex(';',cl.CustomData) - 1)) - charindex('=',cl.CustomData)) , ' NAME','') as CustomData,
cl.FromFirstName,
cl.FromLastName,
2 AS CallType -- T_L_CallType obctAbandoned
FROM
[StrataCS.Perceptionist.local].TVDB.dbo.CallLog CL LEFT OUTER JOIN
/*=============================================
This derived table lists the CallerID's and the most
recent Call Log ID for candidate calls
=============================================*/
(
SELECT
CallerIDNumber, Max(ID) as ID, count(*) as cnt
FROM
[StrataCS.Perceptionist.local].TVDB.dbo.CallLog CL
WHERE
--Last n days
--StartTime >= DATEADD(dd,-#DaysBack,CAST(CONVERT(VARCHAR(10),GETDATE(),112) as DATETIME))
--Get calls only from within the last two hours.
StartTime >= DATEADD(hh,-2,GETDATE())
AND
LEFT(CustomData,11) = 'CompanyName'
AND
CHARINDEX('Db2ID', CustomData) > 0
AND
CallerIDNumber <> ''
AND
Len(CallerIDNumber) = 10
AND
(cl.HoldTime > 0) --0 holdtime is generally an automated call that we will not want to call again
GROUP BY
CallerIDNumber
) as LastAbandonedCallID
ON
CL.CallerIDNumber = LastAbandonedCallID.CallerIDNumber
WHERE
--Last n days
--StartTime >= DATEADD(dd,-#DaysBack,CAST(CONVERT(VARCHAR(10),GETDATE(),112) as DATETIME))
--Get calls only from within the last two hours.
cl.StartTime >= DATEADD(hh,(-1 * #HoursOld),GETDATE())
AND
--determine abandoned calls
CASE
WHEN CL.Result IN (0, 3, 11) THEN 0
WHEN CL.Result IN (1, 2) THEN 1
WHEN CL.Result IN (4, 9) THEN 2
WHEN CL.Result = 5 THEN 3
WHEN CL.Result = 6 THEN 4
WHEN CL.Result = 8 THEN 5
WHEN CL.Result = 10 THEN 6
WHEN CL.Result = 12 THEN 7
WHEN CL.Result = 13 THEN 8
WHEN CL.Result = 14 THEN 9
ELSE -CL.Result
END = 0
--Calls which have hit the call queue will have both a CompanyName and Db2ID in custom data.
AND
LEFT(CustomData,11) = 'CompanyName'
AND
CHARINDEX('Db2ID', CustomData) > 0
AND
--omit calls with no caller id -- or from IGC 6143847400
(
CL.CallerIDNumber <> ''
--OR CL.CallerIDNumber = '6143847400'
)
AND
--make sure the caller id has 10 digits
Len(CL.CallerIDNumber) = 10
AND
--The abandoned call must be the most recent call from this caller id
--CL.ID >= isnull(LastAbandonedCallID.ID,-#DaysBack)
CL.ID >= isnull(LastAbandonedCallID.ID,-1)
AND
(CL.HoldTime > 0) --0 holdtime is generally an automated call that we will not want to call again
ORDER BY
--sort by call time, most recent first.
StartTime DESC
-- Company has opted out of the Abandoned Callback program
DELETE #tmpAbandonedCalls
FROM
#tmpAbandonedCalls tmp
INNER JOIN dbo.T_CompanyPhoneSetup cps
on tmp.DIDNumber = cps.DID
INNER JOIN T_CompanyAbandonedCallbackOptOut aco
ON cps.CompanyID = aco.CompanyID
AND
aco.OptOutIsActive = 1
--Delete calls that have had a terminating outcome or have been returned within the last 20 minutes
DELETE #tmpAbandonedCalls
FROM
#tmpAbandonedCalls
INNER JOIN
(
SELECT
c.CallLogID
FROM
T_Call c (nolock)
INNER JOIN #tmpAbandonedCalls tmp
on tmp.ID = c.CallLogID
LEFT OUTER JOIN T_L_Need n
ON c.NeedID = n.NeedID
LEFT OUTER JOIN T_L_Outcome o
ON c.OutcomeID = o.OutcomeID
LEFT OUTER JOIN dbo.T_L_CallCampaignDetailStatus ccds
ON o.CCDetailStatusID = ccds.CCDetailStatusID
LEFT OUTER JOIN dbo.T_Company co
ON c.CompanyID = co.CompanyID
LEFT OUTER JOIN dbo.T_L_ProductLine pl
ON co.ProductLineID = pl.ProductLineID
LEFT OUTER JOIN T_CompanyAbandonedCallbackOptOut aco
ON (c.CompanyID = aco.CompanyID) and (aco.OptOutIsActive = 1)
GROUP BY
c.CallLogID
HAVING
--Calls that have an outcome that include at least one terminating outcome
(SUM(CAST(isnull(ccds.IsTerminal,0) as INT)) > 0)
OR
(
--Calls that have been returned less than 20 minutes ago
(SUM(CAST(isnull(ccds.IsTerminal,0) as INT)) = 0)
AND
GETDATE() <= DATEADD(mi,20,Max(c.EnteredOn))
)
OR
(
--Calls for Perceptionist Lite product line
(MAX(co.ProductLineID) = 2) -- Perceptionist Lite
)
) LastCall
ON
#tmpAbandonedCalls.[ID] = LastCall.CallLogID
END
INSERT INTO T_OutboundCallList
(TrackingID, Company, CompanyDID, Phone, CallType)
SELECT
#tmpAbandonedCalls.[ID],
#tmpAbandonedCalls.CustomData,
#tmpAbandonedCalls.DIDNumber,
#tmpAbandonedCalls.CallerIDNumber,
#tmpAbandonedCalls.CallType
FROM
#tmpAbandonedCalls
ORDER BY
StartTime
END
GO
ORIGINAL:
I have the following stored procedure that is used to fill a table with values.
PROCEDURE [dbo].[p_OutboundCallList_Create]
AS
BEGIN
TRUNCATE TABLE T_OutboundCallList
EXECUTE p_LeadVendor_GetCallsForCallList
EXECUTE p_CallCampaign_GetCallsForCallList
EXECUTE p_CallLog_GetAbandonedCallsForCallList
EXECUTE p_NoSaleFollowUp_GetCallsForCallList
END
Running this works fine and the table is filled. After creating a job and adding the following step:
EXEC p_OutboundCallList_Create
The job fails with the following error message:
Executed as user: NT AUTHORITY\SYSTEM. Warning: Null value is eliminated
by an aggregate or other SET operation. [SQLSTATE 01003] (Message 8153)
Warning: Null value is eliminated by an aggregate or other SET operation.
[SQLSTATE 01003] (Message 8153) OLE DB provider 'SQLOLEDB' reported an error.
[SQLSTATE 42000] (Error 7399) [SQLSTATE 01000] (Error 7312) OLE DB error trace
[OLE/DB Provider 'SQLOLEDB' IDBInitialize::Initialize returned 0x80004005: ].
[SQLSTATE 01000] (Error 7300). The step failed.
If I comment out the line
EXECUTE p_CallLog_GetAbandonedCallsForCallList
..the job runs fine. This stored procedure (p_CallLog_GetAbandonedCallsForCallList) does rely on a linked server and runs fine by itself and also runs fine when I run p_OutboundCallList_Create. It only fails when I run it as part of a job. I have tried running as a different user (sa, benderle, etc.) and always get the same result (failed).
"Null value is eliminated by an aggregate or other SET operation" is a SQL Server warning, which means you won't see it in the output if you run your query and this warning is raised (switch to the "Messages" tab in SQL Server Management Studio to see this).
Although it's a warning, presumably any warnings in a SQL job cause the job to error out. Fix the p_CallLog_GetAbandonedCallsForCallList procedure so it doesn't raise that warning and you job will work as expected.
I woulf be interested in seeing the code in p_CallLog_GetAbandonedCallsForCallList, as it may explain more as to why this is happening for the user NT AUTHORITY\SYSTEM.
The message occurs when you perform an aggregation (e.g. sum(), max(), count() on a data set that has a null in it).
To fix this, you may need to put an ISNULL() around the field in question, or use an INNER JOIN instead of a LEFT or RIGHT JOIN.
To disable warning that throw error in Sql Server Agent tasks.
The tasks that are launched from the SQL SERVER AGENT (scheduled), give an error, if there is a warning of the style:
"Null value is eliminated by an aggregate or other SET operation"
This message can be disabled by SET ANSI_WARNING OFF
But in some cases, there are sql statements that require this value to be on to avoid errors like:
Heterogeneous queries require the ANSI_NULLS and ANSI_WARNINGS options to be set for the connection. This ensures consistent query semantics. Enable these options and then reissue your query
Therefore, there is no other solution than to prevent SQL SERVER AGENT from considering it an error.
This can be achieved by modifying the values ​​in the REGISTRY (REGEDIT)
Modify the entries, depending on your version of SQL SERVER:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL11.MSSQLSERVER\SQLServerAgent
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL11.SQL2012\SQLServerAgent
Add as 'no error' the message id you want to disable: 7405