I have a stored procedure and which selects data from the database using
DECLARE cursor1 CURSOR WITH RETURN for SELECT...
OPEN cursor1
At this point I would like to delete and change records in the resultset in the same stored procedure. I cannot make these changes in the select.
Can this be done?
I have seen
DELETE WHERE CURRENT OF cursor1
but Data Studio does not like the syntax and underolines 'OF' as an error. I believe the version of Data Studio is only a couple of months old.
Thanks for any help or guidance.
You cannot change the result set without modifying the table itself. When issuing DELETE or UPDATE WHERE CURRENT OF you are actually deleting or updating rows in the underlying table.
Using WHERE CURRENT OF implies looping over the rows in the result set. Note that once you change the cursor position, the new position will be returned to the caller. In other words, after you consume the result set in the procedure itself, you will need to open the cursor once again in order to return the result set to the caller.
Related
Hi I'm pretty much a beginner in SQL, but I would like to know if there is a way to know how old are the records contained in the stored procedure.
For example, if I execute a stored procedure, is there an extra statement that I can add to be able to see this last update date on each row?
When I run the stored procedure, it doesn't have a column that shows that information, but at least I would like to know how old is the data that is displaying.
I have a DBGrid that is updated on a button click. Once updated I have it check each row vs an XML file. If the fields in that row match the data in the XML file, I want to delete that row from the dbgrid only.
The DBgrid is loaded from ADOconnection / Query / Datasource . The main connection is to a DB which is linked to an excel file. The XML file is just a report we get each month. Normally we have to check to make sure all the machines on the excel file is also on the report given to us.. With hundreds of machines I am trying to auto detect any difference.
but I cant figure out how to delete the row in the grid only when it finds a match Thus only the non-Matched items are in the grid.
You can't delete rows from a DBGrid. You delete them from the dataset to which the DBGrid is connected. A DBGrid simply displays the data from a dataset. If you want the row deleted, delete it from that dataset using it's .Delete method.
After reading the edit you made, it looks to me like you should be loading the query data into a TClientDataSet (CDS), and then attaching that CDS to the DBGrid's DataSource. You can then do whatever you want to that CDS without affecting the original data, as long as you don't call the CDS's ApplyUpdates method.
What Ken White says in his answer is 100% correct, but I think there is something else
maybe worth pointing out, especially as you mention XML.
Unlike some other TDataSet descendants, both TClientDataSet and the more modern FireDAC datasets implement the UpdateStatus
property of the dataset and this reflects what has happened to the current record
in the dataset - see the Online Help for details. It is an enumeration [1] declared as
type
TUpdateStatus = (usUnmodified, usModified, usInserted, usDeleted);
You say you want to compare the records with what you have in an XML file and delete
the records which have not been updated "from the DBGrid", which as Ken has said is
not meaningful per se.
However there is another way of going about what you seem to want. If you can load the
data displayed in the dataset feeding the grid from the XML file. then you know
that until you update the dataset, the records must match the XML. So, once the
records have been updated in your app, rather than comparing all the records in the dataset
with their XML counterparts, you could simply delete (from the dataset) the records
whose UpdateStatus is usUnmodified. This is trivial to do using a method like this:
procedure TForm1.DeleteUnmodifiedRecords;
begin
ClientDataSet1.DisableControls;
try
ClientDataSet1.First;
while not ClientDataSet1.Eof do begin
if ClientDataSet1.UpdateStatus = usUnModified then
ClientDataSet1.Delete
else
ClientDataSet1.Next;
end;
finally
ClientDataSet1.EnableControls;
end;
end;
and this will, of course, remove the records from the DBGrid.
Of course, this assumes that you can load the XML data into a TClientDataSet
or a FireDAC dataset, eithe directly or by transforming the XML into a form that
either of these can load using a TXmlTransform component but I won't go
into the details of that here.
[1]: A point to beware of is that usModified does not seem to be the exact logical negation of usUnmodified. This has the slightly surprising consequence that if you
apply a StatusFilter of [usModified] to a CDS, records that have been changed can appear twice, once in their original form and once in their changed form - see fig 6.5 of Cary Jensen's "Delphi in Depth: ClientDataSets", 1st edition.
One option to make rows/records vanish from a dbGrid and other data aware controls is to use the TDataSet's OnFilterRecord and return false for rows you no longer want seen. It does not have any effect on the underlying data - it just filters out what is visible.
procedure TDM1.FDQueryTopicListFilterRecord(DataSet: TDataSet; var Accept: Boolean);
begin
// Check if the row should be shown - set Accept to true if it should, false if not
end;
I need help with the following problem. I have a dbgrid, the underlying query is filtered. I want to apply a new filter but stay at the same row number in the dbgrid. Here is my code:
with qrProperties do
begin
...
MyPoint:=GetBookmark;
Filter:='N<>'+IntToStr(ResultPropertyN);
Filtered:=True;
GotoBookmark(MyPoint);
end;
When it gets executed, an EDBEngineError is raised with a message "Could not find record". My explanation is that the bookmark functions do not take into account the filter and the procedure GotoBookmark searches for a record that is not present in the dbgrid (due to the filter applied). Is there any way to use bookmarks with filters?
Here are a little more details. In my application when I double click on a row in the dbgrid, it disappears (due to the filter applied) but as a result of the filtering the cursor moves to the first row (if I do not use bookmarks). I want it to stay at the same row number that is to go to the record shown immediately after the one that has been deleted.
Your assumption is correct, the record is no longer 'there'.
Wrap GotoBookmark in a try/except and decide what to do in the exception, e.g. go to the first record.
Alternatively you could go to the 'nearest' record you can find. That depends on what you consider 'nearest' and then you would not need bookmarks at all and use e.g. FindNearest.
I have a python program that calls a stored procedure from db2 database. I am using results = cursor.fetchall() to process the results of my stored procedure. However, my stored procedure returns two cursors. results only contains the first one. I need a way to loop through as many cursors as I want. I was hoping fetchmany() would be my answer but it is not.
I need to be able to do multiple result sets as the program I am writing can only call one stored procedure. It would take a lot to go back and make it to be able to call two. Besides with one of these things I need to make 10 cursors return. Everything is dynamic, so the application doesn't know what procedure it is running, it just gets the data and spits it into excel not knowing the meaning. I need one cursor for the data, and the other cursors for different types of counts and totals.
I am looking for a built in function to do this, or maybe even a different library because I have done my share of googling and it looks like pyodbc does not do this for DB2. DB2 is a requirement.
Use the nextset() method of the cursor: https://github.com/mkleehammer/pyodbc/wiki/Cursor#nextset
Sample code:
# fetch rows from first set
rows = cursor.fetchall()
# process first set rows here
# advance to next result set
while (cursor.nextset()):
# fetch rows from next set, discarding first
rows = cursor.fetchall()
# process next set rows here
nextset() will return True if additional result sets are available, and subsequent cursor fetch methods will return rows from the next set. The method returns None if no additional sets are available.
Just a small simplification for the record:
while True:
rows = cursor.fetchall()
# process all result sets in the same place
if not cursor.nextset():
break
I have to develop a report against Sybase and I am calling a stored procedure for the dataset using an exec statement in a text query.
This stored procedure, instead of returning no records when there are none available, returns a table with a different column structure than that which is returned when records are available.
This causes all of my fields to display #ERROR. Is there a way to determine that the data set is going to return this garbage row so that I can hide the rows that are effected and handle the error?
Thanks so much for your help.
Frank
The solution for this is to check the IsMissing property on the dataset field:
Set the row's "Hidden" property to -
=IIF(Fields!FieldThatShouldBeThere.IsMissing,true,false)
Frank