MySQL, two columns both set to the primary key - mysql

For the sake of simplicity lets say I have a table with 3 columns; id, parent_id and name. In this table id is my auto-incrementing primary key. I want to group multiple names together in this table, to do this all names in a group will share the same parent_id. If I am inserting the first name in the group I want the id=parent_id, if i am inserting another name I want to specify a specific parent_id to place that name into a specific group. It would be nice if I could define a default for that column to be the same as the id, if I specify a value for parent_id in the insert query then I would like it to use that value. I know you can set a default to be a specific static value, but can you specify the default to be the same as that row's auto-incrementing primary key? Perhaps this is a job for a trigger or stored procedure?
(I know I could obtain the primary key generated by the last insert and then update the table, but that's 2 quires I'd rather not burn.)
Thanks!

This is a job of a trigger!
CREATE TRIGGER NAME1 AFTER INSERT ON TABLE1
BEGIN
UPDATE TABLE1 SET parent_id = id WHERE (parent_id IS NULL OR parent_id = '');
END;
INSERT INTO TABLE1 (id,parent_id) VALUES (null,null); -- parent_id will be equal to id
INSERT INTO TABLE1 (id,parent_id) VALUES (null,'1'); -- parent_id will be 1
INSERT INTO TABLE1 (id,parent_id) VALUES (null,'2'); -- parent_id will be 2

Related

How to update without altering the structure of table

I have a table which has a structure like as below.
create table test_table (id INT NOT NUll AUTO_INCREMENT
, name varchar(100),
primary key (id))ENGINE=INNODB
Select * from test_table;
id name
1 a
2 b
3 c
Now I want to increment the id by a number lets say 2
So the final results should be
Select * from test_table;
id name
3 a
4 b
5 c
The way I can do it is, first remove the PK and auto increment and then
update the table:
update test_table set id=id+2;
The other way is to make a temp table with out PK and auto increment and then
extract the result to the main table.
Is there any other way to do this without destroying the table structure ?
I am using MYSQL.
In your example, you need to remove the PK first to allow (temporary) duplicate id's during the course of the update.
To avoid duplicates, you must perform an ordered update:
UPDATE test_table SET id = id + 2 ORDER BY id DESC;
This will update records with largest value of id first, hence avoiding collision.
Obviously, if you want to decrement the values of id, then use "ORDER BY id ASC".
Here is the query to update the tables in SQL :- Its generic
UPDATE table_name SET column1=value, column2=value2,WHERE some_column=some_value;
Please follow the link for more information
Update Query
Thanks,
Pavan

Using values from another table as ENUM values in a table

Let's assume that I have mytable in mySQL
CREATE TABLE `mytable` (
`gender` enum('MALE','FEMALE','UNISEX') NOT NULL,
);
I don't want to enumerate these values at design time. I want to put them in another_table as values.
In another_table the SELECT values are:
ID NAME
== ======
01 MALE
02 FEMALE
03 UNISEX
I can define the mytable.gender as INT and combine these two tables in WHERE clause with sth like mytable.gender=another_table.id.
Can I create a database level foreign-key relationship with these enum values at design time?
Yes, you use a foreign key constraint.
That will make the database refuse inserts or updates to id values in the mytable table that doesn't exist in the another_table table, and refuse deletes from the another_table table for values that are used in the mytable table.

Inserting into table in order

How can I insert values into a table (MySQL) in the following manner:
On all the rows of a table, in order of ID column (PK), insert incrementing number in column 'num'?
For example if the table had 3 rows , with Ids 1,5,2, I want ID 1 to get num=1, ID 2 to get num=2 and ID 5 to get num=3.
EDIT
I will explain why I (think I) need this:
I am trying to split a column off a table into a separate table with a 1-to-1 relation. I thought I would get all the values in order of ID and insert them into the new table, with an auto-incrementing PK. then I know that, in order of ID, the values for the new reference column in the original table will be auto-incrementing numbers. So I want to insert them in that order. I hope this is clear.
i am currently not in front of sql database engine and cannot therefore submit fully verified sql code. however if your num field is not an autoincrement field than do something like this:
CREATE TEMPORARY TABLE temp_table_x (
num int auto_increment primary key,
reference_id int
);
INSERT temp_table_x (reference_id)
SELECT id FROM source_table ORDER BY id;
UPDATE source_table st
SET st.num = x.num
FROM temp_table_x x
WHERE reference_id = id;
As long as the num field is an autoincrement field it should be as simple as:
INSERT INTO
yourTable (
field1,
field2,
field3,
etc
)
SELECT
field1,
field2,
field3
FROM
yourSourceTable
ORDER BY
originalIdField
I would NOT make a field that references a column in another table an auto-increment column.
Even if the column that it references is an auto-increment, I wouldn't make the column auto-increment. It will be difficult to keep the columns in sync. If an insert is rolled back in one table but not the other, you'll be out of sync until you reset the auto_increment value.
If it's a 1 to 1 relationship, feel free to make the column a primary key. That way it will be ordered by the column, and it will ensure unique values. However, if any two columns must match, they should not both be auto-increment, though, they should be of the same type (eg. INTEGER).
For example, here's our original table, where the first column is an auto-increment integer column:
id customer_name email_address
---------------------------
1 jsmith jsmith#aol.com
2 bwilliams bwilliams#aol.com
If you wanted to split the email_address off to its own table, in a 1 to 1 relationship:
id email_address
---------------------------
1 jsmith#aol.com
2 bwilliams#aol.com
I would make the first column an integer field and make it the primary key, but it would NOT be an auto-increment column.
To insert values into such a table, you could simply do this:
INSERT INTO table2
(id, email_address)
SELECT id, email_address
FROM table1
ORDER BY id
I found the answer. It is very simple:
SET #c=0;
UPDATE myTable SET num = (#c:=#c+1) ORDER BY id

SQL unique contraint if a column is set to x

is there a way in SQL to create the constraint that a column has to be unique, if a specific column has a specific value?
Example: the rows are not really deleted, but marked as 'deleted' in the database. And within the 'not-deleted' rows, ValueA has to be unique:
ID ValueA ValueB Deleted
-----------------------------------------------------
1 'foo' 10 0
2 'bar' 20 0
3 'bar' 30 1
4 'bar' 40 1
5 'foo' 50 0 --NOT ALLOWED
I thought of something like a CHECK constraint, however I don't know how to do this.
with SQL92 this is not possible, may be you could implement something with a trigger
Can you change the design a little bit?
It seems to me that you have a list of "thingies". For each ValueA, there's a single active "thingy" at any one time. This can best be modeled as follows:
Remove ValueA and Deleted from your main Thingies table.
Create a new table ActiveThingies with columns ValueA and ID. Protect this table by making ValueA a unique or primary key. (You may also need to make ID unique as well depending on whether a single ID can represent more than 1 ValueA).
Now, use the ActiveThingies table to control which record is current at any time. To change the active (non-deleted) record for "foo", update it's ID column in ActiveThingies.
To get your list of non-deleted items join the two tables.
With this design, however, you will lose the ability to remember the ValueA for "deleted" "thingies". If you need to remember those values, you will also need to include the ValueA column in Thingies.
There is workaround this problem - create another column deleted_on
deleted_on timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
and make unique key on both ValueA and deleted_on
UNIQUE KEY not_deleted (ValueA, deleted_on)
When soft deleting a record insert NOW() for value of deleted_on
MySQL ignores CHECK constraints, so you cannot do this in MySQL as you might in another database.
Here is a hack. Unique constraint on valueA + deleted. When deleting rows you cannot use just 1, they must be 1, 2, 3...
This at least lets you do it server-side in MySQL, but introduces a step. When marking a row for deletion, you have to first go find the max(deleted), add 1, and plug that value in when marking for deletion.
Split your table into two tables: One which has a UNIQUE constraint on ValueA and one that doesn't. Use a view+triggers to combine the two tables. Something like:
CREATE TABLE _Active (
ID INTEGER,
ValueA VARCHAR(255) UNIQUE,
ValueB INTEGER
);
CREATE TABLE _Deleted (
ID INTEGER,
ValueA VARCHAR(255), /* NOT unique! */
ValueB INTEGER
);
CREATE VIEW Thingies AS
SELECT ID, ValueA, ValueB, 0 AS Deleted FROM _Active
UNION ALL
SELECT ID, ValueA, ValueB, 1 AS Deleted FROM _Deleted;
CREATE TRIGGER _trg_ii_Thingies_Active
INSTEAD OF INSERT ON Thingies
FOR EACH ROW WHEN NOT NEW.Deleted
BEGIN
INSERT INTO _Active(ID, ValueA, ValueB)
VALUES (NEW.ID, NEW.ValueA, NEW.ValueB);
END;
CREATE TRIGGER _trg_ii_Thingies_Deleted
INSTEAD OF INSERT ON Thingies
FOR EACH ROW WHEN NEW.Deleted
BEGIN
INSERT INTO _Deleted(ID, ValueA, ValueB)
VALUES (NEW.ID, NEW.ValueA, NEW.ValueB);
END;
/* Add triggers for DELETE and UPDATE as appropriate */
(I'm not sure about the CREATE TRIGGER syntax, but you know what I mean.)

MySQL INSERT only if row doesn't exist, otherwise select the duplicate row

I am looking for a statement that will try to insert a row into a table, but return the primary key of the duplicate row if one is encountered. One field in the table is the auto incrementing primary key, the other is unique.
This should, at least in theory, work for you:
First extend your table to have an additional column dummy of type tinyint. Then you can use the following query when inserting/updating:
INSERT INTO yourtable (a, b) VALUES (1, 2) ON DUPLICATE KEY UPDATE id = LAST_INSERT_ID(id), dummy = NOT dummy
(I'm assuming here that the column a has a unique index and a row with a=1 exists.)
You can then get the ID of the new row (in case of an INSERT) or the existing row (in case of an UPDATE) via
SELECT LAST_INSERT_ID()
This should work in DB2, dont know if it will in MySQL or if there is special MySQL syntax for it:
SELECT pk, 'inserted' FROM FINAL TABLE (
INSERT INTO table (Col1)
SELECT Val1
FROM table
WHERE col1 != Val1
FETCH FIRST ROW ONLY
)
UNION
SELECT pk, 'existing'
FROM table
WHERE col1 = val1
The idea here is to select one row from the table when there is not a unique value in there, inserting the new value and returning the generated primary key from the table. This is then combined with the select that returns the corresponding key if the unique values is already in the table. Only one of those statements should return a row, the second column indicating if the primary key is new or exisiting.