SQLite Find ROWID of most recent or next ROWID - sqlite

So I have a table with data about an image. The table looks something like this...
ROWID|title|description|file_path
The file path contains the name of the image. I want to rename the image to match the ROWID.
How do I get the latest ROWID? I need to also account for rows that have been deleted as I am using this as an autoincremented primary key. Because, if a row within the table has been deleted it is possible for the table to look like this...
1|title A|description A|..\fileA.jpg
2|title B|description B|..\fileB.jpg
5|title E|description E|..\fileE.jpg
7|title G|description G|..\fileG.jpg
On top of that there could be one or more rows that have been deleted so the next ROWID could be 10 for all I know.
I also need to account for an fresh new table or a table that has had all data deleted and the next ROWID could be 1000.
In summary, I guess the real question is; Is there a way to find out what the next ROWID will be?

If you have specified AUTOINCREMENT in primary key field and table is not empty this query will return latest ROWID for table MY_TABLE:
SELECT seq
FROM sqlite_sequence
WHERE name = 'MY_TABLE'

What language? Looks like the c API has the following function:
sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
http://www.sqlite.org/c3ref/last_insert_rowid.html
You could also just do:
select MAX(rowid) from [tablename];

Unfortunately neither of these methods completely worked the way I needed them to, but what i did end up doing was....
insert data into table with the fields I needed the rowid for filled with 'aaa'
then updated the rows with the data.
This seemed to solve my current issue. Hopefully it doesn't cause another issue down the road.

I think last_insert_rowid is what you want, usually.
Note that the rowid behavior is different depending on the autoincrement flag - either it will monotonically increase, or it will assume any free id. This will not usually affect any smaller use cases though.

Related

Efficient insertion of row and foreign table row if it does not exist

Similar to this question and this solution for PostgreSQL (in particular "INSERT missing FK rows at the same time"):
Suppose I am making an address book with a "Groups" table and a "Contact" table. When I create a new Contact, I may want to place them into a Group at the same time. So I could do:
INSERT INTO Contact VALUES (
"Bob",
(SELECT group_id FROM Groups WHERE name = "Friends")
)
But what if the "Friends" Group doesn't exist yet? Can we insert this new Group efficiently?
The obvious thing is to do a SELECT to test if the Group exists already; if not do an INSERT. Then do an INSERT into Contacts with the sub-SELECT above.
Or I can constrain Group.name to be UNIQUE, do an INSERT OR IGNORE, then INSERT into Contacts with the sub-SELECT.
I can also keep my own cache of which Groups exist, but that seems like I'm duplicating functionality of the database in the first place.
My guess is that there is no way to do this in one query, since INSERT does not return anything and cannot be used in a subquery. Is that intuition correct? What is the best practice here?
My guess is that there is no way to do this in one query, since INSERT
does not return anything and cannot be used in a subquery. Is that
intuition correct?
You could use a Trigger and a little modification of the tables and then you could do it with a single query.
For example consider the folowing
Purely for convenience of producing the demo:-
DROP TRIGGER IF EXISTS add_group_if_not_exists;
DROP TABLE IF EXISTS contact;
DROP TABLE IF EXISTS groups;
One-time setup SQL :-
CREATE TABLE IF NOT EXISTS groups (id INTEGER PRIMARY KEY, group_name TEXT UNIQUE);
INSERT INTO groups VALUES(-1,'NOTASSIGNED');
CREATE TABLE IF NOT EXISTS contact (id INTEGER PRIMARY KEY, contact TEXT, group_to_use TEXT, group_reference TEXT DEFAULT -1 REFERENCES groups(id));
CREATE TRIGGER IF NOT EXISTS add_group_if_not_exists
AFTER INSERT ON contact
BEGIN
INSERT OR IGNORE INTO groups (group_name) VALUES(new.group_to_use);
UPDATE contact SET group_reference = (SELECT id FROM groups WHERE group_name = new.group_to_use), group_to_use = NULL WHERE id = new.id;
END;
SQL that would be used on an ongoing basis :-
INSERT INTO contact (contact,group_to_use) VALUES
('Fred','Friends'),
('Mary','Family'),
('Ivan','Enemies'),
('Sue','Work colleagues'),
('Arthur','Fellow Rulers'),
('Amy','Work colleagues'),
('Henry','Fellow Rulers'),
('Canute','Fellow Ruler')
;
The number of values and the actual values would vary.
SQL Just for demonstration of the result
SELECT * FROM groups;
SELECT contact,group_name FROM contact JOIN groups ON group_reference = groups.id;
Results
This results in :-
1) The groups (noting that the group "NOTASSIGNED", is intrinsic to the working of the above and hence added initially) :-
have to be careful regard mistakes like (Fellow Ruler instead of Fellow Rulers)
-1 used because it would not be a normal value automatically generated.
2) The contacts with the respective group :-
Efficient insertion
That could likely be debated from here to eternity so I leave it for the fence sitters/destroyers to decide :). However, some considerations:-
It works and appears to do what is wanted.
It's a little wasteful due to the additional wasted column.
It tries to minimise the waste by changing the column to an empty string (NULL may be even more efficient, but for some can be confusing)
There will obviously be an overhead BUT in comparison to the alternatives probably negligible (perhaps important if you were extracting every Facebook user) but if it's user input driven likely irrelevant.
What is the best practice here?
Fences again. :)
Note Hopefully obvious, but the DROP statements are purely for convenience and that all other SQL up until the INSERT is run once
to setup the tables and triggers in preparation for the single INSERT
that adds a group if necessary.

Insert into SQLite3 into "middle" of table

I just want to clarify: if you insert a row to a table in sqlite, it appends it to the table, but -- as I learned -- the table is unordered, so there is really not true way to insert a row into the middle of an "ordered table," right?
Is there even a way to make an ordered table without first created a table and then using '...ORDER BY name/id/etc' (i.e. when you insert something it puts itself in the right place)?
SQLite tables are actually stored in rowid order, but this is unlikely to help you because it is unlikely that there is a gap where you want it.
Furthermore, the order in which rows are stored does not matter because there is no guarantee that this is the order in which they are returned.
When you want to SELECT rows in a specific order, you must use ORDER BY.
If your query is too slow, an index on the sorting column might help.

SQLite - How to insert to table with preliminary scan of the fields?

I use a database in my project and when i insert values ​​into a table i need to check if the field already has a value that does not produce an insert.
for exemple:
INSERT INTO myTable (column1) values ('some_value1')
if some_value1 alredy exists in column1 do not insert the value.
Put a unique constraint on myTable.column1. Then, whenever you try to insert a duplicate value, it won't let you as it violates the constraint. You can either catch and handle this error, or just let the DB engine do it's thing automatically.
EDIT: Note that SQLite doesn't allow you to do many alterations to your table, once it's created; so you may have to recreate your table with the constraint in place.
I believe this can be handled using the conflict resolution IGNORE method on SQLite. The code below should do the trick. The column1 here should be set to unique for this.
INSERT OR IGNORE INTO myTable (column1) values ('some_value1')
I'm using the following links for reference;
http://www.sqlite.org/lang_insert.html
http://www.sqlite.org/lang_conflict.html

How to make sure SQLite never create a row with the same ID twice?

I have a SQLite table that looks like this:
CREATE TABLE Cards (id INTEGER PRIMARY KEY, name TEXT)
So each time I create a new row, SQLite is going to automatically assign it a unique ID.
However, if I delete a row and then create a new row, the new row is going to have the ID of the previously deleted row.
How can I make sure it doesn't happen? Is it possible to somehow force SQLite to always give really unique IDs, that are even different from previously deleted rows?
I can do it in code but I'd rather let SQLite do it if it's possible. Any idea?
Look at autoincrement (INTEGER PRIMARY KEY AUTOINCREMENT). It will guarantee this and if the request can't be honored it will fail with SQLITE_FULL.

Should I use an auto-generated Primary Key if I'm just doing a lookup table?

I have a table which has two varchar(Max) columns
Column 1 Column 2
-----------------------
URLRewitten OriginalURL
its part of my url re-writing for an asp.net webforms site.
when a url comes in I do a check to see if its in the table if it is i use the OriginalURL.
My question is, if all I'm doing is querying the table for urls and no other table in the database will ever link to this table does it need a dedicated primary key field? like an auto-number? will this make queries faster?
and also how can I make the query's run as faster?
Edit: I do have a unique constraint on URLRewitten.
Edit: ways i'm using this table..
Query when a new Request comes in.. search on URLRewitten to find OriginalURL
When needing to display a link on the site, i query on the OriginalURL to find the URLRewitten url i should use.
When adding a new url to the table i make sure that it doesn't already exist.
thats all the querys i do.. at the moment.
Both columns together would be unique.
Do you need a primary key? Yes. Always. However, it looks like in your case OriginalURL could be your primary key (I'm assuming that there wouldn't be more than one value for URLRewritten for a given value in OriginalURL).
This is what's known as a "natural key" (where a component of the data itself is, by its nature, unique). These can be convenient, though I have found that they're generally more trouble than they're worth under most circumstances, so yes, I would recommend some sort of opaque key (meaning a key that has no relation to the data in the row, other than to identify a single row). Whether or not you want an autonumber is up to you. It's certainly convenient, though identity columns come with their own set of advantages and disadvantages.
For now I suppose I would advise creating two things:
A primary key on your table of an identity column
A unique constraint on OriginalURL to enforce data integrity.
I'd put one in there anyway... it'll make updating alot easier or duplicating an existing rule...
i.e. this is easier
UPDATE Rules SET OriginalURL = 'http://www.domain.com' WHERE ID = 1
--OR
INSERT INTO Rules SELECT OriginalUrl, NewUrl FROM Rules WHERE ID = 1
Than this
this is easier
UPDATE Rules SET OriginalURL = "http://www.domain.com" WHERE OriginalURL = 'http://old.domain.com'
--OR
INSERT INTO Rules SELECT OriginalUrl, NewUrl FROM Rules WHERE OriginalURL = 'http://old.domain.com'
In terms of performance, if your going to be searching by OriginalURL,
you should add an index to that column,
I would use the OriginalURL as your primary key as I would assume this is unique. Assuming your are using SQL-Server you could create an index on RewrittenURL with OrigionalURL as an "Included column" to speed up the performance of the query.
An identity column can help when you search for recent events:
select top 100 * from table order by idcolumn desc
We'd have to know what kind of queries you are running, before we can search for a way to make them faster.
As you are doing your query on the URLRewritten column I don't think adding an auto-generated primary key would help you.
Have you got an index on your URLRewritten column? If not, create one: that should see a big increase in the speed of your queries (perhaps just make URLRewritten your primay key?).
Yes there should be a Primary Key Because you can set INDEX on that Primary Key for Fast Access
I don't think adding auto generated primary key will make your query faster.
However there are are a few things to consider:
I would not be so sure, that never
ever nothing will link to this table
:(.
I've seen a lot of people asking about
how to i.e. remove duplicates from
table like that -- with primary key
it is much easier.
To make this query
faster we need to
know more about this table and ways
of using it...
In my opinion, every table, must have auto generated primary key (i.e. identity in MSSQL).
I don't believe in unique natural keys.

Resources