After creating a cursor readwrite by a select query, I update some values in it, and then delete rows that do not match some criteria.
the problem here is:
For example; If I have 30 record and update them, then delete 10, the record number will not change! It will still be 30. Is there a way to tell the cursor to refresh or reload so the rec number would match exactly what I have?
I'm running a select to create cursor read write:
update
delete
But the record number doesn't change, even though when I browse my cursor there are lesser records than before?
You can do something nearly equivalent to 'pack', which is just run a query against the cursor that eliminates the deleted rows:
SELECT * FROM mycursor INTO CURSOR mycursor READWRITE WHERE NOT DELETED()
When you DELETE records in FoxPro, the records are marked as deleted but not removed until a PACK command is issued. Since attempting to PACK a cursor with result in a "Invalid operation for the cursor." error you must issue your COUNT and other commands with a WHERE NOT DELETED() clause so you only operate on the records that have not been marked as deleted.
Regarding browsing the table and not seeing the deleted records, I suspect you have SET DELETED ON which will hide the deleted records from the browse window.
SELECT * FROM myTable INTO CURSOR myCusror READWRITE
COUNT FOR NOT DELETED()
GO TOP
DELETE NEXT 1
COUNT FOR DELETED()
COUNT FOR NOT DELETED()
COPY TO myNewTable FOR NOT DELETED()
If the goal is to be able to make changes and have them saved when you want, you may be better off just using the actual table and turning buffering on.
If you are using Visual Foxpro and have your tables in a DataBase Container, you could use updatable views to accomplish this. Views are basically the same as a cursor, but after you are done editing you can issue a TableUpdate() to send the changes to the Table or a TableRevert() to undone the changes.
Also, a Requery() will refresh the view you are working with.
Related
I am sorry in advance if I sound noob. I am looking through code for stored procedure and I came across:
select
...
into
....
from
....
where
....
for update;
I don't understand what is the purpose of for update;.
I do understand normal update, similar to: http://www.mkyong.com/oracle/oracle-stored-procedure-update-example/. But not able to get my head around for update; and its purpose.
I looked around but could not find clear explanation.
From the document:
The SELECT FOR UPDATE statement allows you to lock the records in the
cursor result set. You are not required to make changes to the records
in order to use this statement. The record locks are released when the
next commit or rollback statement is issued.
Also refer the Oracle docs which says:
The FOR UPDATE clause lets you lock the selected rows so that other
users cannot lock or update the rows until you end your transaction.
You can specify this clause only in a top-level SELECT statement, not
in subqueries.
So the purpose is quite clear it is used when you want to lock your rows during a transaction so that it cannot be used by some other transaction.
You can also refer: FOR UPDATE Clause in a SELECT Statement to get an idea as to how we can use it.
There is SQL Server 2012 database that is used by three different applications. In that database there is a table that contains ~500k rows and for some mysterious reason this table gets emptied every now and then. I think this is possibly caused by:
A delete query without a where clause
A delete query in a loop gone wild
I am trying to locate the cause of this issue by reviewing code but no joy. I need an alternate strategy. I think I can use triggers to detect what/why all rows get deleted but I am not sure how to go about this. So:
Can I use triggers to check if a query is attempting to delete all rows?
Can I use triggers to log the problematic query and the application that issues that query?
Can I use triggers to log such actions into a text file/database table/email?
Is there a better way?
You can use Extended Events to monitor your system.
Here a simple screen shot where are.
A simple policy can monitor for delete and truncate statements.
When this events are raised details are written into file.
Here a screen with details (you can configure the script to collect more data) collected for delete statement.
Here the script used, modify the output file path
CREATE EVENT SESSION [CheckDelete] ON SERVER
ADD EVENT sqlserver.sql_statement_completed(SET collect_statement=(1)
ACTION(sqlserver.client_connection_id,sqlserver.client_hostname)
WHERE ([sqlserver].[like_i_sql_unicode_string]([statement],N'%delete%') OR [sqlserver].[like_i_sql_unicode_string]([statement],N'%truncate%')))
ADD TARGET package0.event_file(SET filename=N'C:\temp\CheckDelete.xel',max_file_size=(50))
WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=OFF)
GO
This is a possibility that may help you. It creates a trigger on Table1 that sends an email when a process DELETEs more than 100 records. I'd modify the message to include some useful data like:
Process ID (##SPID)
Host (HOST_NAME())
Name of app (APP_NAME())
And possibly the entire query
CREATE TRIGGER Table1MassDeleteTrigger
ON dbo.Activities
FOR DELETE
AS
DECLARE #DeleteCount INT = (SELECT COUNT(*) FROM deleted)
IF(#DeleteCount > 100)
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'MailProfileName',
#recipients = 'admin#yourcompany.com',
#body = 'Something is deleting all your data!',
#subject = 'Oops!';
I'm using SQL Server 2012, and I'm debugging a store procedure that do some INSERT INTO #temporal table SELECT.
There is any way to view the data selected in the command (the subquery of the insert into?)
There is any way to view the data inserted and/or the temporal table where the insert maked the changes?
It doesn't matter if is the total rows, not one by one
UPDATE:
Requirements from AT Compliance and Company Policy requires that any modification can be done in the process of test and it's probable this will be managed by another team. There is any way to avoid any change on the script?
The main idea is that the AT user check in their workdesktop the outputs, copy and paste them, without make any change on environment or product.
Thanks and kind regards.
If I understand your question correctly, then take a look at the OUTPUT clause:
Returns information from, or expressions based on, each row affected
by an INSERT, UPDATE, DELETE, or MERGE statement. These results can be
returned to the processing application for use in such things as
confirmation messages, archiving, and other such application
requirements.
For instance:
INSERT INTO #temporaltable
OUTPUT inserted.*
SELECT *
FROM ...
Will give you all the rows from the INSERT statement that was inserted into the temporal table, which were selected from the other table.
Is there any reason you can't just do this: SELECT * FROM #temporal? (And debug it in SQL Server Management Studio, passing in the same parameters your application is passing in).
It's a quick and dirty way of doing it, but one reason you might want to do it this way over the other (cleaner/better) answer, is that you get a bit more control here. And, if you're in a situation where you have multiple inserts to your temp table (hopefully you aren't), you can just do a single select to see all of the inserted rows at once.
I would still probably do it the other way though (now I know about it).
I know of no way to do this without changing the script. Howeer, for the future, you should never write a complex strored proc or script without a debug parameter that allows you to put in the data tests you will want. Make it the last parameter with a default value of 0 and you won't even have to change your current code that calls the proc.
Then you can add statements like the below everywhere you will want to check intermediate results. Further in debug mode you might always rollback any transactions so that a bug will not affect the data.
IF #debug = 1
BEGIN
SELECT * FROM #temp
END
I'm pretty new to Oracle so not entirely sure this is possible, or if perhaps I'm going about it the wrong way but here goes ...
Part of an old feeder script I'm fixing is looping through ~ 20 tables (could change anytime) to populate relevant staging tables. This part is currently very basic:
...
INSERT INTO staging_tbl_1(
SELECT *
FROM source_tbl_1
);
INSERT INTO staging_tbl_2(
SELECT *
FROM source_tbl_2
);
...
Some of the fields in the source database have different constraints etc which means that every now and then it will throw an exception and the feeder will stop. What I'm hoping to do is create a procedure within the existing feeder package to loop through each row in each record before it is inserted and simply wrap it in an exception block. This way it can be logged without causing the feeder to stop.
Essentially I'm chasing something like this:
BEGIN procedure_x(source_record, staging_record)
-- Perform validation to ensure records exit
-- Loop through all record rows
FOR row IN (SELECT * FROM source_record) LOOP
-- Wrap in exception block
-- Insert into staging record
-- Log exception if it occurs
END LOOP;
END
I've attempted ref cursors however in order to get them to work I would also need to know the rowtype in advance (from my limited understanding). I've also tried execute immediate however I cannot find a way to loop this in an appropriate way. Are there any other ways to tackle this?
Additional:
I realise that we really should be fixing the source of the problem rather than going about it like this, unfortunately it is far outside my area of influence.
It is possible to do this without making a separate procedure and just wrap all of the table references in a loop, however I'd like to leave this as a last resort.
Oracle has functionality for logging of DML errors. Use it with single SQL statements. Don't go row-by-row and make your processes crawl.
http://docs.oracle.com/cd/B19306_01/server.102/b14231/tables.htm#ADMIN10261
Each time I perform a query (INSERT, DELETE,UPDATE). After Do I need to do Select * From Table, so my info can be seen on the Grid control?
For example:
UniQuery1 is my dataset.
I'm using a TDBADvListView control.
UniQuery1.Close;
UniQuery1.SQL.Clear;
SQL_QUERY:= 'insert into ListaCamiones(Tablilla,Marca,Modelo,Color) Values ('
+QuotedStr(a1)+','+
QuotedStr(a2)+','+
QuotedStr(a3)+','+
QuotedStr(a4)+')';
UniQuery1.SQL.Text := SQL_QUERY;
UniQuery1.Execute;
Do I need to do, Select * From ListaCamiones;
So I can see the information back on my TDBADvListView?
The answer is both yes and no!
Yes in that you do have to perform a SELECT query again in order to aggregate the modified recordset, no in that you don't have to perform the query as a separate execution.
If you append a semicolon at the end of your INSERT/UPDATE/DELETE query string, and immediately follow that by the desired SELECT query, your call to Execute will simultainiously update the records and aggregate the updated recordset for display.
Additionally, I would change the way you're building your SQL string too!
const
INSERT_QUERY_STRING = 'INSERT INTO ListaCaminoes(Tablilla, Marca, Modelo, Color) VALUES ("%s", "%s", "%s", "%s"); SELECT * FROM ListaCaminoes';
// Now inside your method
UniQuery1.SQL.Text := Format(INSERT_QUERY_STRING, [a1, a2, a3, a4]);
UniQuery1.Execute;
Hope it helps!
In general, yes, because in my experience when you make database changes via SQL statements:
no database component automatically refreshes the query,
no database can refresh the data in your application when the data
has changed in the database.
I recommend that you use a separate query component (UniQuery2) to execute your SQL statement. The you can use the ReQuery method of your Query to re-execute your original query (UniQuery1). Depending on the database components you are using, your local cursor may be reset.
Alternately you can Append/Insert to add records and Edit to change records of UniQuery1. This avoids the need to re-execute your original query because the changes are added to the dataset records buffered locally by the Query component. But, re-executing the query is necessary to get records that were added/edited by other users since your query was last executed.
If you just inserted the Information to the Database you have got it already!
In some SQL-Variants (in mySQL I am shure) you can have the command "insert_id()" from the API, that returns the AUTO_INCREMENT - value of the last inserted Dataset.
If you just want to get this ID, it is the way to go (on mySQL, like I said), but if you want to have other data you have to Query it again. In a combined query (like posted before) or in two seperate queries.
Glad to help!