Cannot drop table created within same script - sql

I have a script in which I create a temporary table, that I subsequently want to drop.
I simply create the table, fill it using a INSERT INTO statement, but when it comes to dropping it, the script fails stating that the table is in use.
From reading around it would seem to be caused by the transaction managment, but I'm a little confused.
Here is a little script that reproduces the issue:
CREATE TABLE SCRIPT_TEMP (
NAME VARCHAR(100) NOT NULL,
USERNAME VARCHAR(150) NOT NULL);
COMMIT WORK;
INSERT INTO SCRIPT_TEMP (NAME, USERNAME)
SELECT NAME, COALESCE(USERNAME, 'empty')
FROM SALESREPS;
COMMIT WORK;
DROP TABLE SCRIPT_TEMP;
COMMIT WORK;
Or, in order to be easily testable to anyone without a SALESREPS table, use this insert statement :o)
INSERT INTO SCRIPT_TEMP (NAME, USERNAME)
SELECT 'Name 1', 'Username 1'
FROM RDB$DATABASE;
COMMIT WORK;
I fail to see what still holds a reference to the SCRIPT_TEMP table by the time the drop call is made. Why would the script's own transaction block it even after the second COMMIT?
If I split the execution in 2 scripts everything is fine.
What am I missing??
Thanks!!
PS: using Firebird 2.5.2, in case that matters
PPS: my script is a bit more involved than this. THe temp table is filled with table names and related constraints that need to be manipulated, but that's not the issue, that part is working well. And the fact is, the issue I want to resolve is easily reproducible with the code sample here, that I got to while debugging. This SO question seems to be about the exact same problem, but the only answer is not helpful to the problem itself

Thanks to Val Marinov for pointing me in the right direction.
It appears my issue is due to my SQL Manager - there must be a setting I'm not aware of.
Script runs as expected in FlameRobin.

Related

SQL - Table not found after backup

I saved a SQL table before deleting some information from it with the sql statment:
select * into x_table from y_table
After doing some operations, I want to get back some information from the table I saved with the query above. Unfortunately, MS SQL Server MGMTS shows an error saying that the table does not exist.
However, when I put the drop statement, the table is recognized - and the table is not underlined.
Any idea why this table is recognized by the drop table statement and not the select from statement. This seems strange for me.
EDIT:
Thank you
It may be that the table isn't underlined in your drop table command because its name is still in your IntelliSense cache. Select Edit -> IntelliSense -> Refresh Local Cache in SSMS (or just press Ctrl+Shift+R) and see if the table name is underlined then.
Edit:
Another possibility is that your drop table command might be in the same batch as another statement that creates the table, in which case SSMS won't underline it because it knows that even though the table doesn't exist now, it will exist by the time that command is executed. For instance:
None of the tables one, two, or three existed in my database when I took this screenshot. If I highlight line 6 and try to run it by itself, it will fail. Yet you can see that two is not underlined on line 6 because SSMS can see that if I run the whole script, the table will be created on line 5. On the other hand, three is underlined on line 9 because I commented out the code that would have created it on line 8.
All of that said, I think we might be making too much of this problem. If you try to select from a table and SQL Server tells you it doesn't exist, then it doesn't exist. You can't rely on IntelliSense to tell you that it does; the two examples above are probably not the only ways that IntelliSense might mislead you about the current status of a table.
If you want the simplest way to know whether an object with a given name (like x_table) exists, just use:
select object_id('x_table');
If this query returns null, x_table doesn't exist, regardless of what IntelliSense is telling you. If it returns non-null, then there is some object out there with that name, and then the real question is why your select statement is failing. And to answer that, I'd need to see the statement.
A lot of posts like this, you have to copy in 2 statements :
CREATE TABLE newtable LIKE oldtable;
INSERT newtable SELECT * FROM oldtable;

Is there any way to safely run SELECT INTO?

I have a script that runs a SELECT INTO into a table. To my knowledge, there are no other procedures that might be concurrently referencing/modifying this table. Once in awhile, however, I get the following error:
Schema changed after the target table was created. Rerun the Select
Into query.
What can cause this error and how do I avoid it?
I did some googling, and this link suggests that SELECT INTO cannot be used safely without some crazy try-catch-retry logic. Is this really the case?
I'm using SQLServer 2012.
Unless you really don't know the fields and data types in advance, I'd recommend first creating the table, then adding the data with an Insert statement. In your link, David Moutray suggests the same thing, here's his example code verbatim:
CREATE TABLE #TempTableY (ParticipantID INT NOT NULL);
INSERT #TempTableY (ParticipantID)
SELECT ParticipantID
FROM TableX;

How to figure out why rows are disappearing from my SQL server?

I'm working with a SQL Server 2008 installation that was maintained for years by another team of programmers.
I'm having a problem that rows of data seem to be mysteriously disappearing from a specific table in my server.
I would like to be able to set up some sort of monitoring system that would tell me when the table is modified, and a summary of the modification.
I think that "triggers" might be what I'm looking for, but I've never used them before. Are triggers what I want to use, and if so, what is a good resource for learning to use them? Is there a better solution?
I think that I should mention that the table I'm referring to is not that frequently updated, so I don't think that adding a little bit of overhead should be a big deal, but I would prefer a solution that I can brush away once the problem is resolved.
A FOR DELETE trigger could help you capture the rows that are being deleted. You could create an audit table (copy of the table that you'd like to monitor) and then add this code to your trigger:
INSERT INTO [Your Audit Table]
SELECT * FROM deleted
I've also seen some "more advanced" scenarios involving FOR XML.
I don't know that the trigger would help determine who is deleting the records, but you might be able to PROVE that the records are being deleted, and perhaps what time, etc. That could help you troubleshoot further.
The following sample should be a basic idea of what you're looking for.
CREATE TABLE MyTestTable(col1 int, col2 varchar(10));
GO
CREATE TABLE MyLogTable(col1 int, col2 varchar(10), ModDate datetime, ModBy varchar(50));
GO
CREATE TRIGGER tr_MyTestTable_IO_UD ON MyTestTable AFTER UPDATE, DELETE
AS
INSERT MyLogTable
SELECT col1, col2, GETDATE(), SUSER_SNAME()
FROM deleted;
GO
Insert MyTestTable Values (1, 'aaaaa');
Insert MyTestTable Values (2, 'bbbbb');
UPDATE MyTestTable Set col2 = 'bbbcc' WHERE col1 = 2;
DELETE MyTestTable;
GO
SELECT * FROM MyLogTable;
GO
However, keep in mind that there are still ways of deleting records that won't be caught by a trigger. (TRUNCATE TABLE and various bulk update commands.)
Another solution would be to attach Sql Profiler to the database with specific conditions. This will log every query run for your inspection.
I like to stay away from triggers but they could help for your problem like Draghon said
I think you have it figured out. A trigger is likely your best bet as it's as close to the data as you can get. Inspecting the code (programming or even a stored procedure) would not give you as much an assurance as a trigger would; a Delete trigger in this case.
Check out this article: http://www.go4expert.com/forums/showthread.php?t=15510

SQL continue executing queries after duplicate key violation

I have a situation where I want to insert a row if it doesn't exist, and to not insert it if it already does. I tried creating sql queries that prevented this from happening (see here), but I was told a solution is to create constraints and catch the exception when they're violated.
I have constraints in place already. My question is - how can I catch the exception and continue executing more queries? If my code looks like this:
cur = transaction.cursor()
#execute some queries that succeed
try:
cur.execute(fooquery, bardata) #this query might fail, but that's OK
except psycopg2.IntegrityError:
pass
cur.execute(fooquery2, bardata2)
Then I get an error on the second execute:
psycopg2.InternalError: current transaction is aborted, commands ignored until end of transaction block
How can I tell the computer that I want it to keep executing queries? I don't want to transaction.commit(), because I might want to roll back the entire transaction (the queries that succeeded before).
I think what you could do is use a SAVEPOINT before trying to execute the statement which could cause the violation. If the violation happens, then you could rollback to the SAVEPOINT, but keep your original transaction.
Here's another thread which may be helpful:
Continuing a transaction after primary key violation error
I gave an up-vote to the SAVEPOINT answer--especially since it links to a question where my answer was accepted. ;)
However, given your statement in the comments section that you expect errors "more often than not," may I suggest another alternative?
This solution actually harkens back to your other question. The difference here is how to load the data very quickly into the right place and format in order to move data around a single SELECT -and- is generic for any table you want to populate (so the same code could be used for multiple different tables). Here's a rough layout of how I would do it in pure PostgreSQL, assuming I had a CSV file in the same format of the table to be inserted into:
CREATE TEMP TABLE input_file (LIKE target_table);
COPY input_file FROM '/path/to/file.csv' WITH CSV;
INSERT INTO target_table
SELECT * FROM input_file
WHERE (<unique key field list>) NOT IN (
SELECT <unique key field list>
FROM target_table
);
Okay, this is a idealized example and I'm also glossing over several things (like reporting back the duplicates, pushing the data into the table via Python in-memory data, COPY from STDIN rather than via a file, etc.), but hopefully the basic idea is there and it's going to avoid much of the overhead if you expect more records to be rejected than accepted.

Watch a Database column to determine what is modifying

How do I find out what application or SP is modifing the values in a config table? I thought I had isolated the app that was responsible but these particular values keep chnging back to true when I keep modifying them to be false.
First, create a logging table:
CREATE TABLE modlog(
datestamp smalldatetime,
username varchar(255) NOT NULL DEFAULT SYSTEM_USER
);
Then create an UPDATE trigger on your table:
CREATE TRIGGER mytable_mods ON mytable FOR UPDATE AS
INSERT INTO modlog(smalldatetime) VALUES (GETDATE());
Just peek into the modlog table to figure out which user is updating the table, and when. You could get fancy and also log particular fields being updated.
Another approach would be to set up a trace in SQL Server Profiler, filter the heck out of it so it only returns updates on that table, and keep it open until something happens.
If your applications include the ApplicationName parameter in their connection strings, you can use App_Name() instead of SYSTEM_USER, which will log the application name, removing the extra detective work. Knowing the user might still be useful so you can figure out what they are doing to trigger the update.
Create a trigger to roll back the update. Wait for the app to error out. It can be a very simple trigger:
CREATE TRIGGER BugOffRogueProgram
ON MyConfigTable
FOR UPDATE
AS
BEGIN
ROLLBACK TRAN
END
The answers provided so far are absolutely on the spot - that's the way to do it in SQL Server 2005.
Just as a brief teaser: in SQL Server 2008, there's a new feature called Change Data Capture to support this exact scenario "out of the box" without the need to write triggers and update tables yourself. Quite handy!
Marc