Basically, the following is what I wish to do:
INSERT INTO table
(
column1, column2
)
VALUES
(
?, ?
)
WHERE EXISTS
(
SELECT 1
FROM table2
WHERE id = ?
)
In other words: provided an id exists in table2, the values should be inserted, otherwise nothing should happen.
What is the correct syntax for this task?
I found that this does what I need.
INSERT INTO table1
(
column1, column2
)
SELECT ?, ?
FROM
table2
WHERE EXISTS
(
SELECT 1
FROM table2
WHERE id = ?
)
LIMIT 1
I have no mysql database available but similar to other databases and after reading the reference it must be something like
INSERT INTO table (column1, column2)
SELECT ?, ? FROM table2 WHERE id=?
I know this is a pretty old question that's already been answered, but a friend of mine helped set up a database with a "constraint" where an insert or update had to have 1 value match one value from a different table in the same database exactly in order to fire off.
I'm not very good with MySQL calls yet so I don't understand exactly what it does... but it may help you cut down on the code necessary to do what you want?
(Note: I had to modify it a bit to remove some sensitive names & such from it, but it should be a good representation.)
-- -----------------------------------------------------
-- Table `db1`.`table1`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `db1`.`table1` (
`id` INT NOT NULL AUTO_INCREMENT ,
`av_key` VARCHAR(40) NOT NULL ,
PRIMARY KEY (`id`) )
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `db1`.`table2`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `db1`.`table2` (
`bkid` INT NOT NULL AUTO_INCREMENT ,
`id` INT NOT NULL ,
`data` VARCHAR(6144) NULL ,
PRIMARY KEY (`bkid`) ,
INDEX `id_idx` (`id` ASC) ,
CONSTRAINT `id`
FOREIGN KEY (`id` )
REFERENCES `db1`.`table1` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
With this, you just need to do the insert/update statement, and it'll just fail if there's no match for "id" in both tables.
Don't know if you already found out or if that's what you needed, but figured it was worth sharing!
Related
I have the following table:
CREATE TABLE `my_table` (
composite_pk1 INT NOT NULL ,
composite_pk2 INT NOT NULL ,
data VARCHAR(255) NOT NULL ,
primary key (composite_pk1, composite_pk2)
) ENGINE=InnoDB;
For a given composite_pk1, I wish composite_pk2 to act as an autoincrement primary key. I don't wish to lock the table, and as such plan on using a trigger such as the following:
DELIMITER $$
CREATE TRIGGER my_trigger BEFORE INSERT ON my_table
FOR EACH ROW BEGIN
SET NEW.composite_pk2 = (
SELECT IFNULL(MAX(composite_pk2), 0) + 1
FROM issue_log
WHERE composite_pk1 = NEW.composite_pk1
);
END $$
I can now insert a record:
$stmt=$myDB->prepare('INSERT INTO my_table(composite_pk1, data) VALUES (?,?)');
$stmt->execute([123,'hello']);
How do I get the last inserted composite_pk2? PDO::lastInsertId only works with native autoincrement tables (i.e. not the trigger approach). I "could" later do a SELECT query to get the max value, however, there is no guarantee that another record has snuck in.
You can make composite_pk2 an unique key with auto_increment:
CREATE TABLE `my_table` (
composite_pk1 INT NOT NULL ,
composite_pk2 INT NOT NULL unique auto_increment,
data VARCHAR(255) NOT NULL ,
primary key (composite_pk1, composite_pk2)
) ENGINE=InnoDB;
Now last_insert_id() will return the recently created id for composite_pk2.
i have a very annoying problem at this moment. i want a table with the following specification:
CREATE TABLE `test` (
`client` INT NOT NULL ,
`id` INT NOT NULL AUTO_INCREMENT ,
`test` INT NOT NULL ,
PRIMARY KEY ( `client` , `id` ) ,
INDEX ( `test` )
) ENGINE = INNODB;
you can see, that i have a primary key with 2 columns. now i want that the id auto_increment column only increments in order to the first column. for example:
## client/id ##
1/1
1/2
1/3
2/1
2/2
2/3
etc.
is this really impossible with innodb? i need innodb because of the transactional features.
You can derive it easily in SELECT statement
set #sno:=0;
set #client:='';
select #sno:=case when #client=client then #sno+1 else 1 end as sno,
#client:=client as client_id from table order by client;
I want to automatically delete rows when the table (shown below) gets a new insert, if certain conditions are met.
When:
There are rows referring to the same 'field' with the same 'user_id'
Their 'field', 'display' and 'search' columns are the same
Simply, when the rows would become duplicates (except the 'group_id' column) the non null 'group_id' should be deleted, otherwise a row should be updated or inserted.
Is there a way to set this up in mysql (in spirit of "ON DUPLICATE do stuff" combined with unique keys etc.), or do I have to explicitly check for it in php (with multiple queries)?
Additional info:
There should always be a row with NULL 'group_id' for every possible 'field' (there's a limited set, defined elsewhere). On the other hand there might not be one with a non null 'group_id'.
CREATE TABLE `Views` (
`user_id` SMALLINT(5) UNSIGNED NOT NULL,
`db` ENUM('db_a','db_b') NOT NULL COLLATE 'utf8_swedish_ci',
`field` VARCHAR(40) NOT NULL COLLATE 'utf8_swedish_ci',
`display` TINYINT(1) UNSIGNED NOT NULL,
`search` TINYINT(1) UNSIGNED NOT NULL,
`group_id` SMALLINT(6) UNSIGNED NULL DEFAULT NULL,
UNIQUE INDEX `user_id` (`field`, `db`, `user_id`),
INDEX `Views_ibfk_1` (`user_id`),
INDEX `group_id` (`group_id`),
CONSTRAINT `Views_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `User` (`id`) ON
UPDATE CASCADE ON DELETE CASCADE
)
COLLATE='utf8_swedish_ci'
ENGINE=InnoDB;
I think you need to revise your logic. It makes no sense to Insert a row only to delete another row. Why not just update the Group_ID field in the duplicate row to what is being inserted? Below is a rough idea of how I would go about it.
N.b. I haven't done much work with MySQL and cannot get the below to run on SQLFiddle, but based on the MySQL docs I can't work out why. Perhaps someone more versed in MySQL can correct me?
SET #User_ID = 1;
SET #db = 'db_a';
SET #Field = 'Field';
SET #Display = 1;
SET #Search = 1;
SET #Group_ID = 1;
IF EXISTS
( SELECT 1
FROM Views
WHERE User_ID = #User_ID
AND DB = #DB
AND Field = #Field
AND Group_ID IS NOT NULL
)
THEN
UPDATE Views
SET Group_ID = #Group_ID,
Display = #Display,
Search = #Search
WHERE User_ID = #User_ID
AND DB = #DB
AND Field = #Field
AND Group_ID IS NOT NULL
ELSE
INSERT INTO Views (User_ID, DB, Field, Display, Search, Group_ID)
VALUES (#User_ID, #DB, #Field, #Display, #Search, #Group_ID)
END IF;
Alternatively (and my preferred solution), add a Timestamp field to your table and create a view as follows:
SELECT v.User_ID, v.DB, v.Field, v.Display, v.Search, v.Group_ID
FROM Views v
INNER JOIN
( SELECT User_ID, DB, Field, MAX(CreatedDate) AS CreatedDate
FROM Views
WHERE Group_ID IS NOT NULL
GROUP BY User_ID, DB, Field
) MaxView
ON MaxView.User_ID = v.User_ID
AND MaxView.DB = v.DB
AND MaxView.Field = v.Field
AND MaxView.CreatedDate = v.CreatedDate
WHERE v.Group_ID IS NOT NULL
UNION ALL
SELECT v.User_ID, v.DB, v.Field, v.Display, v.Search, v.Group_ID
FROM Views v
WHERE v.Group_ID IS NULL
This would allow you to track changes to your data properly, without compromising the need to be able to view unique records.
delete group_id from Views where group_id != 'NUll'
Your question is not very good to understand, so I'm not sure this is what you want:
DELETE FROM Views WHERE # delete from the table views
group_id IS NOT NULL AND # first condition delete only rows with not null group_id
(SELECT count(*) as tot FROM Views GROUP BY group_id) = 1 # second condition count the difference in group id
If that's not what you want, please update your question with more details...
Mysql table (migration_terms) fields are as follows
oldterm count newterm seed
I used the following create table statment.
CREATE TABLE `migration_terms`
(
`oldterm` varchar(255) DEFAULT NULL,
`count` smallint(6) DEFAULT '0',
`newterm` varchar(255) DEFAULT NULL,
`seed` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`seed`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
And It works, no problems there.
but then when I used the following insert into statement to populate it;
"INSERT INTO migration_terms
SELECT looseterm as oldterm,
COUNT(seed) AS count
FROM looseterms
GROUP BY looseterm
ORDER BY count DESC "
I get this error;
Column count doesn't match value count at row 1
I cannot figure out why?
If you need the table structure of the looseterms table, it was created by the following create table statement.
CREATE TABLE looseterms
(
`seed` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`looseterm` varchar(255)
)
You need to specify the columns if your select statement has fewer columns than the table
"INSERT INTO migration_terms
(oldterm,
count)
SELECT looseterm AS oldterm,
Count(seed) AS count
FROM looseterms
GROUP BY looseterm
ORDER BY count DESC "
From MySql docs on Insert Syntax
If you do not specify a list of column names for INSERT ... VALUES or
INSERT ... SELECT, values for every column in the table must be
provided by the VALUES list or the SELECT statement. If you do not
know the order of the columns in the table, use DESCRIBE tbl_name to
find out.
Your insert is adding 2 columns of data, whereas your table's definition has 4 columns
How to change the order of rows in order to have the rows ordered by custom_field?
For example I have got table with id asc and would like to have the rows in the desc order. I need it in order not to use the 'order by id desc' in the mysql query to optimize the query speed.
I tried:
insert table_with_ordered_rows()
select * from table_with_not_ordered_rows order by id desc;
but it just copy the table with standard asc order.
The only way to get the sorted result set in mysql - is to add ORDER BY in query.
in the mysql query to optimize the query speed.
It is incorrect. If you have issues with query performance - then ask about query performance. Give us complete table structure, the query, the explain and statistics about data.
The only way to guarantee order in a result set is to use an ORDER BY clause. An ORDER BY can make use of an index, if one exists...
That said, the following worked for me on MySQL 5.1.49:
CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`col` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1$$
INSERT INTO t1 (col) VALUES ('a'),('b'),('c');
Result set:
id col
--------
1 a
2 b
3 c
Intermediate table:
CREATE TABLE `t2` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`col` varchar(45) DEFAULT NULL,
`old_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1$$
INSERT INTO t2 (col, old_id)
SELECT t.col, t.id
FROM t1 t
ORDER BY t.id DESC
Result set:
id col old_id
----------------
1 c 3
2 b 2
3 a 1
ALTER `tablename` ORDER BY `orderField` DESC;
But you must execute this query after each insert. See 13.1.7. ALTER TABLE Syntax.