mysql insert on duplicate FIELD instead of KEY - mysql

-------------------------------------
| user_id | user_name | user_visits |
-------------------------------------
| 1 | foo | 5 |
-------------------------------------
| 2 | bar | 12 |
-------------------------------------
user_id: auto increament, user_visits: default 1
INSERT INTO table (user_name) VALUES ('baz'), ('bar'), ('qux');
the above statement will of course insert 3 new records, as the result:
-------------------------------------
| user_id | user_name | user_visits |
-------------------------------------
| 1 | foo | 5 |
-------------------------------------
| 2 | bar | 12 |
-------------------------------------
| 3 | baz | 1 |
-------------------------------------
| 4 | bar | 1 |
-------------------------------------
| 5 | qux | 1 |
-------------------------------------
but what I'm trying to achieve is:
-------------------------------------
| user_id | user_name | user_visits |
-------------------------------------
| 1 | foo | 5 |
-------------------------------------
| 2 | bar | 13 |
-------------------------------------
| 3 | baz | 1 |
-------------------------------------
| 4 | qux | 1 |
-------------------------------------
so literally,
if field user_name exists, update user_visits, else insert a new record.
is it possible to achieve this with a single insert statement?

Sure there is but it has nothing to do with your insert statement. You need to add a unique index on the user_name column:
create unique index user_name_idx on yourtable (user_name);
Then afterward in your code that tracks the count will have to decide whether to do an insert or an update.

You have to create a key for your username field and then use INSERT ON DUPLICATE query to update the columns values.
For example your query must be,
INSERT INTO table (user_name) VALUES ('baz'), ('bar'), ('qux')
ON DUPLICATE KEY UPDATE user_visits=user_visits+1;
For further reference visit http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html

You could leave your INSERT statement as is and implement a trigger that handles your special actions.
See: An Introduction To Triggers

Related

Mysql Query for comparing two tables' and inserting the matched in another

I have two tables, say XYZ and ABC
XYZ
| id|
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
ABC
| id| name |
| 3 | rocky|
| 4 | Alex |
Perform ---->
ALTER TABLE XYZ ADD COLUMN name VARCHAR(8);
Now I want to set the values of ABC table in XYZ,like:-
| id| name |
| 1 | null |
| 2 | null |
| 3 | rocky|
| 4 | Alex |
| 5 | null |
I want a single line query??
Assuming id is a primary key:
REPLACE INTO XYZ SELECT * FROM ABC
If id isn't a primary key or a unique key, a multi-table update like:
update XYZ JOIN ABC USING (id) SET XYZ.name=ABC.name
ref: fiddle

MySQL creates new rows instead of updating when using the INSERT INTO SELECT ... ON DUPLICATE KEY UPDATE ... SQL Statement

I run into a problem with this query:
INSERT INTO unit_storage (user_id,diagram_id,amount)
SELECT uf.user_id,
uf.diagram_id,
uf.amount
FROM unit_factory uf
WHERE uf.production_finish_time < /*current unix epoch seconds*/
AND uf.user_id = /*provided user id*/ ON DUPLICATE KEY
UPDATE unit_storage.amount=unit_storage.amount+uf.amount
Let's start with the example of that is happening and what is my desired effect…
As you may have guessed from the compared value, production_finish_time is integer column where the time in seconds is marking a certain date.
Take a look at unit_factory table rows:
+-----+----------+-------------+---------+-------------------------+--+
| id | user_id | diagram_id | amount | production_finish_time | |
+-----+----------+-------------+---------+-------------------------+--+
| 7 | 10 | 2 | 1 | 1521472903 | |
| 8 | 10 | 2 | 1 | 1521473704 | |
| 9 | 10 | 2 | 1 | 1521473729 | |
| 10 | 10 | 2 | 1 | 1521474294 | |
+-----+----------+-------------+---------+-------------------------+--+
After I run the query, unit_storage table becomes a copy of the unit_factory table:
+-----+----------+-------------+---------+--+
| id | user_id | diagram_id | amount | |
+-----+----------+-------------+---------+--+
| 16 | 10 | 2 | 1 | |
| 17 | 10 | 2 | 1 | |
| 18 | 10 | 2 | 1 | |
| 19 | 10 | 2 | 1 | |
+-----+----------+-------------+---------+--+
While the result I need is:
+-----+----------+-------------+---------+--+
| id | user_id | diagram_id | amount | |
+-----+----------+-------------+---------+--+
| 16 | 10 | 2 | 4 | |
+-----+----------+-------------+---------+--+
What is the correct query for the desired result?
Edit:
As requested, indexes for both tables:
--
-- Indexes for table `unit_storage`
--
ALTER TABLE `unit_storage`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `unit_factory`
--
ALTER TABLE `unit_factory`
ADD PRIMARY KEY (`id`);
For the on duplicate key to trigger, there has to be a key:
ALTER TABLE unit_storage ADD CONSTRAINT key1 UNIQUE (user_id, diagram_id)
Here's a working example on SQL Fiddle.
INSERT INTO unit_storage (user_id,diagram_id,amount)
SELECT Min(uf.user_id),
Min(uf.diagram_id),
sum(uf.amount)
FROM unit_factory uf
WHERE uf.production_finish_time < /*current unix epoch seconds*/
AND uf.user_id = /*provided user id*/ ON DUPLICATE KEY
Group by uf.user_id,
uf.diagram_id
UPDATE unit_storage.amount=unit_storage.amount+uf.amount

Mysql->autoincrementing related to an other field

I am stuck on a project design. One of the table has 1-M relation with users table. So it has a foreign key. Same field is also primary key.
Table as follows
Itemid:
Primarykey
Autoincrement
Useriditem:
Primarykey
Foreign key of id in users table
Itemname:
Not null
Values:
-----------------------------------------
| **ITEMID** | **USERID** | ITEMNAME |
-----------------------------------------
| 1 | 1 | fooooooo |
-----------------------------------------
| 2 | 1 | tinytext |
-----------------------------------------
| 3 | 1 | MediumText |
-----------------------------------------
| 4 | 2 | LARGEtext |
-----------------------------------------
| 5 | 2 | HUGETEXT |
-----------------------------------------
| 6 | 1 | BLOOOOOB |
-----------------------------------------
| 7 | 3 | 001010101 |
-----------------------------------------
This is the result of the current design. What i am wondering is that a way to make auto increment for each user separately.
Something like "Autoincrement item id GROUP BY user id"
-----------------------------------------
| **ITEMID** | **USERID** | ITEMNAME |
-----------------------------------------
| 1 | 1 | fooooooo |
-----------------------------------------
| 2 | 1 | tinytext |
-----------------------------------------
| 3 | 1 | MediumText |
-----------------------------------------
| 1 | 2 | LARGEtext |
-----------------------------------------
| 2 | 2 | HUGETEXT |
-----------------------------------------
| 4 | 1 | BLOOOOOB |
-----------------------------------------
| 1 | 3 | 001010101 |
-----------------------------------------
Is there a way to do this using mysql?
You want something like this:
Demo
CREATE TRIGGER item_id_auto_inc
BEFORE INSERT ON items
FOR EACH ROW
BEGIN
SET NEW.item_id := (SELECT CASE WHEN ISNULL(MAX(item_id)) THEN 0 ELSE MAX(item_id) END +1 FROM items WHERE user_id=NEW.user_id);
END
//
I dont know what happens when multiple users execute queries but i think i managed to narrow down the algorithm.
how to "insert into table (col1, col2) values (select max(id) from table2, select id from table3); "?
INSERT INTO table VALUES (
(SELECT (MAX(itemid)+1)
FROM table
WHERE userid = 'theid') , 'theid' , 'foo1');
Can this solve the simultaneous execution by multiple user problem.
The safer way to do this is taking into account that your application can get hit by more than 1 user at any given time
START TRANSACTION;
Insert into table A
Select Last inserted id from table A using Last_Insert_ID()
Update table B
COMMIT;
At least you are guaranteed to get this last inserted id from table A into table B.

Join/merge two tables, improvise/make up "missing" entries

I have two tables, tbl_foo and tbl_bar, and I want to join these tables with tbl_foo.foo_id = tbl_bar.foo_id in the on-clause. However, for each tbl_bar.baz_id there should be one row for each tbl_foo.foo_id (even if no such entry in tbl_bar exists). How do I write such query?
There's more info on the schema and my desired result below.
Edit: Each row must have a foo_id and baz_id.
Edit 2: Added tbl_baz below.
Desired result
+--------+--------+--------+------------+
| bar_id | baz_id | foo_id | some_field |
+--------+--------+--------+------------+
| 1 | 101 | 1 | foo |
| 2 | 101 | 2 | bar |
| 3 | 101 | 3 | baz |
| NULL | 101 | 4 | bin |
| 4 | 102 | 1 | foo |
| NULL | 102 | 2 | bar |
| 5 | 102 | 3 | baz |
| NULL | 102 | 4 | bin |
+--------+--------+--------+------------+
Table: tbl_foo
+--------+------------+
| foo_id | some_field |
+--------+------------+
| 1 | foo |
| 2 | bar |
| 3 | baz |
| 4 | bin |
+--------+------------+
Table: tbl_bar
+--------+--------+--------+
| bar_id | baz_id | foo_id |
+--------+--------+--------+
| 1 | 101 | 1 |
| 2 | 101 | 2 |
| 3 | 101 | 3 |
| 4 | 102 | 1 |
| 5 | 102 | 3 |
+--------+--------+--------+
Table: tbl_baz
+--------+
| baz_id |
+--------+
| 101 |
| 102 |
+--------+
SQL Schema
CREATE TABLE tbl_foo (
foo_id INT,
some_field VARCHAR(255),
PRIMARY KEY (foo_id)
);
INSERT INTO tbl_foo VALUES
(1, 'foo'),
(2, 'bar'),
(3, 'baz'),
(4, 'bin');
CREATE TABLE tbl_bar (
bar_id INT,
baz_id INT,
foo_id INT,
PRIMARY KEY (bar_id, baz_id),
FOREIGN KEY (baz_id) REFERENCES tbl_baz (baz_id),
FOREIGN KEY (foo_id) REFERENCES tbl_foo (foo_id)
);
INSERT INTO tbl_bar VALUES
(1, 101, 1),
(2, 101, 2),
(3, 101, 3),
(4, 102, 1),
(5, 102, 3);
CREATE TABLE tbl_baz (
baz_id INT,
PRIMARY KEY (baz_id)
);
INSERT INTO tbl_baz VALUES
(101),
(102);
Like mwigdalh said, there's no way to achieve that output with the given tables. If there was another baz table, there would be a way. The problem is that the highlighted records below are essentially pulled from thin air, and meaningless. You could just as easily put "meh" in each one, and the output would make as much sense.
+--------+--------+--------+------------+
| bar_id | baz_id | foo_id | some_field |
+--------+--------+--------+------------+
| 1 | 101 | 1 | foo |
| 2 | 101 | 2 | bar |
| 3 | 101 | 3 | baz |
| NULL | *101*| 4 | bin |
| 4 | 102 | 1 | foo |
| NULL | *102*| 2 | bar |
| 5 | 102 | 3 | baz |
| NULL | *102*| 4 | bin |
+--------+--------+--------+------------+
If you provide some context in a closer-to-real-world example, it might be found that there's a different output altogether that achieves your desired result.
You may be looking for a query like this:
UPDATE
Based upon new tbl_baz:
select y.bar_id, x.baz_id, x.foo_id, x.some_field
from (
select a.foo_id, a.some_field, b.baz_id
-- Cross foo_id with all baz_id
from tbl_foo as a, tbl_baz as b
) as x
-- Get the bar_id where it exists for each foo_id/baz_id combo
left join tbl_bar as y on x.foo_id = y.foo_id
and x.baz_id = y.baz_id
order by x.baz_id, x.foo_id
This is based on the assumption that you want to see each foo_id for each baz_id regardless of what is in your many-to-many table.
EXAMPLE of why you may not want this, or may want to update your many-to-many table instead:
If we replace "foo" and "baz" with "person" and "car", this query is essentially saying that every person owns every car. This may be the case, but it is certainly not represented in the "ownership" many-to-many table (bar).
Vague, you can't get there from here. You're asking for a result that specifies a baz_id for rows where there is no corresponding row from tbl_bar. There is simply no way to construct the missing data in this case.
Either your schema is not correct or you need some custom default logic for cases where you can't find a row in tbl_bar.

My SQL AUTO_INCREMENT on a secondary column

Is it possible to auto increment a value on a secondary column depending on a another refrence column in MySQL.
Say I have a table as follows, which I need to auto increment the ID value depending on the GRP_ID
+--------+----+---------+
| grp_id | id | name |
+--------+----+---------+
| 1001 | 1 | abc |
| 1002 | 1 | xyz |
| 1002 | 2 | ijl |
| 1002 | 3 | efg |
| 1003 | 1 | hij |
| 1003 | 2 | mno |
+--------+----+---------+
you can use LAST_INSERT_ID() it's defending last the insert auto increment id any table in your mysql db, but you need to insert values first reference table or column in MySQL .bec
there"s the place for id
INSERT INTO table (id, grap_id,name)
VALUES (LAST_INSERT_ID() ,' ', 'Value4name');