In my Microsoft SQL Server Management if I use this query:
select * from Modules where ModuleTitle like '%MyOldString%'
I can find multiple results with different ModuleIDs like 1, 2, 5, 1257, etc.
So now, I want to backup this ModuleIDs, then change all the string "MyOldString" to "MyNewString" in all that Module Titles, how should I do ?
If change one of them, I can use:
update Modules set ModuleTitle = 'MyNewString' where ModuleID = 1257
But now, I only need to replace the string and all at one for all that in the search results, is it possible ? And I need to backup that ModuleIDs, in case I need to change them back.
You could update it with a replace query:
update Modules
SET ModuleTitle = REPLACE(ModuleTitle,'MyOldString','MyNewString')
WHERE ModuleTitle like '%MyOldString%'
;
First, you can easily change the string using the same WHERE expression as you do for searching.
select * from Modules where ModuleTitle like '%MyOldString%'
You can update using
update Modules set ModuleTitle = 'MyNewString'
where ModuleTitle like '%MyOldString%'
As far as backup, where do you want to back the records up to? Just title or the full record?
One option would be to write a trigger, and automatically back things up into a separate table (containing ID, old title, and an update date). The benefit of the trigger would be the records get logged every time the title changes, not just when your code does it.
CREATE TABLE Module_backup
(Module_ID int,
oldtitle VARCHAR(200),
updDate DATETIME DEFAULT getDate()
)
Add a trigger to the table. Basically, in the trigger, if both INSERTED and DELETED are populated (i.e. an update operation),
INSERT INTO Module_backup(Module_id,oldtitle)
SELECT Module_Id,ModuleTitle FROM DELETED
Related
I refactored a table that stored both metadata and data into two tables, one for metadata and one for data. This allows metadata to be queried efficiently.
I also created an updatable view with the original table's columns, using sqlite's insert, update and delete triggers. This allows calling code that needs both data and metadata to remain unchanged.
The insert and update triggers write each incoming row as two rows - one in the metadata table and one in the data table, like this:
// View
CREATE VIEW IF NOT EXISTS Item as select n.Id, n.Title, n.Author, c.Content
FROM ItemMetadata n, ItemData c where n.id = c.Id
// Trigger
CREATE TRIGGER IF NOT EXISTS item_update
INSTEAD OF UPDATE OF id, Title, Author, Content ON Item
BEGIN
UPDATE ItemMetadata
SET Title=NEW.Title, Author=NEW.Author
WHERE Id=old.Id;
UPDATE ItemData SET Content=NEW.Content
WHERE Id=old.Id;
END;
Questions:
Are the updates to the ItemMetadata and ItemData tables atomic? Is there a chance that a reader can see the result of the first update before the second update has completed?
Originally I had the WHERE clauses be WHERE rowid=old.rowid but that seemed to cause random problems so I changed them to WHERE Id=old.Id. The original version was based on tutorial code I found. But after thinking about it I wonder how sqlite even comes up with an old rowid - after all, this is a view across multiple tables. What rowid does sqlite pass to an update trigger, and is the WHERE clause the way I first coded it problematic?
The documentation says:
No changes can be made to the database except within a transaction. Any command that changes the database (basically, any SQL command other than SELECT) will automatically start a transaction if one is not already in effect.
Commands in a trigger are considered part of the command that triggered the trigger.
So all commands in a trigger are part of a transaction, and atomic.
Views do not have a (usable) rowid.
I need to parameterize a view, and I am doing so by creating a TEMP TABLE which has the parameters for the view.
CREATE TEMP TABLE parms (parm1 INTEGER, parm2 INTEGER);
CREATE VIEW tableview AS ...
The VIEW is rather complex, but it basically uses these two parameters to kick start a recursive CTE, and there isn't any other way that I have found to express the view without these parameters.
The parameters must be stored in a temporary table because each connection should be able to have its own view with different parameters.
In any case, this works fine for creating the view itself, so long as I create the same TEMP TABLE at the start of any queries that use the view, e.g.:
CREATE TEMP TABLE parms (parm1 INTEGER, parm2 INTEGER);
INSERT INTO parms (parm1,parm2) VALUES (5,66);
SELECT * FROM tableview;
I am able to do the same thing to create a trigger to allow inserts on the view:
CREATE TEMP TABLE parms (parm1 INTEGER, parm2 INTEGER);
CREATE TRIGGER tableinsert INSTEAD OF INSERT ON tableview ...
However, when I try to do an actual INSERT (re-creating the TEMP TABLE first as before) I get an error:
no such table: main.parms
If I create a non-temporary table, I do not get this error, but then I have the problem that different connections can't have their own separate views.
I have review the documentation for triggers, and it mentions caveats of using temporary triggers on a non-temporary table, but I don't see anything regarding the reverse.
I did find a reference elsewhere that indicated that "the table... must exist in the same database as the table or view to which the trigger is attached". I thought a temporary table was part of the current database, is this not true? Is there some way to make this true?
I also tried accessing the parms table as temp.parms in the TRIGGER, but got the error:
qualified table names are not allowed on INSERT, UPDATE, and DELETE
statements within triggers
If I can't use a temporary table, is there some way to work around it to accomplish the same thing?
Update: Ok, so it seems to be an SQLite limitation. After digging around a bit in the SQLite source code, it seems to be pretty trivial to allow SELECT access to a temporary table in a trigger. However, allowing UPDATE access appears to be a lot harder.
Temporary objects are created in a separate database named temp, so they are not accessible from triggers in other databases.
The remaining mechanism to get a connection-specific value into a trigger is to use a user-defined function.
I am unsure on how to do this 'best practice' wise.
I have a web application (asp.net VB) that connects to an MS SQL server 2012. Currently when the page loads the app connects to a DB table and gets the last ID and adds 1 to it and displays this to the user. When the user submits the form the new ID is saved to the DB.
The problem being the app may be opened by 2 users at the same time and therefore they will get assigned the same ref number which will cause problems when the data is saved.
How can I assign different numbers to different users if the app is opened at the same time without saving unnecessary data?
You have multiple solutions for this, I'll try to outline a few approaches. (I'll assume that you need to insert things into a DB that I'll call "orders".)
First of all, you can move the ID-generation to the moment when the order is actually inserted, and not at the moment when the user start to enter the data. That way, you do not generate an ID for a user that never completes the form. Also this scenario is easy to accomplish using autoincrementing values in sql server. You can, for example do:
-- create a table with an identity column
create table Orders (
ID int identity(1,1) not null,
Description nvarchar(max) not null
);
-- insert values, without specifying the ID column
insert into Orders (Description) values ()
-- select the row back
-- returns 1, 'My First Order'
select * from Orders;
Another way to do this is to use SQL Server Sequences. These are things that do nothing except generate numbers in a row. They guarantee that the numbers won't be repeated, and always keep count of the current value, i.e.
-- create a sequence
create sequence OrderIdSequence
start with 1
increment by 1;
-- get the next sequence value
select next value for OrderIdSequence
I have an appcelerator titanium project (you don't need to be familiar with the platform to help me) that I am using to create an iOS app. I want to have a database with a table that is filled with several rows for the first time, and then left alone after the first time.
I know you can create a table if it doesn't exist. Is there something similar for Inserting data?
Thanks!
Expanding on MPelletier's response with some Titanium-specific code, you could do the following in your project:
var my_db = Ti.Database.open('nameofdb');
var my_result_set = my_db.execute('SELECT * FROM MyTable');
var records = my_result_set.rowCount;
The records variable will indicate whether or not you have data in your table and then you can act accordingly.
There are a couple of nice ORM-ish utilities out there for Titanium: TiStore and Joli are the two I've used. Both are inspired by ActiveRecord and can be helpful in reducing your DB-related code. They're on Github if you want to know more about them!
There's INSERT OR REPLACE if you want, but you might as well just check against the number of rows on the table:
SELECT COUNT(*) FROM MyTable;
Then decide to enter them on that.
You can create your DB and insert data in it via SQLLiteManager or whatever tool you want and then dump it.
Take the file you dumped, put it in your Titanium project folder (somewhere in the Resources folder).
Then this line of code will take the content of the .sqlite file and insert it in the iOS db:
var db = Ti.Database.install('../your-db.sqlite', 'your-db-name');
Just don't forget the CREATE IF NOT EXISTS statement in your SQL file.
Or use REPLACE instead of INSERT as MPelletier said.
I'm unable to retrieve the latest inserted id from my SQL Server 2000 db using a typed dataset in asp.NET
I have created a tableadapter and I ticked the "Refresh datatable" and "Generate Insert, Update and Delete statements". This auto-generates the Fill and GetData methods, and the Insert, Update, Select and Delete statements.
I have tried every possible solution in this thread
http://forums.asp.net/t/990365.aspx
but I'm still unsuccesfull, it always returns 1(=number of affected rows).
I do not want to create a seperate insert method as the auto-generated insertCommand perfectly suits my needs.
As suggested in the thread above, I have tried to update the InsertCommand SQL syntax to add SELECT SCOPY_IDENTITY() or something similar, I have tried to add a parameter of type ReturnValue, but all I get is the number of affected rows.
Does anyone has a different take on this?
Thanks in advance!
Stijn
I decided to give up, I can't afford to waste any more time on this.
I use the Insert statement after which I do a select MAX(id) query to hget the insert ID
If anyone should have a solution, I'll be glad to read it here
Thanks
Stijn
I successfully found a way to get the incremental id after insert using my table adapter.
My approach is a little different, I'm using a Store procedure to make the insert, so my insert command has all the values but the ID, I made the sp return the ID just calling:
SET #ID=SCOPE_IDENTITY()
and then
COMMIT TRAN
and last line will be
RETURN #ID
Then I searched my table adapter parameters for InsertCommand and set the #RETURNVALUE to the column of the incremental ID of the table, so when it's executed automatically put the return value on the id field.
Hope this help
You need to tell your table's table-adapter to refresh the
data-table after update/insert operation.
This is how you can do that.
Open the properties of TableAdapter -> Default Select Query -> Advnaced options. and Check the option of Refresh the data table. Save the adapter now. Now when you call update on table-adapter, the data-table will be updated [refreshed] after the update/insert operation and will reflect the latest values from database table. if the primary-key or any coloumn is set to auto-increment, the data-table will have those latest value post recent update.
Now you can Call the update as TableAdapterObj.Update(ds.dataTable);
Read latest values from the DataTable(ds.dataTable) coloumns and assign respective values into the child table before update/insert. This will work exactly the way you want.
alt text http://ruchitsurati.net/files/tds1.png