Check Excel file destination temp table in SSIS? - sql

I have created ssis package to generate excel file dynamically from sql table.
But when I try to check whether that excel connection temp table if present or not using below query in sql task it gets failed syntax error
IF object_id(MyExcel) is not null
CREATE TABLE `MyExcel` (
`CUSIP` varchar(50),
`FaceAmount` decimal(18,4),
`Portfolio` varchar(50),
`PositionDate` DateTime,
`PositionCost` decimal(18,6),
`CurrentPrice` decimal(18,6)
)
else drop table MyExcel
ERROR :
[Execute SQL Task] Error: Executing the query "IF object_id(MyExcel) is not null
CREATE TABLE `..." failed with the following error: "Invalid SQL statement; expected 'DELETE', 'INSERT', 'PROCEDURE', 'SELECT', or 'UPDATE'.". Possible failure reasons: Problems with the query, "ResultSet" property not set correctly, parameters not set correctly, or connection not established correctly.
Please advise?
I have tried with answer
IF OBJECT_ID(N'MyExcel') IS NOT NULL
BEGIN
DROP TABLE MyExcel;
END;
CREATE TABLE [MyExcel]
(
[CUSIP] VARCHAR(50),
[FaceAmount] DECIMAL(18,4),
[Portfolio] VARCHAR(50),
[PositionDate] DATETIME,
[PositionCost] DECIMAL(18,6),
[CurrentPrice] DECIMAL(18,6)
);
But still getting same error for statements
IF OBJECT_ID(N'MyExcel') IS NOT NULL
BEGIN
DROP TABLE MyExcel;
END;
I'm using this query inside SQL TASK
Connection type is EXCEL

This appears to be a combination of SQL-Server syntax (OBJECT_ID('ObjectName')) and MySQL syntax (back ticks for object names). I am assuming you are connecting to a SQL-Server database so you should qualify your object names with []. e.g.
IF OBJECT_ID(N'MyExcel') IS NOT NULL
BEGIN
CREATE TABLE [MyExcel]
(
[CUSIP] VARCHAR(50),
[FaceAmount] DECIMAL(18,4),
[Portfolio] VARCHAR(50),
[PositionDate] DATETIME,
[PositionCost] DECIMAL(18,6),
[CurrentPrice] DECIMAL(18,6)
);
END;
ELSE
BEGIN
DROP TABLE MyExcel;
END;
However, I believe your logic is flawed, your statement is saying "If the table exists, create it, if not drop it", so if it does already exist you will get an error saying the table already exists, if it doesn't then you will get an error saying you can't drop it because it doesn't exist. What you would really want is:
IF OBJECT_ID(N'MyExcel') IS NULL
BEGIN
CREATE TABLE [MyExcel]
....
However, this still presents you with a problem, since if the table exists before the task is run, it won't after, if it doesn't exist before then it will be created, which means whether or not the table exists after the task completes is dependent on whether or not the table exists before. I would imagine you want to do something like:
IF OBJECT_ID(N'MyExcel') IS NULL
BEGIN
CREATE TABLE [MyExcel]
(
[CUSIP] VARCHAR(50),
[FaceAmount] DECIMAL(18,4),
[Portfolio] VARCHAR(50),
[PositionDate] DATETIME,
[PositionCost] DECIMAL(18,6),
[CurrentPrice] DECIMAL(18,6)
);
END;
ELSE
BEGIN
TRUNCATE TABLE [MyExcel];
-- If you don't want to truncate the table and want it with
-- it's previous data in just remove the entire `else` clause
END;
Or
IF OBJECT_ID(N'MyExcel') IS NOT NULL
BEGIN
DROP TABLE MyExcel;
END;
CREATE TABLE [MyExcel]
(
[CUSIP] VARCHAR(50),
[FaceAmount] DECIMAL(18,4),
[Portfolio] VARCHAR(50),
[PositionDate] DATETIME,
[PositionCost] DECIMAL(18,6),
[CurrentPrice] DECIMAL(18,6)
);
i.e. after the task is run you will always have an table called MyExcel in the database, so you know it will be there when you get to the next step in your SSIS package.
ADDENDUM
As far as I know, you cannot use IF with an excel connection. There is an article here on querying the meta data from an excel workbook so you can check if a table exists. This is probably the technically correct way of doing it.
I was able to create a work around though, by having an Execute SQL Task with the following SQL:
DELETE
FROM MyExcel;
Then adding another Execute SQL Task to the On Error event handler to run:
CREATE TABLE MyExcel
(
CUSIP VARCHAR(50),
FaceAmount DECIMAL(18,4),
Portfolio VARCHAR(50),
PositionDate DATETIME,
PositionCost DECIMAL(18,6),
CurrentPrice DECIMAL(18,6)
);
So if the table does not exists, the delete statement will throw an error, which will trigger the create table statement. Thus ensuring after the task has run the table MyExcel definitely exists.
These tasks could be reversed, the result would be the same

You don't create an excel file with CREATE TABLE. If you come to think of excel file as database, the tables would be.. worksheets :).
To create an excel file, you'd Excel Connection Manager. You need to point it once to a template file, and after you set up excel destination with correct expressions, the file will be created. If it already exists, you just need to redirect the error.
And then you use Execute Sql to create the table (i.e. worksheet), of your desired structure.

You can add a Execute SQL Task to the end of the control flow to Drop the Excel table(s) in the package. This will leave the environment ready for the package to be processed again.

Related

Temp table already exists

Hi I have a temporary table in which I am trying to insert records based on a where condition but it throws an error that it already exists.
I have tried to change the names but that is not the issue as the temporary tables are delete when the session ends.
I think I am writing the query right.
SELECT [Name]
INTO #TEMP_REJECT
FROM #TEMP_VALIDATION
WHERE Name = #Name
I am trying to insert #TEMP_REJECT FROM #TEMP_VALIDATION
Error message
"There is already an object named '#TEMP_REJECT' in the database."
Please suggest.
Thank you for your help.
R
SQL Server won't tell you that a table doesn't exist if it doesn't.
I suggest that you add
IF OBJECT_ID('tempdb..#TEMP_REJECT') IS NOT NULL
DROP TABLE #TEMP_REJECT
in front of your select statement. This guarantees that the temp table won't exist when the select is executed.
So your statement becomes
IF OBJECT_ID('tempdb..#TEMP_REJECT') IS NOT NULL
DROP TABLE #TEMP_REJECT
SELECT [Name]
INTO #TEMP_REJECT
FROM #TEMP_VALIDATION
WHERE Name = #Name
This answer will help you :
https://stackoverflow.com/a/8560644/3635715
To make short : SELECT INTO creates table then insert records.
INSERT INTO only insert the records.
So in your case, since #TEMP_REJECT already exists, SELECT INTO is rejected because it cannot create the table again, so you have to use INSERT INTO after first SELECT INTO.
IF OBJECT_ID('tempdb..#TEMP_REJECT') IS NOT NULL
BEGIN
INSERT INTO #TEMP_REJECT
SELECT [Name]
FROM #TEMP_VALIDATION
WHERE Name = #Name
END
ELSE
BEGIN
SELECT [Name]
INTO #TEMP_REJECT
FROM #TEMP_VALIDATION
WHERE Name = #Name
END
References :
INTO Clause
INSERT Clause
Try checking before inserting
if object_id('tempdb..#TEMP_REJECT') is not null
drop table #TEMP_REJECT
SELECT [Name]
INTO #TEMP_REJECT
FROM #TEMP_VALIDATION
WHERE Name = #Name
if SQL says,there is temp table,there must be a table prior to your insert
I've noticed that I get the same error when I am working consecutively through the same SQL Server tab/file.
For example, I have a large SQL file that I use to execute a series of updates using temp tables. When I execute it consecutively, it errors out complaining that my #tempTable already exists (even if I use a "if this table exists, drop it" statement as DeanOC describes).
Exiting out of the file/tab between consecutive runs resolves the issue.
If this poses an issue for your use case, I'd suggest bundling your statements in a stored proc and implementing DeanOC's drop logic therein.

StoredProc manipulating Temporary table throws 'Invalid column name' on execution

I have a a number of sp's that create a temporary table #TempData with various fields. Within these sp's I call some processing sp that operates on #TempData. Temp data processing depends on sp input parameters. SP code is:
CREATE PROCEDURE [dbo].[tempdata_proc]
#ID int,
#NeedAvg tinyint = 0
AS
BEGIN
SET NOCOUNT ON;
if #NeedAvg = 1
Update #TempData set AvgValue = 1
Update #TempData set Value = -1;
END
Then, this sp is called in outer sp with the following code:
USE [BN]
--GO
--DBCC FREEPROCCACHE;
GO
Create table #TempData
(
tele_time datetime
, Value float
--, AvgValue float
)
Create clustered index IXTemp on #TempData(tele_time);
insert into #TempData(tele_time, Value ) values( GETDATE(), 50 ); --sample data
declare
#ID int,
#UpdAvg int;
select
#ID = 1000,
#UpdAvg = 1
;
Exec dbo.tempdata_proc #ID, #UpdAvg ;
select * from #TempData;
drop table #TempData
This code throws an error: Msg 207, Level 16, State 1, Procedure tempdata_proc, Line 8: Invalid column name "AvgValue".
But if only I uncomment declaration AvgValue float - everything works OK.
The question: is there any workaround letting the stored proc code remain the same and providing a tip to the optimizer - skip this because AvgValue column will not be used by the sp due to params passed.
Dynamic SQL is not a welcomed solution BTW. Using alternative to #TempData tablename is undesireable solution according to existing tsql code (huge modifications necessary for that).
Tried SET FMTONLY, tempdb.tempdb.sys.columns, try-catch wrapping without any success.
The way that stored procedures are processed is split into two parts - one part, checking for syntactical correctness, is performed at the time that the stored procedure is created or altered. The remaining part of compilation is deferred until the point in time at which the store procedure is executed. This is referred to as Deferred Name Resolution and allows a stored procedure to include references to tables (not just limited to temp tables) that do not exist at the point in time that the procedure is created.
Unfortunately, when it comes to the point in time that the procedure is executed, it needs to be able to compile all of the individual statements, and it's at this time that it will discover that the table exists but that the column doesn't - and so at this time, it will generate an error and refuse to run the procedure.
The T-SQL language is unfortunately a very simplistic compiler, and doesn't take runtime control flow into account when attempting to perform the compilation. It doesn't analyse the control flow or attempt to defer the compilation in conditional paths - it just fails the compilation because the column doesn't (at this time) exist.
Unfortunately, there aren't any mechanisms built in to SQL Server to control this behaviour - this is the behaviour you get, and anything that addresses it is going to be perceived as a workaround - as evidenced already by the (valid) suggestions in the comments - the two main ways to deal with it are to use dynamic SQL or to ensure that the temp table always contains all columns required.
One way to workaround your concerns about maintenance if you go down the "all uses of the temp table should have all columns" is to move the column definitions into a separate stored procedure, that can then augment the temporary table with all of the required columns - something like:
create procedure S_TT_Init
as
alter table #TT add Column1 int not null
alter table #TT add Column2 varchar(9) null
go
create procedure S_TT_Consumer
as
insert into #TT(Column1,Column2) values (9,'abc')
go
create procedure S_TT_User
as
create table #TT (tmp int null)
exec S_TT_Init
insert into #TT(Column1) values (8)
exec S_TT_Consumer
select Column1 from #TT
go
exec S_TT_User
Which produces the output 8 and 9. You'd put your temp table definition in S_TT_Init, S_TT_Consumer is the inner query that multiple stored procedures call, and S_TT_User is an example of one such stored procedure.
Create the table with the column initially. If you're populating the TEMP table with SPROC output just make it an IDENTITY INT (1,1) so the columns line up with your output.
Then drop the column and re-add it as the appropriate data type later on in the SPROC.
The only (or maybe best) way i can thing off beyond dynamic SQL is using checks for database structure.
if exists (Select 1 From tempdb.sys.columns Where object_id=OBJECT_ID('tempdb.dbo.#TTT') and name = 'AvgValue')
begin
--do something AvgValue related
end
maybe create a simple function that takes table name and column or only column if its always #TempTable and retursn 1/0 if the column exists, would be useful in the long run i think
if dbo.TempTableHasField('AvgValue')=1
begin
-- do something AvgValue related
end
EDIT1: Dang, you are right, sorry about that, i was sure i had ... this.... :( let me thing a bit more

Informix SQL - What is wrong with this simple stored procedure &| trigger syntax?

IBM Informix Dynamic Server Version 11.50.FC6
I am trying to execute a simple stored procedure from within an update trigger. Together, they are used to update a field with the current timestamp when another field in the same row is updated.
Table sp_test:
id (serial int, unique, not null, primary key)
stat (char(1), not null, default="A")
add_date (date, not null, default today)
upd_date (date, null)
The stored procedure code is:
create procedure upd_row_date_proc (cid int)
update sproc_trig_rec set upd_date = current where id = cid;
end procedure;
This executes fine and creates the routine, but the trigger I am trying to implement on updates is not working.
The trigger code is:
create trigger upd_row_date_trig
update of stat on sproc_trig_rec
after (execute procedure upd_row_date_proc(id));
I've tried a bunch of syntax variations, but cannot get it to work.
I usually get my error on the ( char of the 3rd line. Here's the error code:
201: A syntax error has occurred.
Error in line 3
Near character position 0
Does anyone know what I'm doing wrong in the syntax of the trigger? Could this type of updating be defined in the creation of the table, or do I need to accomplish it by doing it the way described above?
Thanks for any help
This finally worked for me
create trigger ken_trig
update of stat on sproc_trig_rec
referencing old as ken_pre_upd
for each row (execute procedure ken_proc(ken_pre_upd.id));

Inserting multiple rows with SQL where a record does not exist

I want to insert multiple rows of data into a MySQL database, but only when my order_id field is unique. This is the current query I have, which doesn't work. Lets say a record with an order_id of 2 is already in the table:
INSERT INTO conversion
(user_id,url_id,order_id,sale,commission,transaction_date,process_date)
VALUES (1,1,1,'32',0.3995,'2010-11-15 12:15:18','2010-11-15 12:15:18'),
(3,6,2,'*not-available*',0.001975,'2010-11-15 12:15:18','2010-11-15 12:15:18')
WHERE (order_id <> 3);
Any help is appreciated.
Tom
Solved by using REPLACE.
Example:
REPLACE INTO conversion (user_id,url_id,order_id,sale,commission,transaction_date,process_date) VALUES (1,1,3,'32',0.3995,'2010-11-15 12:50:31','2010-11-15 12:50:31'),(1,2,2,'*not-available*',0.001975,'2010-11-15 12:50:31','2010-11-15 12:50:31');
url: http://dev.mysql.com/doc/refman/5.0/en/replace.html
Thanks all.
INSERT doesn't support the WHERE clause because if you're inserting it implies that the record doesn't currently exist, so therefore there would be nothing for the WHERE clause to look at.
The way to do it in the example you've given is simply not to call the INSERT statement if the order_id field in your insert doesn't match the criteria you want.
If you're calling INSERT multiple times, you'd have some sort of code (either SQL or an external program) which loops through the rows you're inserting; this would be where you'd filter it.
If I am in a similar situation, I would create a stored procedure to handle the logic of figuring out whether an order_id already exists.
--Run this first
--It will create a stored procedure call InsertConversion
--Begin of stored procedure
CREATE PROCEDURE InsertConversion
#user_id int,
#url_id int,
#order_id int,
#sale varchar(5),
#commission money,
#transaction_date datetime,
#process_date datetime
AS
BEGIN
SET NOCOUNT ON;
if not exists(select order_id from conversion where order_id = #order_id)
begin
INSERT INTO conversion(user_id, url_id, order_id, sale, commission, transaction_date, process_date)
VALUES(#user_id, #url_id, #order_id, #sale, #commission, #transaction_date, #process_date)
end
END
GO
--End of stored procedure
Once the store procedure created, you can execute it and pass in the same values as you would pass into an INSERT/VALUES statement:
exec InsertConversion 1,1,1,'32',0.3995,'2010-11-15 12:15:18','2010-11-15 12:15:18'
exec InsertConversion 3,6,2,'*not-available*',0.001975,'2010-11-15 12:15:18','2010-11-15 12:15:18'
If you want to be fancy, you can include a couple of 'print' statement in the store procedure to tell you whether it inserts the record.

MySQL How to INSERT INTO [temp table] FROM [Stored Procedure]

This is very similar to question 653714, but for MySQL instead of SQL Server.
Basically, I have a complicated select that is the basis for several stored procedures. I would like to share the code across the stored procedures, however, I'm not sure how to do this. One way I could do this is by making the shared select a stored procedure and then calling that stored procedure from the other ones. I can't figure out how to work with the result set of the nested stored procedure. If I could put them in a temp table I could use the results effectively, but I can't figure out how to get them in a temp table. For example, this does not work:
CREATE TEMPORARY TABLE tmp EXEC nested_sp();
The problem is, Stored Procedures don't really return output directly. They can execute select statements inside the script, but have no return value.
MySQL calls stored procedures via CALL StoredProcedureName(); And you cannot direct that output to anything, as they don't return anything (unlike a function).
MySQL Call Command
You cannot "SELECT INTO" with stored procedures.
Create the temporary table first and have your stored procedure to store the query result into the created temporary table using normal "INSERT INTO". The temporary table is visible as long as you drop it or until the connection is closed.
i know this is coming really late but since it took me ages to find a real solution i might as well share. I worked on an example that is below.
the tables created are:
CREATE TABLE BOOK(
B_ID INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY(B_ID),
TITLE VARCHAR(100),
DESCRIPTION VARCHAR(30),
PRICE DOUBLE);
CREATE TABLE BOOK_COMMENT(
PRIMARY KEY(B_C_ID),
B_C_ID INT NOT NULL AUTO_INCREMENT,
REMARK VARCHAR(120),
B_ID INT,
FOREIGN KEY(B_ID) REFERENCES BOOK(B_ID));
CREATE TABLE AUTHOR(
A_ID INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY(A_ID),
A_NAME CHAR(15),
B_ID INT,
FOREIGN KEY(B_ID) REFERENCES BOOK(B_ID));
DELIMITER
CREATE PROCEDURE BOOK_IMPORTANT( _PRICE DOUBLE, _B_ID INT, A_NAME CHAR(15), _BD_ID INT)
BEGIN
INSERT INTO BOOK(PRICE)
VALUES(_PRICE);
SET _B_ID=LAST_INSERT_ID();
INSERT INTO BOOK_COMMENT(B_ID)
VALUES(_B_ID);
SET _BD_ID=LAST_INSERT_ID();
INSERT INTO AUTHOR(A_NAME,B_ID)
VALUES(A_NAME,_BD_ID);
END
then use the following to insert the values.
CALL BOOK_IMPORTANT('0.79',LAST_INSERT_ID(),'',LAST_INSERT_ID());
LAST_INSERT_ID() takes the last auto increment of the table and inserts it into the referencing column of the child table.
In the procedure parameters _B_ID and _BD_ID represent the B_ID since I need B_ID as a foreign key in both tables.
Sorry for the excess wording. All the other guys expect you to automatically know how to do it. Hope it helps
My first reaction was "That sounds like a view to me". Doesn't that abstract it enough so you can just add the variability into an SP per case?
Anything that adds a temp table that wouldn't otherwise be there is a very likely antipattern.
Maybe it's a closed topic, but I would like to offer a solution based on the properties of MySQL temporary tables. First, the way to create the temporary table would not be to call the stored procedure "CREATE TEMPORARY TABLE tmp EXEC nested_sp ();". The query is to the temporary table of "infrastructure", (to name it somehow).
To achieve the desired result, it is necessary to create 2 stored procedures, the first stored procedure processes the data and fills the temporary "infrastructure" table, the second stored procedure, reads this table and continues with the process and finally "DROP" the "infrastructure" table
This is the first stored procedure:
CREATE DEFINER = 'root'#'localhost'
PROCEDURE cajareal.priv_test()
BEGIN
CREATE TEMPORARY TABLE IF NOT EXISTS tmp(
column1 TEXT
, column2 TEXT
, column3 TEXT
);
INSERT INTO tmp(column1, column2 , column3) VALUES(CURDATE(), CURRENT_DATE(), CURRENT_TIMESTAMP());
END
This is the second stored procedure:
CREATE DEFINER = 'root'#'localhost'
PROCEDURE cajareal.priv_caller()
BEGIN
CALL priv_test;
-- Read data of "infrastructure" table
SELECT * FROM tmp;
-- Do the business logic
-- Delete the "infrastructure" table
DROP TABLE tmp;
END
I use this technique to analyze a string and convert it to the table