How to find the largest value of a column in mysql? - mysql

I am writing a forum application. I have a script that creates a board. In addition to the autoincremented board_id column, all boards have an integer column called position that is used to order the boards on the home page. When a new board is created, I want the default position to be the largest value within the rows of the boards table with the given category_id. Positions can have duplicates because they are positioned within their category. I hope that makes sense.
So if I have the following boards...
b_id | c_id | pos |
-------------------
1 | 1 | 1 |
-------------------
2 | 1 | 2 |
-------------------
3 | 2 | 1 |
-------------------
And I am creating a new board in c_id 2, the position should be 2. If the new board is in c_id 1, the position would be 3. How can I do this?
The query below is what I am currently using, but the position always ends up being 0.
INSERT INTO `forum_boards` (
`title`,
`description`,
`category_id`,
`position`
) VALUES (
'Suggestion Box',
'Have an idea that will help us run things better? Let us know!',
'1',
'(SELECT MAX(position), category_id FROM forum_boards WHERE category_id = 1)+1'
)

You can take the approach you are using. You need to drop the single quotes:
INSERT INTO `forum_boards` (`title`, `description`, `category_id`, `position`
)
VALUES ('Suggestion Box',
'Have an idea that will help us run things better? Let us know!',
1,
(SELECT MAX(position) + 1 FROM forum_boards WHERE category_id = 1)'
);
However, this doesn't take into account categories that are initially empty. And, I would write this using insert . . . select:
INSERT INTO `forum_boards` (`title`, `description`, `category_id`, `position`
)
SELECT 'Suggestion Box',
'Have an idea that will help us run things better? Let us know!',
1,
COALESCE(MAX(position) + 1, 1)
FROM forum_boards
WHERE category_id = 1;
Note that I dropped the single quotes around '1'. Numbers should be passed in as numbers, not strings.

Related

search data location wise in PHP SQL

I have some parent and daughter design-wise locations-id in the MySQL database.
Where the daughter linked to the parent. I will show the database design below -
I can able to fetch the data when I search it through daughter location id wise but I don't have any idea how I combined the daughter value when I click parent location.
For example -
MainLocation (123) //total stock 23+10+56= 89
|
|
|---- DaughterLoc1 (456) //suppose stock 23
|
|---- DaughterLoc2 (789) //suppose stock 10 and total stock 10+56 = 66
|
|
|---DaughterLocA (963) //suppose stock 56
SQL : SELECT stock FROM table WHERE location = '456'
OUTPUT = 23 (Corrent)
But I want when searching location 123 I want output 89
My table design is like this below -
table: LocParent
-------------------------
| ID | stock | loc_id |
-------------------------
| 1 | 10 | 789 |
-------------------------
`location`
--------------------------------------------------------------------------------
| ID | main_loc | main_loc_id | loc_under | loc_under_id | stock |
--------------------------------------------------------------------------------
| 1 | MainLocation | 123 | DaughterLoc1 | 456 | 23 |
--------------------------------------------------------------------------------
| 2 | MainLocation | 123 | DaughterLoc2 | 789 | 10 |
--------------------------------------------------------------------------------
It is hard to tell from your sample structure what things actually look like still, and it is further complicated by multiple things called an "id". But, generally speaking, if your depth is finite, you can make small sub-queries, and if your depth is infinite (or unbound) you can make a recursive query.
Here is a sample database. It doesn't match yours, but hopefully it make sense still. If it doesn't, it would help if you provided an actual schema and data (excluding irrelevant columns).
This table is self-referencing to make things easier for demo.
CREATE TABLE sample
(
id int AUTO_INCREMENT NOT NULL,
parent_id INT NULL,
stock int NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT FOREIGN KEY (`parent_id`) REFERENCES `sample` (`id`)
);
And here's some sample data. There are two records that are "root" and don't have parent values (IDs 1 and 5), two child values (IDs 2 and 3) and one grandchild value (ID 4)
INSERT INTO sample VALUES (1, null, 11);
INSERT INTO sample VALUES (2, 1, 22);
INSERT INTO sample VALUES (3, 1, 33);
INSERT INTO sample VALUES (4, 2, 4);
INSERT INTO sample VALUES (5, null, 55);
Finite/bound
If you have a finite/bound depth, you can make use of subqueries like the below. This one goes to a depth of 3 and sums to 70. Hopefully it is fairly easy to read, but I've included a couple of comments.
SELECT
s.id,
s.stock -- root
+
(
(
SELECT
SUM(c.stock) -- child
FROM
sample c
WHERE
c.parent_id = s.id
)
+
(
SELECT
SUM(p.stock) -- grandchild
FROM
sample c
JOIN
sample p
ON
p.parent_id = c.id
WHERE
c.parent_id = s.id
)
)
as three_level_sum
FROM
sample s
WHERE
s.id = 1;
Infinite/unbound
If you have an infinite hierarchy, however, things get more complicated. MySQL and other database platforms have a thing called "Common Table Expressions" (CTEs) that allow you to make recursive queries. These can be harder to wrap your head around because of the recursion, but it basically does the same as the previous version, just with infinite depth. This version also returns the sum of 70.
WITH RECURSIVE sample_rec AS
(
SELECT
id AS root_id,
id,
parent_id,
stock
FROM
sample
WHERE
parent_id IS NULL
UNION ALL
SELECT
R.root_id,
E.id,
E.parent_id,
E.stock
FROM
sample E
INNER JOIN
sample_rec R
ON
E.parent_id = R.id
)
SELECT
SUM(stock)
FROM
sample_rec
WHERE
root_id = 1

MySQL complex subquery formulation

I have two tables - books and images. books has columns like id, name, releasedate, purchasecount. images has bookid (which is same as the id in books, basically one book can have multiple images. Although I haven't set any foreign key constraint), bucketid, poster (each record points to an image file in a certain bucket, for a certain bookid).
Table schema:
poster is unique in images, hence it is a primary key.
Covering index on books: (name, id, releasedate)
Covering index on images: (bookid,poster,bucketid)
My query is, given a name, find the top ten books (sorted by number of purchasecount) from the books table whose name matches that name, and for that book, return any (preferably the first) record (bucketid and poster) from the images table.
Obviously this can be solved by two queries by running the first, and using its results to query the images table, but that will be slow, so I want to use 'join' and subquery to do it in one go. However, what I am trying is not giving me correct results:
select books.id,books.name,year(releasedate),purchasecount,bucketid,poster from books
inner join (select bucketid,bookid, poster from images) t on
t.bookid = books.id where name like "%foo%" order by purchasecount desc limit 2;
Can anybody suggest an optimal query to fetch the result set as desired here (including any suggestion to change the table schema to improve search time) ?
Updated fiddle: http://sqlfiddle.com/#!9/17c5a8/1.
The example query should return two results - fooe and fool, and one (any of the multiple posters corresponding to each book) poster for each result. However I am not getting correct results. Expected:
fooe - 1973 - 459 - 11 - swt (or fooe - 1973 - 459 - 11 - pqr)
fool - 1963 - 456 - 12 - xxx (or fool - 1963 - 456 - 111 - qwe)
I agree with Strawberry about the schema. We can discuss ideas for better performance and all that. But here is my take on how to solve this after a few chats and changes to the question.
Note below the data changes to deal with various boundary conditions which include books with no images in that table, and tie-breaks. Tie-breaks meaning using the max(upvotes). The OP changed the question a few times and added a new column in the images table.
Modified quetion became return 1 row make per book. Scratch that, always 1 row per book even if there are no images. The image info to return would be the one with max upvotes.
Books table
create table books
( id int primary key,
name varchar(1000),
releasedate date,
purchasecount int
) ENGINE=InnoDB;
insert into books values(1,"fool","1963-12-18",456);
insert into books values(2,"foo","1933-12-18",11);
insert into books values(3,"fooherty","1943-12-18",77);
insert into books values(4,"eoo","1953-12-18",678);
insert into books values(5,"fooe","1973-12-18",459);
insert into books values(6,"qoo","1983-12-18",500);
Data Changes from original question.
Mainly the new upvotes column.
The below includes a tie-break row added.
create table images
( bookid int,
poster varchar(150) primary key,
bucketid int,
upvotes int -- a new column introduced by OP
) ENGINE=InnoDB;
insert into images values (1,"xxx",12,27);
insert into images values (5,"pqr",11,0);
insert into images values (5,"swt",11,100);
insert into images values (2,"yyy",77,65);
insert into images values (1,"qwe",111,69);
insert into images values (1,"blah_blah_tie_break",111,69);
insert into images values (3,"qwqqe",14,81);
insert into images values (1,"qqawe",8,45);
insert into images values (2,"z",81,79);
Visualization of a Derived Table
This is just to assist in visualizing an inner piece of the final query. It demonstrates the gotcha for tie-break situations, thus the rownum variable. That variable is reset to 1 each time the bookid changes otherwise it increments. In the end (our final query) we only want rownum=1 rows so that max 1 row is returned per book (if any).
Final Query
select b.id,b.purchasecount,xDerivedImages2.poster,xDerivedImages2.bucketid
from books b
left join
( select i.bookid,i.poster,i.bucketid,i.upvotes,
#rn := if(#lastbookid = i.bookid, #rn + 1, 1) as rownum,
#lastbookid := i.bookid as dummy
from
( select bookid,max(upvotes) as maxup
from images
group by bookid
) xDerivedImages
join images i
on i.bookid=xDerivedImages.bookid and i.upvotes=xDerivedImages.maxup
cross join (select #rn:=0,#lastbookid:=-1) params
order by i.bookid
) xDerivedImages2
on xDerivedImages2.bookid=b.id and xDerivedImages2.rownum=1
order by b.purchasecount desc
limit 10
Results
+----+---------------+---------------------+----------+
| id | purchasecount | poster | bucketid |
+----+---------------+---------------------+----------+
| 4 | 678 | NULL | NULL |
| 6 | 500 | NULL | NULL |
| 5 | 459 | swt | 11 |
| 1 | 456 | blah_blah_tie_break | 111 |
| 3 | 77 | qwqqe | 14 |
| 2 | 11 | z | 81 |
+----+---------------+---------------------+----------+
The significance of the cross join is merely to introduce and set starting values for 2 variables. That is all.
The results are the top ten books in descending order of purchasecount with the info from images if it exists (otherwise NULL) for the most upvoted image. The image selected honors tie-break rules picking the first one as mentioned above in the Visualization section with rownum.
Final Thoughts
I leave it to the OP to wedge in the appropriate where clause at the end as the sample data given had no useful book name to search on. That part is trivial. Oh, and do something about the schema for the large width of your primary keys. But that is off-topic at the moment.

Adapt query to return category hierarchy by keyword

I asked this question previously, then someone suggested that it was a duplicate of another previously answered question. However, I could not adapt that solution to what I need despite 3 hours of trying.
So, my new question is how to adapt that solution to my own needs.
A simplified version of my category/subcategory database schema looks like this:
tblAllCategories
record_id title level parent_cat_id parent_id keywords
-------------------------------------------------------------------------------------------
1 Antiques & Collectables 0 NULL NULL junk
2 Art 0 NULL NULL
25 Furniture 1 1 1
59 Office Furniture 2 1 25 retro,shabby chic
101 Chairs 3 1 59
Notes:
Level 0 = top-level category, level 1 = second level, etc
parent_cat_id is the top-level category (i.e. having level 0)
parent_id refers to the level immediately above the relevant level
I added the keyword column to assist keyword searches so that items in certain relevant categories would be returned if the user entered a keyword but did not select a category to drill down into.
So, at the front end, after the user enters keyword, e.g., "Retro", I need to return not only the category that has the term "retro" in its keyword column, but also all higher level categories. So, according to the schema above, a search on "retro" would return category 59 along with its super-categories - 25 and 1.
The query should be sorted by level, such that the front end search results would look something like this (after necessary coding):
The solution offered is from this question
And the query is as follows:
SELECT T2.id, T2.title,T2.controller,T2.method,T2.url
FROM (
SELECT
#r AS _id,
(SELECT #r := parent_id FROM menu WHERE id = _id) AS parent_id,
#l := #l + 1 AS lvl
FROM
(SELECT #r := 31, #l := 0) vars,
menu m
WHERE #r <> 0) T1
JOIN menu T2
ON T1._id = T2.id
ORDER BY T1.lvl DESC;
I need to adapt this query to work off a passed keyword, not an ID.
Edit the vars subquery to have #r equal to the record_id of the row with the keywork, something like
SELECT T2.record_id, T2.title,T2.level,T2.keywords
FROM (SELECT #r AS _id
, (SELECT #r := parent_id
FROM tblAllCategories
WHERE record_id = _id) AS parent_id
, #l := #l + 1 AS lvl
FROM (SELECT #r := record_id, #l := 0
FROM tblAllCategories
WHERE keywords like '%retro%') vars
, tblAllCategories m
WHERE #r <> 0) T1
JOIN tblAllCategories T2 ON T1._id = T2.record_id
ORDER BY T1.lvl DESC;
SQLFiddle demo
Having the keywork as a comma separated values is not the best, a many to many relationship between this table and a keyword table (with the compulsory junction table) will be better as it will avoid the use of LIKE. In this example if there were another category with the keyword 'retrobike' that category and all his hierarchy will also be in the result.
This is going to take a while so get some coffee.
There are a lot of good resources available for hierarchical development. Most of what you will see below comes from sites like this and it refers you to Celko which I hardily recommend.
The first thing you'll have to do is remove the keywords field. The extra effort in development, use and maintenance is nowhere near the benefit received. I'll show you how to implement it later.
In this design, think of a row as a node. Each node has two values, the left boundary and the right boundary. These form a range or span of influence. If a node has boundaries of 1:4 and another node has 2:3, the second node is a subnode of the first as its span is contained in the span of the first. Also, as the boundaries of the second node are consecutive, there can be no node below it, so it must be a leaf node. This may sound complicated at first, especially when considering many levels of nodes, but you will see how the SQL is relatively easy to write and the maintenance effort for the table is minimal.
The complete script is here.
CREATE TABLE categories (
id INT not null auto_increment PRIMARY KEY,
name VARCHAR( 50 ) NOT NULL,
lBound INT NOT NULL,
rBound INT NOT NULL,
-- MySQL does not implement check constraints. These are here for illustration.
-- The functionality will be implemented via trigger.
CONSTRAINT cat_ptr_incr_chk CHECK ( lBound < rBound ), -- basic integrity check
CONSTRAINT cat_ptr_root_chk CHECK ( lBound >= 0 ) -- eliminates negative values
);
create unique index ndx_cat_lBound on categories( lBound );
create unique index ndx_cat_rBound on categories( rBound );
Notice there is nothing here that say "I'm a leaf node", "I'm a root" or "My root node is such-and-such." This information is all encompassed by the lBound and rBound (left boundary, right boundary) values. Let's build a few nodes so we can see what this looks like.
INSERT INTO categories( name, lBound, rBound )
values( 'Categories', 0, 1 );
ID name lBound rBound
== ========== ====== ======
1 Categories 0 1
This we do before creating the triggers on the table. That's really so the insert trigger doesn't have to have special code that must recognize when the first row (the root node of the entire structure). That code would only be executed when the first row is inserted and never again. Now we don't have to worry about it.
So now me have the root of the structure. Notice that its bounds are 0 and 1. Nothing can fit between 0 and 1 so this is a leaf node. The tree root is also a leaf. That means the tree is empty.
So now we write the triggers and dml procedures. The code is in the script so I won't duplicate it here, just say that the insert and delete triggers will not allow just anyone to issue an Insert or Delete statement. Anyone may issue an Update, but only the name is allowed to be changed. The only way Inserts, Deletes and complete Updates may be performed is through the procedures. With that in mind, let's create the first node under the root.
call ins_category( 'Electronics', 1 );
This creates a node with the name 'Electronics' as a subnode of the node with ID=1 (the root).
ID name lBound rBound
== ========== ====== ======
1 Categories 0 3
2 Electronics 1 2
Notice how the trigger has expanded the right boundary of the root to allow for the new node. The next node will be yet another level.
call ins_category( 'Televisions', 2 );
Node 2 is Electronics so the new node will be its subnode.
ID name lBound rBound
== ========== ====== ======
1 Categories 0 5
2 Electronics 1 4
3 Televisions 2 3
Let's create a new upper level node -- still it must be under the root, but will be the start of a subtree beside Electronics.
call ins_category( 'Antiques & Collectibles', 1 );
ID name lBound rBound
== ========== ====== ======
1 Categories 0 7
2 Electronics 1 4
3 Televisions 2 3
4 Antiques & Collectibles 5 6
Notice the 5-6 does not fit between any boundary range except for the root. So it is a subnode directly under the root, just like Electronics, but is independent of the other subnodes.
The SQL to give a clearer picture of the structure is not complicated. After completing the tree with a lot more nodes, let's see what it looks like:
-- Examine the tree or subtree using pre-order traversal. We start at the node
-- specified in the where clause. The root of the entire tree has lBound = 0.
-- Any other ID will show just the subtree starting at that node.
SELECT n.ID, n.NAME, n.lBound, n.rBound
FROM categories p
join categories n
on n.lBound BETWEEN p.lBound AND p.rBound
where p.lBound = 0
ORDER BY n.lBound;
+----+----------------------------+--------+--------+
| id | name | lBound | rBound |
+----+----------------------------+--------+--------+
| 1 | >Categories | 0 | 31 |
| 2 | -->Electronics | 1 | 20 |
| 3 | ---->Televisions | 2 | 9 |
| 4 | ------>Tube | 3 | 4 |
| 5 | ------>LCD | 5 | 6 |
| 6 | ------>Plasma | 7 | 8 |
| 7 | ---->Portable Electronics | 10 | 19 |
| 8 | ------>MP3 Players | 11 | 14 |
| 9 | -------->Flash | 12 | 13 |
| 10 | ------>CD Players | 15 | 16 |
| 11 | ------>2-Way Radios | 17 | 18 |
| 12 | -->Antiques & Collectibles | 21 | 28 |
| 14 | ---->Furniture | 22 | 27 |
| 15 | ------>Office Furniture | 23 | 26 |
| 16 | -------->Chairs | 24 | 25 |
| 13 | -->Art | 29 | 30 |
+----+----------------------------+--------+--------+
The output above is actually from a view defined in the script, but it shows clearly the hierarchical structure. This may easily be converted to a set of nested menus or navigational nodes.
There are enhancements that may be made, but they needn't change this basic structure. You'll find it reasonably easy to maintain. I had started out thinking this would be a whole lot easier in a DBMS such as Oracle, SQL Server or PostGreSQL which allows triggers on views. Then access could be limited to only the views so triggers would take care of everything. That would eliminate the need for separate stored procedures. But this way isn't half bad. I could happily live with it. In fact, there is a simplicity and flexibility to using the stored procedures that wouldn't be available thru views alone (you can't pass parameters to views).
The keyword feature is also defined but I won't show that here. Look at the script. Execute it a little at a time to get a clear picture of what is taking place. If you have any questions, you know where to find me.
[Edit] Added a few enhancements, including working with the keywords.
You can use this simple, for Add a new column by HeirarchyID type for management Tree :
We can use Microsoft example CLICK HERE
THIS IS A SAMPLE TABLE
create table [EmployeeTB]
(
employee int identity primary key,
name nvarchar(50),
hourlyrate money,
managerid int -- parent in personnel tree
);
set identity_insert dbo.[EmployeeTB] on;
insert into [EmployeeTB] (employee, name, hourlyrate, managerid)
values
(1, 'Big Boss', 1000.00, 1),
(2, 'Joe', 10.00, 1),
(8, 'Mary', 20.00, 1),
(14, 'Jack', 15.00, 1),
(3, 'Jane', 10.00, 2),
(5, 'Max', 35.00, 2),
(9, 'Lynn', 15.00, 8),
(10, 'Miles', 60.00, 8),
(12, 'Sue', 15.00, 8),
(15, 'June', 50.00, 14),
(18, 'Jim', 55.00, 14),
(19, 'Bob', 40.00, 14),
(4, 'Jayne', 35.00, 3),
(6, 'Ann', 45.00, 5),
(7, 'Art', 10.00, 5),
(11, 'Al', 70.00, 10),
(13, 'Mike', 50.00, 12),
(16, 'Marty', 55.00, 15),
(17, 'Barb', 60.00, 15),
(20, 'Bart', 1000.00, 19);
set identity_insert dbo.[EmployeeTB] off;
select * from [EmployeeTB]
order by managerid
--Big Boss /
--Joe /1/
--Jane /1/1/
--Max /1/2/
--Ann /1/2/1/
--Art /1/2/2/
Now add NEW COLUMN BY HEIRARCHY
alter table [EmployeeTB]
add [Chain] hierarchyid;
-- fills all Chains
with sibs
as
(
select managerid,
employee,
cast(row_number() over (partition by managerid order by employee) as varchar) + '/' as sib
from [EmployeeTB]
where employee != managerid
)
--select * from sibs
,[noChain]
as
(
select managerid, employee, hierarchyid::GetRoot() as Chain from [EmployeeTB]
where employee = managerid
UNION ALL
select P.managerid, P.employee, cast([noChain].Chain.ToString() + sibs.sib as hierarchyid) as Chain
from [EmployeeTB] as P
join [noChain] on P.managerid = [noChain].employee
join sibs on
P.employee = sibs.employee
)
--select Chain.ToString(), * from [noChain]
update [EmployeeTB]
set Chain = [noChain].Chain
from [EmployeeTB] as P join [noChain]
on P.employee = [noChain].employee
select Chain.ToString(), * from [EmployeeTB]
order by managerid
we can find any model of view for this example.

Insert or update based on row data

First off, I know about REPLACE INTO and INSERT INTO ... ON KEY DUPLICATE UPDATE but this is not what I'm looking for -or- I don't know how to use them to achieve what I want.
This is my simple table structure:
+-----------+---------+----------+----------+
| player_id | item_id | quantity | location |
+-----------+---------+----------+----------+
My INSERT query looks like this:
INSERT INTO items VALUES (2, 10, 40, 1);
Now, if there is a row where all fields match, except for quantity (doesn't matter if it matches or not, but the point is that the other 3 match). So, if there's a row where player_id is 2, item_id is 10 and location is 1 (quantity value doesn't matter - it can be 40, but also doesn't have to), then I want to update it, rather than insert a new one.
Obviously, I'm looking for a way that is different than SELECT + UPDATE, if there is any...
If there are no other constraints to be considered, couldn't you just add a combined unique key over (player_id, item_id and location), and then go for INSERT INTO ... ON DUPLICATE KEY UPDATE?
Edit: Trying to clarify. I suppose you have something like the following table creation statement:
CREATE TABLE items (
player_id INT NOT NULL,
item_id INT NOT NULL,
quantity INT NOT NULL,
location INT NOT NULL
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_unicode_ci;
You add a combined unique index for three columns:
ALTER TABLE items ADD UNIQUE player_item_location (player_id, item_id, location);
So you can INSERT this row:
INSERT INTO items (player_id, item_id, quantity, location) VALUES (2, 10, 40, 1);
And if you try to execute the same INSERT again, you end up with the message:
#1062 - Duplicate entry '2-10-1' for key 'player_item_location'
But if you add the ON DUPLICATE KEY UPDATE like this:
INSERT INTO items (player_id, item_id, quantity, location) VALUES (2, 10, 30, 1) ON DUPLICATE KEY UPDATE quantity = 30;
You will end up in not adding another row, but updating the existing one (player 2, item 10, location 1) and changing its quantity from 40 to 30.
And, if you want to add another row, say for player 3, item 10, location 1, this will work, too:
INSERT INTO items (player_id, item_id, quantity, location) VALUES (3, 10, 40, 1);
So after the three INSERTs, you should end up in having the following rows in your table:
mysql> SELECT * FROM items;
+-----------+---------+----------+----------+
| player_id | item_id | quantity | location |
+-----------+---------+----------+----------+
| 2 | 10 | 30 | 1 |
| 3 | 10 | 40 | 1 |
+-----------+---------+----------+----------+
2 rows in set (0.00 sec)
Based on your question, I thought that this is the behaviour you wanted to have. If not, please let us know what exactly doesn't work or where I didn't understand you correctly.
Well, you can use BEFORE INSERT triggers, which will be executed before every insert and make the required changes according to the values.
Read more here: http://dev.mysql.com/doc/refman/5.0/en///create-trigger.html

insert into table select max(column_name)+1

I have this mysql table built like this:
CREATE TABLE `posts` (
`post_id` INT(10) NOT NULL AUTO_INCREMENT,
`post_user_id` INT(10) NOT NULL DEFAULT '0',
`gen_id` INT(10) NOT NULL DEFAULT '0',
PRIMARY KEY (`post_user_id`, `post_id`)
)
COLLATE='utf8_general_ci'
ENGINE=MyISAM;
When I do:
insert into posts (post_user_id) values (1);
insert into posts (post_user_id) values (1);
insert into posts (post_user_id) values (2);
insert into posts (post_user_id) values (1);
select * from posts;
I get:
post_id | post_user_id | gen_id
1 1 0
2 1 0
1 2 0
3 1 0
A unique post_id is generated for each unique user.
I need the gen_id column to be 1 2 3 4 5 6 etc. How can I increment this column when I do an insert. I tried the one below, but it won't work. What's the right way to do this?
insert into posts (post_user_id,gen_id) values (1,select max(gen_id)+1 from posts);
//Select the highest gen_id and add 1 to it.
Try this:
INSERT INTO posts (post_user_id,gen_id)
SELECT 1, MAX(gen_id)+1 FROM posts;
Use a TRIGGER on your table. This sample code can get you started:
DELIMITER //
CREATE TRIGGER ai_trigger_name AFTER INSERT ON posts
FOR EACH ROW
BEGIN
UPDATE posts
SET gen_id = (SELECT MAX(gen_id) FROM posts) + 1
WHERE post_id = LAST_INSERT_ID()
LIMIT 1;
END;//
DELIMITER ;
For my case the first number to increment was null. I resolve with
IFNULL(MAX(number), 0) + 1
or better the query became
SELECT IFNULL(MAX(number), 0) + 1 FROM mytable;
Here is the table "Autos" and the data that it contains to begin with:
AutoID | Year | Make | Model | Color |Seq
1 | 2012 | Jeep |Liberty| Black | 1
2 | 2013 | BMW | 330XI | Blue | 2
The AutoID column is an auto incrementing column so it is not necessary to include it in the insert statement.
The rest of the columns are varchars except for the Seq column which is an integer column/field.
If you want to make it so that when you insert the next row into the table and the Seq column auto increments to the # 3 you need to write your query as follows:
INSERT INTO Autos
(
Seq,
Year,
Make,
Model,
Color,
)
Values
(
(SELECT MAX(Seq) FROM Autos) + 1, --this increments the Seq column
2013,'Mercedes','S550','Black');
The reason that I put the Seq column first is to ensure that it will work correctly... it does not matter where you put it, but better safe than sorry.
The Seq column should now have a value of 3 along with the added values for the rest of that row in the database.
The way that I intended that to be displayed did not happen...so I will start from the beginning: First I created a table.
create table Cars (
AutoID int identity (1,1) Primary Key,
Year int,
Make varchar (25),
Model varchar (25),
TrimLevel varchar (30),
Color varchar (30),
CreatedDate date,
Seq int
)
Secondly I inserted some dummy values
insert into Cars values (
2013,'Ford' ,'Explorer','XLT','Brown',GETDATE(),1),
(2011,'Hyundai' ,'Sante Fe','SE','White',GETDATE(),2),
(2009,'Jeep' ,'Liberty','Jet','Blue',GETDATE(),3),
(2005,'BMW' ,'325','','Green',GETDATE(),4),
(2008,'Chevy' ,'HHR','SS','Red',GETDATE(),5);
When the insertion is complete you should have 5 rows of data.
Since the Seq column is not an auto increment column and you want to ensure that the next Seq's row of data is automatically incremented to the # 6 and its subsequent rows are incremented as well you would need to write the following code:
INSERT INTO Cars
(
Seq,
Year,
color,
Make,
Model,
TrimLevel,
CreatedDate
)
Values
(
(SELECT MAX(Seq) FROM Cars) + 1,
2013,'Black','Mercedes','A550','AMG',GETDATE());
I have run this insert statement many times using different data just to make sure that it works correctly....hopefully this helps!