I'm writing an Informix procedure.
I created a temp table, but I want to export this data in a text document.
I can't use an UNLOAD statement in SPL; can somebody help me?
The UNLOAD statement is not recognized by the server. The programs such as DB-Access, ISQL and I4GL recognize it and simulate it as a statement (basically, as a SELECT, of course, reading the data from the server and writing it to a file on the client). Consequently, the statement won't work in SPL — Stored Procedure Language — because that is run by the server on the server. (One reason for the disconnect is that the server can't write direct to a file on the client.)
So, you'll need to do things differently. The solution suggested by Ricardo Henriques in his answer is entirely sensible, as long as the file being created on the server machine is OK.
Will you execute it on the Informix Server or a client? Which is the IDS version?
Here is a way using external tables, the file is stored on the server host:
CREATE PROCEDURE sp_unload()
CREATE TEMP TABLE temp1(
col1 INT
) WITH NO LOG;
INSERT INTO temp1 VALUES (1);
INSERT INTO temp1 VALUES (2);
INSERT INTO temp1 VALUES (3);
CREATE EXTERNAL TABLE temp1_ext
SAMEAS temp1
USING (
DATAFILES ("DISK:/home/informix/temp.dat")
);
INSERT INTO temp1_ext SELECT * FROM temp1;
DROP TABLE temp1_ext;
DROP TABLE temp1;
END PROCEDURE;
If what you're looking is to store on a client server you'll have to provide what kind of client you use (OS and the way you connect to the IDS).
If your using the dbaccess you can use the SP to create the temporary table and after submit the unload of the data.
If using other clients probably your best option is to rewrite your SP as a function that returns more than one value from more than one row..
Then, iterate it and write to a file.
Related
I have written a stored procedure that includes a SELECT on a number of tables that applies logic to calculate values and transforms some of the data.
I have been asked if I can exclude records from the resultset in the stored procedure and write the record to a separate log table. I was looking to loop through the result set from the SELECT statement and delete the record I want to exclude once I have written it to a table. At the moment I am struggling to find the syntax to delete from the result set of a SELECT statement in a stored procedure and can only find how to use the cursor reference to delete from the original database table.
I need to remove the records in the same stored procedure and I am looking to avoid duplicating the logic by using some of the logic to find the records to include and repeat some of the logic again to be able to find the records to exclude. The only other alternative I can think of is using a temporary table, but I think what I am trying to do should be possible.
Any help appreciated.
When you have an open cursor in a stored procedure (or in an application), you can perform positioned deletes. You can execute the statement,
DELETE WHERE CURRENT OF cursorname;
Please be aware that by default issuing a COMMIT statement will close any open cursors, so if you plan to have this delete operation spread over multiple transactions you will need to declare your cursors using WITH HOLD.
I have an SSIS routine that reads from a very dynamic table and inserts whichever rows it finds into a table in a different database, before truncating the original source table.
Due to the dynamic nature of the source table this truncation not surprisingly leads to rows not making it to the second database.
What is the best way of deleting only those rows that have been migrated?
There is an identity column on the source table but it is not migrated across.
I can't change either table schema.
A option, that might sound stupid but it works, is to delete first and use the OUTPUT clause.
I created a simple control flow that populates a table for me.
IF EXISTS
(
SELECT 1 FROM sys.tables AS T WHERE T.name = 'DeleteFirst'
)
BEGIN
DROP TABLE dbo.DeleteFirst;
END
CREATE TABLE dbo.DeleteFirst
(
[name] sysname
);
INSERT INTO
dbo.DeleteFirst
SELECT
V.name
FROM
master.dbo.spt_values V
WHERE
V.name IS NOT NULL;
In my OLE DB Source, instead of using a SELECT, DELETE the data you want to go down the pipeline and OUTPUT the DELETED virtual table. Somethinng like
DELETE
DF
OUTPUT
DELETED.*
FROM
dbo.DeleteFirst AS DF;
It works, it works!
One option would be to create a table to log the identity of your processed records into, and then a separate package (or dataflow) to delete those records. If you're already logging processed records somewhere then you could just add the identity there - otherwise, create a new table to store the data.
A second option: If you're trying to avoid creating additional tables, then separate the record selection and record processing into two stages. Broadly, you'd select all your records in the control flow, then process them on-by-one in the dataflow.
Specifically:
Create a variable of type Object to store your record list, and another variable matching your identity type (int presumably) to store the 'current record identity'.
In the control flow, add an Execute SQL task which uses a query to build a list of identity values to process, then stores them into the recordlist variable.
Add a Foreach Loop Container to process that list; the foreach task would load the current record identifier into the second variable you defined above.
In the foreach task, add a dataflow to copy that single record, then delete it from the source.
There's quite a few examples of this online; e.g. this one from the venerable Jamie Thomson, or this one which includes a bit more detail.
Note that you didn't talk about the scale of the data; if you have very large numbers of records the first suggestion is likely a better choice. Note that in both cases you lose the advantage of the table truncation (because you're using a standard delete call).
(1) When you open multiple cursors in a stored procedure, and then use a JDBC callable statement to iterate through the result sets, each in turn, are the order in which they are returned the same order in which they cursors are opened in the stored procedure? Or reverse of that? Or....?
(2) Is there a way to specify by sequence number or name which result set to process first?
For 1: The order of returned resultsets is undefined for JDBC, so it will depend on your actual database system. That said, it would be highly illogical for a stored procedure to return results in a different order than the order they are produced by the stored procedure.
For 2: Once again, this is not defined by JDBC. However I haven't heard of database systems that would allow you to control the order of returned results by any means other than their order in the stored procedure.
I thought I would use a stored routine to clean up some of my more complex SQL statements. From what I've read, it seems impossible to use a stored procedure within an sql statement, and a stored function only returns a single value when what I need is a result set. I am using mySQL v5.0
SELECT p.`id`, gi.`id`
FROM `sport`.`players` AS p JOIN `sport`.`gameinstances` AS gi
ON p.`id` = gi.`playerid`
WHERE (p.`playerid` IN (CALL findPlayers`("Canada", "2002")))
AND (gi.`instanceid` NOT IN (CALL findGameInstances`("Canada", "2002")));
For example, the procedures 'findPlayers' and 'findGameInstances' are are stored routines that execute some SQL and return a result set. I would prefer not to include their code directly within the statement above.
I don't know if mysql can use any of these techniques, but in SQl server I would try one of two different things (at least it might give you something to look for in th emysql documentation):
First a table values used defined function then join to that
Second, insert the results set of the sp into a temp table then join to the tem table
You could also consider putting the complicated logic in a view and then just adding the where clause after joining to the view. This won't work if your stored proc does dynamic things a view can't do, but it is a possibilty.
Let's say I have 'myStoredProcedure' that takes in an Id as a parameter, and returns a table of information.
Is it possible to write a SQL statement similar to this?
SELECT
MyColumn
FROM
Table-ify('myStoredProcedure ' + #MyId) AS [MyTable]
I get the feeling that it's not, but it would be very beneficial in a scenario I have with legacy code & linked server tables
Thanks!
You can use a table value function in this way.
Here is a few tricks...
No it is not - at least not in any official or documented way - unless you change your stored procedure to a TVF.
But however there are ways (read) hacks to do it. All of them basically involved a linked server and using OpenQuery - for example seehere. Do however note that it is quite fragile as you need to hardcode the name of the server - so it can be problematic if you have multiple sql server instances with different name.
Here is a pretty good summary of the ways of sharing data between stored procedures http://www.sommarskog.se/share_data.html.
Basically it depends what you want to do. The most common ways are creating the temporary table prior to calling the stored procedure and having it fill it, or having one permanent table that the stored procedure dumps the data into which also contains the process id.
Table Valued functions have been mentioned, but there are a number of restrictions when you create a function as opposed to a stored procedure, so they may or may not be right for you. The link provides a good guide to what is available.
SQL Server 2005 and SQL Server 2008 change the options a bit. SQL Server 2005+ make working with XML much easier. So XML can be passed as an output variable and pretty easily "shredded" into a table using the XML functions nodes and value. I believe SQL 2008 allows table variables to be passed into stored procedures (although read only). Since you cited SQL 2000 the 2005+ enhancements don't apply to you, but I mentioned them for completeness.
Most likely you'll go with a table valued function, or creating the temporary table prior to calling the stored procedure and then having it populate that.
While working on the project, I used the following to insert the results of xp_readerrorlog (afaik, returns a table) into a temporary table created ahead of time.
INSERT INTO [tempdb].[dbo].[ErrorLogsTMP]
EXEC master.dbo.xp_readerrorlog
From the temporary table, select the columns you want.