SQLite Swap 2 Primary Key Values In A Column - sqlite

My table student is as follows:
Name
Id
Dave
3414
Bob
2861
The ID is the primary key value that has a unique constraint. I'm trying to swap the two primary key values, so Bob's ID is 3414 and Dave's ID is 2861. What's the quickest way to do this?
UPDATE student SET Id=2861 WHERE Id=3414;
UPDATE student SET Id=3414 WHERE Id=2861;
These two statements won't work as it will create duplicate primary keys.

You can do it in three steps (Wrapped in a transaction so it's atomic as far as other connections to the database are concerned), by first changing one of the PKs to a value that's not already in the database. Negative numbers work well, assuming your PKs are normally values >= 0, which is true of automatically generated rowid/INTEGER PRIMARY KEY values in Sqlite.
BEGIN;
UPDATE student SET Id=-Id WHERE Id=2861;
UPDATE student SET Id=2861 WHERE Id=3414;
UPDATE student SET Id=3414 WHERE Id=-2861;
COMMIT;

Somebody asked something like this here
but it apparently does not work in some versions

Related

How to insert row into 2 tables with a one-to-one relationship in SQL Server

Suppose I have 2 tables with a one-to-one relation:
tblOrder (orderId, orderName, totalPrice, billId)
tblBill (billId, billAmount, cardNumber)
The orderId in tblOrder and billId in tblBill are the primary key and they are both identity keys. Also billId in the tblOrder is the unique foreign key.
In the front end using Asp.net, I want the customers to enter the tblOrder information first into the database, then I want them to enter tblBill information. But I want to automate the process of setting the billId foreign key on the tblOrder. Problem is when multiple users will use the system at same time how can I know which bill will belong to which order?
One solution I thought of was to insert an empty row in tblBill and set that id column value to the tblOrder's billId foreign key. And update the bill information when customer enters the bill information in front end. But it doesn't seem like an optimal solution since one empty row insertion will happen for every purchase.

SQLite: Ordering my select results

I have a table with unique usernames and a bunch of string data I am keeping track of. Each user will have 1000 rows and when I select them I want to return them in the order they were added. Is the following code a necessary and correct way of doing this:
CREATE TABLE foo (
username TEXT PRIMARY KEY,
col1 TEXT,
col2 TEXT,
...
order_id INTEGER NOT NULL
);
CREATE INDEX foo_order_index ON foo(order_id);
SELECT * FROM foo where username = 'bar' ORDER BY order_id;
Add a DateAdded field and default it to the date/time the row was added and sort on that.
If you absolutely must use the order_ID, which I don't suggest. Then at least make it an identity column. The reason I advise against this is because you are relying on side affects to do your sorting and it will make your code harder to read.
If each user will have 1000 rows, then username should not be the primary key. One option is to use the int identity column which all tables have (which optimizes I/O reads since it's typically stored in that order).
Read under "RowIds and the Integer Primary Key" # http://www.sqlite.org/lang_createtable.html
The data for each table in SQLite is stored as a B-Tree structure
containing an entry for each table row, using the rowid value as the
key. This means that retrieving or sorting records by rowid is fast.
Because it's stored in that order in the B-tree structure, it should be fast to order by the int primary key. Make sure it's an alias for rowid though - more in that article.
Also, if you're going to be doing queries where username = 'bob', you should consider an index on the username column - especially there's going to be many users which makes the index effective because of high selectivity. In contrast, adding an index on a column with values like 1 and 0 only leads to low selectivity and renders the index very ineffective. So, if you have 3 users :) it's not worth it.
You can remove the order_id column & index entirely (unless you need them for something other than this sorting).
SQLite tables always have a integer primary key - in this case, your username column has silently been made a unique key, so the table only has the one integer primary key. The key column is called rowid. For your sorting purpose, you'll want to explicitly make it AUTOINCREMENT so that every row always has a higher rowid than older rows.
You probably want to read http://www.sqlite.org/autoinc.html
CREATE TABLE foo (
rowid INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE KEY,
...
Then your select becomes
select * from foo order by rowed;
One advantage of this approach is that you're re-using the index SQLite will already be placing on your table. A date or order_id column is going to mean an extra index, which is just overhead here.

Speed up SQL select in SQLite

I'm making a large database that, for the sake of this question, let's say, contains 3 tables:
A. Table "Employees" with fields:
id = INTEGER PRIMARY INDEX AUTOINCREMENT
Others don't matter
B. Table "Job_Sites" with fields:
id = INTEGER PRIMARY INDEX AUTOINCREMENT
Others don't matter
C. Table "Workdays" with fields:
id = INTEGER PRIMARY INDEX AUTOINCREMENT
emp_id = is a foreign key to Employees(id)
job_id = is a foreign key to Job_Sites(id)
datew = INTEGER that stands for the actual workday, represented by a Unix date in seconds since midnight of Jan 1, 1970
The most common operation in this database is to display workdays for a specific employee. I perform the following select statement:
SELECT * FROM Workdays WHERE emp_id='Actual Employee ID' AND job_id='Actual Job Site ID' AND datew>=D1 AND datew<D2
I need to point out that D1 and D2 are calculated for the beginning of the month in search and for the next month, respectively.
I actually have two questions:
Should I set any fields as indexes besides primary indexes? (Sorry, I seem to misunderstand the whole indexing concept)
Is there any way to re-write the Select statement to maybe speed it up. For instance, most of the checks in it would be to see that the actual employee ID and job site ID match. Maybe there's a way to split it up?
PS. Forgot to say, I use SQLite in a Windows C++ application.
If you use the above query often, then you may get better performance by creating a multicolumn index containing the columns in the query:
CREATE INDEX WorkdaysLookupIndex ON Workdays (emp_id, job_id, datew);
Sometimes you just have to create the index and try your queries to see what is faster.

The ids of a table in my sqlite database have been reset

I have an iPhone app and one of my users found a really strange problem with my application. I can't reproduce the problem and I can't figure out why it's happening. Maybe you can?
In Sqlite I have a table with about 1000 rows, each with a unique id. But for some reason the id of that table has restarted, before it was around 1000 but now it's restarted from 80 something. So everytime the user inserts a new row the new assigned id starts around 80 something and I get two duplicates ids that should be unique and yeah you can understand the problem. I have looked at all queries that does anything to that table and none of them could have done this. I always relay on the built in mechanism where the ids are assigned automatically.
Have you seen anything like this?
The schema of the table looks like this:
CREATE TABLE mytable(
id INTEGER PRIMARY KEY
);
As you can see I don't use AUTOINCREMENT. But from what I understand even if the user deletes a row with id 80, it is ok to give a new inserted row id 80 but not like it works now where the database just keeps incrementing the ids even if I have already have rows with the same id. Shouldn't it work like this:
HIGHEST ROWID IS 1000, ALL IDS FROM 0-1000 ARE TAKEN
USER DELETES ROW WITH ID 80
INSERT A NEW ROW
THE ID OF THE INSERTED ROW MIGHT NOW BE 80
SETS THE ID OF THE INSERTED ROW TO 80
INSERT A NEW ROW
THE ID OF THE INSERTED ROW CAN NOT BE 81 AS THIS IS ALREADY TAKEN
SETS THE ID OF THE INSERTED ROW TO 1001
Isn't that how it should work?
Did you declare your id column as a(n autoincrementing) primary key?
CREATE TABLE mytable(
id INTEGER PRIMARY KEY AUTOINCREMENT
);
By adding the autoincrement keyword you ensure that all keys generated will be unique over the lifetime of your table. By omitting it, the keys will still be unique, but it may generate keys that have already been used by other, deleted entries. Note that using autoincrement can cause problems, so read up on it before you add it.
Edit This is a bit of a long-shot, but sqlite only supports one primary key per table. If you have more than one primary key declared, you need to declare all but the one you actually want to use as a primary key as "unique". Hence
CREATE TABLE mytable(
id INTEGER PRIMARY KEY,
otherId INTEGER UNIQUE
);
Hard to say without the code and schema, but my instinct is that this unique ID is not defined as either unique nor primary key, which they should.
How do you make sure (in theory) id's are unique? What is your insert query like?

Unique record in Asp.Net SQL

I asked this question previously but the answers weren't what I was looking for.
I created a table in Asp.net without using code. It contains two columns.
YourUserId and FriendUserId
This is a many to many relationship.
Heres what I want:
There can be multiple records with your name as the UserId, there can also be multiple records with FriendUserId being the same...but there cannot be multiple records with both being the same. For example:
Dave : Greg
Dave : Chris
Greg : Chris
Chris : Greg
is good
Dave : Greg
Dave : Greg
is not good.
I right clicked on the table and chose Indexes/Keys. I then put both columns in the columns section and chose to make the unique. I thought this would make them unique as a whole but individually not unique.
If you go to the Dataset, it show keys next to both columns and says that there is a constraint with both columns being checked.
Is there a way of just making sure that you are not inserting a duplicate copy of a record into the table without individual columns being unique?
I tried controling it with my sql insert statement but that did not work. This is what I tried.
INSERT INTO [FriendRequests] ([UserId], [FriendUserId]) VALUES ('"+UserId+"', '"+PossibleFriend+"') WHERE NOT EXIST (SELECT [UserId], [FriendUserId] FROM [FriendRequests])
That didn't work for some reason.
Thank you for your help!
You should create a compound primary key to prevent duplicate rows.
ALTER TABLE FriendRequests
ADD CONSTRAINT pk_FriendRequests PRIMARY KEY (UserID, FriendUserID)
Or select both columns in table designer and right click to set it as a key.
To prevent self-friendship, you'd create a CHECK constraint:
ALTER TABLE FriendRequests
ADD CONSTRAINT ck_FriendRequests_NoSelfFriends CHECK (UserID <> FriendUserID)
You can add the check constraint in the designer by right clicking anywhere in the table designer, clicking "Check constraints", clicking "add", and setting expression to UserID <> FriendUserID
You might want to look at this question
Sounds like you need a composite key to make both fields a single key.
I have a better idea. Create a new table. Called FriendRequestRelationships. Have the following columns
FriendRelationshipId (PRIMARY KEY)
UserId_1 (FOREIGN KEY CONSTRAINT)
UserId_2 (FOREIGN KEY CONSTRAINT)
Put a unique constraint to only allow one relationship wit UserId_1 and UserId_2. This table now serves as your many-to-many relationship harness.
Create a scalar function that can return the FriendUserId for a UserId, lets say it's called fn_GetFriendUserIdForUserId
You can now display your relationships by running the following query
SELECT dbo.fn_GetFriendUserIdForUserId(UserId_1) AS 'Friend1',
dbo.fn_GetFriendUserIdForUserId(UserId_2) AS 'Friend2',
FROM FriendRelationshipId

Resources