Related
For example, I have a table:
User ID(int) | Card ID(int) | Deck(int)
1841 | 14 | 1
1841 | 14 | 1
it is defined that the int values in deck column would always take on 1 or 2 as a value(1 indicating that it is in the deck). and card ID is not unique for a user(this indicate that a user have 2 card 14) , as shown in the example above. what if i want to remove one card 14 in the deck and the other would remain. what is the proper sql command, i tried UPDATE but it
you can define limit at the end of update query
update [table name] set Deck=2 where User_ID=1841 and Card_id=14 limit 1;
Basically you're missing a way of referencing any single particular row. Depending how critical to the application is need for such reference, it is almost always bad idea to allow such situation. There are many solutions for this, for example
1) Every row usually contains unique OID or ROWID field , which is not displayed with "SELECT * FROM TABLE", but can be used if requested implicitly. Depending on what database engine you use, e.g. with PostgreSQL try
SELECT OID, * FROM TABLE WHERE OID = 'somevalue'
this is usually used if you don't want to enforce UNIQUE on the table, but rather deal with possible mistaken input later if it will unfortunately appear.
2) You can add ID column, for example autoincremental ( refer to DB manual ), and then update it to contain unique IDs
ALTER TABLE table_name ADD column_name column-definition;
3) You can use self incrementing "running total", eg. with MySQL it looks more/less like this:
SET #runtot:=0;
SELECT *, (#runtot := #runtot + 1) AS rt FROM table WHERE rt='somevalue'
(this will do calculation every time so probably will be inefficient )
4) You can use LIMIT as explained in previous answer
5) You can JOIN some another table with unique IDs and possibly update resulting relation, or combine some query to create and use static VIEW
6) You can use SELECT with some dynamically allocated value, for example RAND() or NOW() or similar. It probably won't create unique identifiers across whole table, depending what function you'll use and how you will use it
7) combine two or more above solutions altogether
..and probably many other solutions. Anyway usually there's some "Id" column used with some UNIQUE constraint.
I have a table, and there is no column which stores a field of when the record/row was added. How can I get the latest entry into this table? There would be two cases in this:
Loop through entire table and get the largest ID, if a numeric ID is being used as the identifier. But this would be very inefficient for a large table.
If a random string is being used as the identifier (which is probably very, very bad practise), then this would require more thinking (I personally have no idea other than my first point above).
If I have one field in each row of my table which is numeric, and I want to add it up to get a total (so row 1 has a field which is 3, row 2 has a field which is 7, I want to add all these up and return the total), how would this be done?
Thanks
1) If the id is incremental, "select max(id) as latest from mytable". If a random string was used, there should still be an incremental numeric primary key in addition. Add it. There is no reason not to have one, and databases are optimized to use such a primary key for relations.
2) "select sum(mynumfield) as total from mytable"
for the last thing use a SUM()
SELECT SUM(OrderPrice) AS OrderTotal FROM Orders
assuming they are all in the same column.
Your first question is a bit unclear, but if you want to know when a row was inserted (or updated), then the only way is to record the time when the insert/update occurs. Typically, you use a DEFAULT constraint for inserts and a trigger for updates.
If you want to know the maximum value (which may not necessarily be the last inserted row) then use MAX, as others have said:
SELECT MAX(SomeColumn) FROM dbo.SomeTable
If the column is indexed, MSSQL does not need to read the whole table to answer this query.
For the second question, just do this:
SELECT SUM(SomeColumn) FROM dbo.SomeTable
You might want to look into some SQL books and tutorials to pick up the basic syntax.
So I've got:
id number
1 0
2 0
3 0
Is there a sql statement to copy everything from id into number?
I'm about to write a php scrip to select, then update every row. My SQL knowledge is pretty basic, but I'm sure there's a smart guy way to to do this:
Background: The id used to be a number that was displayed in the app and was unique. That number is no longer unique with some new features I'm adding--so I need to move it to a field that isn't unique while maintaining the integrity of the old.
You can use an update statement and reference the columns. Just do the following:
update mytable set number = id
That sets number equal to id on each row. Enjoy!
Is it possible to reorder rows in SQL database?
For example; how can I swap the order of 2nd row and 3rd row's values?
The order of the row is important to me since i need to display the value according to the order.
Thanks for all the answers. But 'Order by' won't work for me.
For example, I put a list of bookmarks in database.
I want to display based on the result I get from query. (not in alphabet order). Just when they are inserted.
But user may re-arrange the position of the bookmark (in any way he/she wants). So I can't use 'order by'.
An example is how the bookmark display in the bookmark in firefox. User can switch position easily. How can I mention that in DB?
Thank you.
It sounds like you need another column like "ListOrder". So your table might look like:
BookMark ListOrder
======== =========
d 1
g 2
b 3
f 4
a 5
Then you can "order by" ListOrder.
Select * from MyTable Order By ListOrder
If the user can only move a bookmark one place at a time, you can use integers as the ListOrder, and swap them. For example, if the user wants to move "f" up one row:
Update MyTable
Set ListOrder=ListOrder+1
Where ListOrder=(Select ListOrder-1 From MyTable where BookMark='f')
Update MyTable
Set ListOrder=ListOrder-1
Where BookMark='f'
If the user can move a bookmark up or down many rows at once, then you need to reorder a segment. For example, if the user wants to move "f" to the top of the list, you need to:
if (increment) {
update MyTable
Set ListOrder=ListOrder-1
where ListOrder<=1 -- The New position
and ListOrder >(Select ListOrder from MyTable where BookMark='f')
} else {
update MyTable
Set ListOrder=ListOrder+1
where ListOrder>=1 -- The New position
and ListOrder <(Select ListOrder from MyTable where BookMark='f')
}
update MyTable
Set ListOrder=1 -- The New Position
Where Bookmark='f'
As others have mentioned, it's not a good idea to depend on the physical order of the database table. Relational tables are conceptually more like unordered sets than ordered lists. Assuming a certain physical order may lead to unpredictable results.
Sounds like what you need is a separate column that stores the user's preferred sort order. But you'll still need to do something in your query to display the results in that order.
It is possible to specify the physical order of records in a database by creating a clustered index, but that is not something you'd want to do on an arbitrary user-specified basis. And it may still lead to unexpected results.
Use ORDER BY in your SELECT query. For example, to order by a user's last name, use:
SELECT * FROM User ORDER BY LastName
The order of the rows on the actual database should not matter.
You should use the ORDER BY clause in your queries to order them as you need.
Databases can store the data in any way they want. Using the "order by" clause is the only way to guarantee an ordering of the data. In your bookmark example, you could have an integer field that indicates the ordering, and then update that field as a user moves things around. Then ORDER BY that column to get things in the right order.
A little late to the party, but anyone still looking for an answer to this problem, you need to use the Stern-Brocot technique.
Here's an article explaining the theory behind it
For each item you need to store a numerator and denominator. Then you can also add a computed column which is the division of both. Each time you move an item inbetween 2 others, the item's numerator becomes the sum of both neighboring numerators, and the item's denominator becomes the sum of both neighboring denominators.
These numbers won't skyrocket as fast as with the "averaging" method, where you lose all accuracy after 17 swaps.
I also created a demo where the method is implemented.
I have a solution for this that I have used a few times. I keep an extra field "sort_order" in the table, and update this when reordering. I've used this in cases when I have some sort of containers with items, and the order of the items should be editable inside the container. When reordering, I only update the sort_order for the items in the current container, which means not to many (usually in practice only a few) rows have to be updated.
In short, I do the following:
add a sort_order field to the items table
when inserting a new row, I set sort_order=id
when reordering (needs id of item to move, and id of item to insert after):
select id, sort_order from items where container = ID order by sort_order
split the id and sort_order from rows in two arrays
remove the id of the item to move from the id-list
insert the id of the item to move after the id of the item to insert after
merge the list of ids and the list of sort_order into a two dimensional array, as [[id, sort_order], [id2, sort_order], ...]
run update item set sort_order=SORT_ORDER where id=ID (executemany) with merged list
(If moving item to another container, after updating "container foreign key" move first or last depending on app.)
(If the update involves a large number of items, I do not think this solution is a good approach.)
I have made an example using python and mysql on http://wannapy.blogspot.com/2010/11/reorder-rows-in-sql-database.html (copy and try it) along with some extra explanations.
I guess a simple order by would be what you're looking for?
select my_column from my_table order by my_order_column;
As others have stated use an order by.
Never depend on the order data exists in a physical table, always base it of the data you are working with, be it one or more key fields.
First, let me agree with everyone here that the order in the table shouldn't matter. Use a separate [SortOrder] column that you update and include an Order By clause.
That said, SQL Server databases do allow for a single "clustered index" on a table that will actually force the position in the underlying table storage. Primarily useful if you have a big dataset and always query by something specific.
Add a position column to your table and store as a simple integer.
If you need to support multiple users or lists, your best bet is to create a bookmarks table, an users table and a table to link them.
bookmarks: id,url
users: id,name
users_bookmarks: user_id, bookmark_id, position, date_created
Assuming date_created is populated when inserting rows you can get secondary list ordering based on date.
select bookmark_id from users_bookmarks where user_id = 1 order by position, date_created;
At times like this, I am reminded of a quote from the Matrix: "Do not try and order the database. That's impossible. Instead, only realize the truth... there is no order. Then you will see that it the table that orders itself, it is you who orders the table."
When working with MySQL through a GUI, there is always a decision to make. If you run something like SELECT * FROM users, MySql will always make a decision to order this by some field. Normally, this will be the primary key.
+----------------
| id | name |
-----------------
| 1 | Brian |
| 2 | Carl |
| 3 | Albert |
-----------------
When you add an ORDER BY command to the query, it will make the decision to order by some other field.
For Example Select * From users ORDER BY name would yield:
+----------------
| id | name |
-----------------
| 3 | Albert |
| 1 | Brian |
| 2 | Carl |
-----------------
So to your question, you appear to want to change the default order by which your table displays this information. In order to do that, check to see what your Primary Key field
is. For most practical purposes, having a unique identifying natural number tends to do the trick. MySQL has an AUTO_INCREMENT function for this. When creating the table, it would look something like field_name int NOT NULL AUTO_INCREMENT.
All of this is to say: if you would like to change "the row order", you would need to update this value. However, since the identifier is something that other tables would use to reference your field, this seems a little bit reckless.
If you for example went: UPDATE table Set id = 1 where id = 2;, this would initially fail, since the id fields would end up being both an identical value and fail the PrimaryKey check (which insists on both uniqueness and having a value set). You could Juggle this by running three update statements in a row:
UPDATE users Set id = 100000000 where id = 1;
UPDATE users Set id = 1 where id = 2;
UPDATE users Set id = 2 where id = 100000000;
This would result in the rows for this table looking like:
+----------------
| id | name |
-----------------
| 1 | Carl |
| 2 | Brian |
| 3 | Albert |
----------------+
Which technically would work to reorder this table, but this is in a bubble. MySQL being a relational database means that any table which was depending on that data to be consistent will now be pointed to the wrong data. For example, I have a table which stores birthdays, referencing the initial user table. It's structure might look like this:
+----------------------------+
| id | user_id | birthdate |
+----------------------------+
| 1 | 1 | 1993-01-01 |
| 1 | 2 | 1980-02-03 |
| 1 | 3 | 1955-01-01 |
+----------------------------+
By switching the ID's on the user table, you MUST update the user_id value on the birthdays table. Of course MySQL comes prepared for this: enter "Foreign Key Constraints". As long as you configured all of your foreign key constraints to Cascade Updates, you wouldn't need to manually change the reference to every value you changed.
These queries would all be a lot of manual work and potentially weaken your data's integrity. If you have fields you would like to rank and reorder regularly, the answer posed by Mike Lewis on this question with the "table order" would be a more sensible answer (and if that is the case, then his is the best solution and just disregard this answer).
In response to your post here, the answer you may be looking for is:
To order chronologically, add a DateAdded or similar column with a datetime or smalldatetime datatype.
On all methods that insert into the database, make sure you insert CURRENT_TIMESTAMP in the DateAdded column.
On methods that query the database, add ORDER BY DateAdded at the end of the query string.
NEVER rely on the physical position in the database system. It may work MOST of the time but definitely not ALL of the time.
The question lacks any detail that would let anyone give you correct answer. Clearly you could read the records into memory and then update them. But this is bad on so many different levels.
The issue is like this. Depending on the schema that is actually implemented there is logic to the way that the records are physically written to disk. Sometimes they are written in order of insert and other times they are inserted with space between blocks (see extents).
So changing the physical order is not likely without swapping column data; and this has a deep effect on the various indices. You are left having to change the logical order.
As I read your update... I'm left to understand that you may have multiple users and each user is to have bookmarks that they want ordered. Looks like you need a second table that acts as an intersection between the user and the bookmark. Then all you need is an inner join and an order by.
But there is not enough information to offer a complete solution.
Here is a stored procedure script to increment or decrement (one at a time) in MySQL.
Note, MySQL doesn't allow you to select in the same query you're updating so the above answers don't work.
I have also set it to return an error if there is no item above / below if you're incrementing / decrementing, respectively.
DELIMITER $$
CREATE PROCEDURE `spReorderSequenceItems` (
IN _SequenceItemId INT,
IN _SequenceId INT,
IN IncrementUp TINYINT,
OUT Error VARCHAR(255)
)
BEGIN
DECLARE CurrentPosition INT;
SELECT Position INTO CurrentPosition
FROM tblSequenceItems
WHERE SequenceItemId = _SequenceItemId;
IF IncrementUp = 1 THEN
IF (
SELECT Position
FROM tblSequenceItems
WHERE Position = CurrentPosition + 1 AND SequenceId = _SequenceId
) THEN
UPDATE tblSequenceItems
SET Position = Position - 1
WHERE Position = CurrentPosition + 1 AND SequenceId = _SequenceId;
UPDATE tblSequenceItems
SET Position = Position + 1
WHERE SequenceItemId = _SequenceItemId;
ELSE
SELECT 'No Item Above' AS _Error INTO Error;
END IF;
ELSE
IF (
SELECT Position
FROM tblSequenceItems
WHERE Position = CurrentPosition - 1 AND SequenceId = _SequenceId
) THEN
UPDATE tblSequenceItems
SET Position = Position + 1
WHERE Position = CurrentPosition - 1 AND SequenceId = _SequenceId;
UPDATE tblSequenceItems
SET Position = Position - 1
WHERE SequenceItemId = _SequenceItemId;
ELSE
SELECT 'No Item Below' AS _Error INTO Error;
END IF;
END IF;
END
$$
DELIMITER ;
Call it with
CALL spReorderSequenceItems(1, 1, 1, #Error);
SELECT #Error;
What's the best way to store a linked list in a MySQL database so that inserts are simple (i.e. you don't have to re-index a bunch of stuff every time) and such that the list can easily be pulled out in order?
Using Adrian's solution, but instead of incrementing by 1, increment by 10 or even 100. Then insertions can be calculated at half of the difference of what you're inserting between without having to update everything below the insertion. Pick a number large enough to handle your average number of insertions - if its too small then you'll have to fall back to updating all rows with a higher position during an insertion.
create a table with two self referencing columns PreviousID and NextID. If the item is the first thing in the list PreviousID will be null, if it is the last, NextID will be null. The SQL will look something like this:
create table tblDummy
{
PKColumn int not null,
PreviousID int null,
DataColumn1 varchar(50) not null,
DataColumn2 varchar(50) not null,
DataColumn3 varchar(50) not null,
DataColumn4 varchar(50) not null,
DataColumn5 varchar(50) not null,
DataColumn6 varchar(50) not null,
DataColumn7 varchar(50) not null,
NextID int null
}
Store an integer column in your table called 'position'. Record a 0 for the first item in your list, a 1 for the second item, etc. Index that column in your database, and when you want to pull your values out, sort by that column.
alter table linked_list add column position integer not null default 0;
alter table linked_list add index position_index (position);
select * from linked_list order by position;
To insert a value at index 3, modify the positions of rows 3 and above, and then insert:
update linked_list set position = position + 1 where position >= 3;
insert into linked_list (my_value, position) values ("new value", 3);
A linked list can be stored using recursive pointers in the table. This is very much the same hierarchies are stored in Sql and this is using the recursive association pattern.
You can learn more about it here (Wayback Machine link).
I hope this helps.
The simplest option would be creating a table with a row per list item, a column for the item position, and columns for other data in the item. Then you can use ORDER BY on the position column to retrieve in the desired order.
create table linked_list
( list_id integer not null
, position integer not null
, data varchar(100) not null
);
alter table linked_list add primary key ( list_id, position );
To manipulate the list just update the position and then insert/delete records as needed. So to insert an item into list 1 at index 3:
begin transaction;
update linked_list set position = position + 1 where position >= 3 and list_id = 1;
insert into linked_list (list_id, position, data)
values (1, 3, "some data");
commit;
Since operations on the list can require multiple commands (eg an insert will require an INSERT and an UPDATE), ensure you always perform the commands within a transaction.
A variation of this simple option is to have position incrementing by some factor for each item, say 100, so that when you perform an INSERT you don't always need to renumber the position of the following elements. However, this requires a little more effort to work out when to increment the following elements, so you lose simplicity but gain performance if you will have many inserts.
Depending on your requirements other options might appeal, such as:
If you want to perform lots of manipulations on the list and not many retrievals you may prefer to have an ID column pointing to the next item in the list, instead of using a position column. Then you need to iterative logic in the retrieval of the list in order to get the items in order. This can be relatively easily implemented in a stored proc.
If you have many lists, a quick way to serialise and deserialise your list to text/binary, and you only ever want to store and retrieve the entire list, then store the entire list as a single value in a single column. Probably not what you're asking for here though.
This is something I've been trying to figure out for a while myself. The best way I've found so far is to create a single table for the linked list using the following format (this is pseudo code):
LinkedList(
key1,
information,
key2
)
key1 is the starting point. Key2 is a foreign key linking to itself in the next column. So your columns will link something link something like this
col1
key1 = 0,
information= 'hello'
key2 = 1
Key1 is primary key of col1. key2 is a foreign key leading to the key1 of col2
col2
key1 = 1,
information= 'wassup'
key2 = null
key2 from col2 is set to null because it doesn't point to anything
When you first enter a column in for the table, you'll need to make sure key2 is set to null or you'll get an error. After you enter the second column, you can go back and set key2 of the first column to the primary key of the second column.
This makes the best method to enter many entries at a time, then go back and set the foreign keys accordingly (or build a GUI that just does that for you)
Here's some actual code I've prepared (all actual code worked on MSSQL. You may want to do some research for the version of SQL you are using!):
createtable.sql
create table linkedlist00 (
key1 int primary key not null identity(1,1),
info varchar(10),
key2 int
)
register_foreign_key.sql
alter table dbo.linkedlist00
add foreign key (key2) references dbo.linkedlist00(key1)
*I put them into two seperate files, because it has to be done in two steps. MSSQL won't let you do it in one step, because the table doesn't exist yet for the foreign key to reference.
Linked List is especially powerful in one-to-many relationships. So if you've ever wanted to make an array of foreign keys? Well this is one way to do it! You can make a primary table that points to the first column in the linked-list table, and then instead of the "information" field, you can use a foreign key to the desired information table.
Example:
Let's say you have a Bureaucracy that keeps forms.
Let's say they have a table called file cabinet
FileCabinet(
Cabinet ID (pk)
Files ID (fk)
)
each column contains a primary key for the cabinet and a foreign key for the files. These files could be tax forms, health insurance papers, field trip permissions slips etc
Files(
Files ID (pk)
File ID (fk)
Next File ID (fk)
)
this serves as a container for the Files
File(
File ID (pk)
Information on the file
)
this is the specific file
There may be better ways to do this and there are, depending on your specific needs. The example just illustrates possible usage.
There are a few approaches I can think of right off, each with differing levels of complexity and flexibility. I'm assuming your goal is to preserve an order in retrieval, rather than requiring storage as an actual linked list.
The simplest method would be to assign an ordinal value to each record in the table (e.g. 1, 2, 3, ...). Then, when you retrieve the records, specify an order-by on the ordinal column to get them back in order.
This approach also allows you to retrieve the records without regard to membership in a list, but allows for membership in only one list, and may require an additional "list id" column to indicate to which list the record belongs.
An slightly more elaborate, but also more flexible approach would be to store information about membership in a list or lists in a separate table. The table would need 3 columns: The list id, the ordinal value, and a foreign key pointer to the data record. Under this approach, the underlying data knows nothing about its membership in lists, and can easily be included in multiple lists.
This post is old but still going to give my .02$. Updating every record in a table or record set sounds crazy to solve ordering. the amount of indexing also crazy, but it sounds like most have accepted it.
Crazy solution i came up with to reduce updates and indexing is to create two tables (and in most use cases you don's sort all records in just one table anyway). Table A to hold the records of the list being sorted and table B to group and hold a record of the order as a string. the order string represents an array that can be used to order the selected records either on the web server or browser layer of a webpage application.
Create Table A{
Id int primary key identity(1,1),
Data varchar(10) not null
B_Id int
}
Create Table B{
Id int primary key Identity(1,1),
GroupName varchat(10) not null,
Order varchar(max) null
}
The format of the order sting should be id, position and some separator to split() your string by. in the case of jQuery UI the .sortable('serialize') function outputs an order string for you that is POST friendly that includes the id and position of each record in the list.
The real magic is the way you choose to reorder the selected list using the saved ordering string. this will depend on the application you are building. here is an example again from jQuery to reorder the list of items: http://ovisdevelopment.com/oramincite/?p=155
https://dba.stackexchange.com/questions/46238/linked-list-in-sql-and-trees suggests a trick of using floating-point position column for fast inserts and ordering.
It also mentions specialized SQL Server 2014 hierarchyid feature.
I think its much simpler adding a created column of Datetime type and a position column of int, so now you can have duplicate positions, at the select statement use the order by position, created desc option and your list will be fetched in order.
Increment the SERIAL 'index' by 100, but manually add intermediate values with an 'index' equal to Prev+Next / 2. If you ever saturate the 100 rows, reorder the index back to 100s.
This should maintain sequence with primary index.
A list can be stored by having a column contain the offset (list index position) -- an insert in the middle is then incrementing all above the new parent and then doing an insert.
You could implement it like a double ended queue (deque) to support fast push/pop/delete(if oridnal is known) and retrieval you would have two data structures. One with the actual data and another with the number of elements added over the history of the key. Tradeoff: This method would be slower for any insert into the middle of the linked list O(n).
create table queue (
primary_key,
queue_key
ordinal,
data
)
You would have an index on queue_key+ordinal
You would also have another table which stores the number of rows EVER added to the queue...
create table queue_addcount (
primary_key,
add_count
)
When pushing a new item to either end of the queue (left or right) you would always increment the add_count.
If you push to the back you could set the ordinal...
ordinal = add_count + 1
If you push to the front you could set the ordinal...
ordinal = -(add_count + 1)
update
add_count = add_count + 1
This way you can delete anywhere in the queue/list and it would still return in order and you could also continue to push new items maintaining the order.
You could optionally rewrite the ordinal to avoid overflow if a lot of deletes have occurred.
You could also have an index on the ordinal to support fast ordered retrieval of the list.
If you want to support inserts into the middle you would need to find the ordinal which it needs to be insert at then insert with that ordinal. Then increment every ordinal by one following that insertion point. Also, increment the add_count as usual. If the ordinal is negative you could decrement all of the earlier ordinals to do fewer updates. This would be O(n)