I have a simple MySQL Database like:
CREATE TABLE `tab_update` (
`id` int(11) NOT NULL,
`number` int(11) NOT NULL,
`description` varchar(11) NOT NULL,
UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
and some data inside:
INSERT INTO `tab_update` (`id`, `number`, `description`) VALUES ('111', '5', 'first value');
INSERT INTO `tab_update` (`id`, `number`, `description`) VALUES ('222', '5', 'first value');
INSERT INTO `tab_update` (`id`, `number`, `description`) VALUES ('333', '5', 'first value');
What I want is to:
insert data to the database, if the same 'id' does not exist already
or
update data if both below conditions are met:
a) 'id' is already in the database
b) new number value is bigger than the number stored already
What I am trying to do now is:
INSERT INTO tab_update (id, number, description) VALUES (333, 1, 'second value')
ON DUPLICATE KEY UPDATE number = GREATEST(number, VALUES(number)), description = 'second value'
this works partially - inserts data or update, however, I have a wrong behavior. If we have 'number = 1' (which is less then 5) this should not update the record.
At the moment keeps updating description, but should not.
Could you please guys help me improve this query?
update:
I am trying also:
INSERT INTO tab_update (id, number, description) VALUES (333, 6, 'second value')
ON DUPLICATE KEY UPDATE
number = GREATEST(number, VALUES(number)),
description = IF(VALUES(number) > number, VALUES(description), description)
but last line does not work as expected.
Related
The problem:
When I update Tom in the redo table, I want the changes to affect the daily and lab irrespective of whether Tom exists in daily or lab. Even if he doesn't exist in daily or
lab I want the update to be made only in the redo table.
Look at the tables below:
First table redo
Second Table daily
Third Table lab
What I tried:
UPDATE redo,daily,lab SET
redo.name = '$newName', daily.name = '$newName', lab.name = '$newName',
redo.place = '$newPlace', daily.place = '$newPlace', lab.place = '$newPlace',
redo.code = '$newCode', daily.code = '$newCode', lab.code = '$newCode',
redo.age = '$newAge', daily.age= '$newAge', lab.age = '$newAge',
redo.date = redo.date, daily.date = daily.date, lab.date = lab.date,
redo.contact = '$newContact',daily.contact = '$newContact', lab.contact='$newContact',
redo.secondarycontact = '$newSecondaryContact',
daily.secondarycontact = '$newSecondaryContact',
lab.secondarycontact = '$newSecondaryContact'
WHERE redo.no='$no' AND
(redo.name=daily.name AND redo.name=lab.name) AND
(redo.place=daily.place AND redo.place=lab.place)
Result:
Values are updated only if they exist in all the 3 tables at the same time.
Given your use case and relationships, this is how I would set up the tables if it were my project:
NOTE:
I've made some assumptions about your field types in the below that may not be correct, but it should be trivial to adapt them as needed for your use case.
Using this structure will require slightly more complex or well thought out queries, but the result will be MUCH more maintainable and far less error prone.
I would normaly name columns and such differently, but I've elected to use names similar to the naming convention you seem to be using to keep it simple since this question isnt about "best practices naming columns" etc..
Create the tables
Create an 'activities' table to hold all types of activities in one place, note the "type" column with possible values of 'lab','redo','daily'
CREATE TABLE `activities` (
`no` bigint(20) NOT NULL AUTO_INCREMENT,
`consultation` varchar(255) DEFAULT NULL,
`lab` varchar(255) DEFAULT NULL,
`token` VARCHAR(45) NULL,
`detailsid` bigint(20) NOT NULL,
`foreignkey` bigint(20) DEFAULT NULL,
`type` enum('lab','redo','daily') NOT NULL,
`date` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`no`)
);
Create an 'activitiyusers' table to hold the details for the people that are related to our "activities"
CREATE TABLE `activitiyusers` (
`no` BIGINT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL,
`gender` ENUM('M', 'F') NOT NULL,
`age` SMALLINT NULL,
`contact` VARCHAR(255) NOT NULL,
`secondarycontact` VARCHAR(255) NULL,
`place` VARCHAR(255) NULL,
`code` VARCHAR(45) NULL,
`createdat` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
`updatedat` VARCHAR(45) NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`no`));
Insert some test data
Insert 3 new "activitiyusers"
INSERT INTO `activitiyusers` (`name`, `gender`, `age`, `contact`, `secondarycontact`, `place`, `code`) VALUES ('Tom', 'M', '31', '1212121', '3434343', 'California', '1');
INSERT INTO `activitiyusers` (`name`, `gender`, `age`, `contact`, `secondarycontact`, `place`, `code`) VALUES ('Jack', 'M', '45', '99999', '11111', 'Colorado', '2');
INSERT INTO `activitiyusers` (`name`, `gender`, `age`, `contact`, `secondarycontact`, `place`, `code`) VALUES ('Harry', 'M', '99', '112233', '998877', 'Texas', '3');
Insert 3 new "redo" activities, one related to each of our 3 "activitiyusers"
INSERT INTO `activities` (`token`, `detailsid`, `foreignkey`, `type`) VALUES ('0', '1', NULL, 'redo');
INSERT INTO `activities` (`token`, `detailsid`, `foreignkey`, `type`) VALUES ('0', '2', NULL, 'redo');
INSERT INTO `activities` (`token`, `detailsid`, `foreignkey`, `type`) VALUES ('0', '3', NULL, 'redo');
Insert 2 new "daily" activities, one related to Tom and 'redo' activity 1, the second related to Harry and 'redo' activity 3"
INSERT INTO `activities` (`consultation`, `detailsid`, `foreignkey`, `type`) VALUES ('Cough and Cold', '1', '1', 'daily');
INSERT INTO `activities` (`consultation`, `detailsid`, `foreignkey`, `type`) VALUES ('Panadol', '3', '3', 'daily');
Insert 2 new "lab" activities, one related to Jack and 'redo' activity 2, the second related to Harry and 'redo' activity 3"
INSERT INTO `activities` (`lab`, `detailsid`, `foreignkey`, `type`) VALUES ('Blood Test', '2', '2', 'lab');
INSERT INTO `activities` (`lab`, `detailsid`, `foreignkey`, `type`) VALUES ('Injection', '3', '3', 'lab');
Examples of how to work with this data:
Note: these queries will make use of join cluases as well as Column and table aliases
Get All "activities" for "Tom", along with Tom's details
SELECT
a.no AS activityno,
a.consultation,
a.lab,
a.token,
a.type,
a.date,
au.no AS userno,
au.name,
au.gender,
au.age,
au.contact,
au.secondarycontact,
au.place,
au.code,
au.createdat,
au.updatedate
FROM
activities a
JOIN
activitiyusers au ON a.detailsid = au.no
WHERE
name = 'Tom';
Get all "redo type activities" for "Jack", along with Jack's details
SELECT
a.no AS activityno,
a.consultation,
a.lab,
a.token,
a.type,
a.date,
au.no AS userno,
au.name,
au.gender,
au.age,
au.contact,
au.secondarycontact,
au.place,
au.code,
au.createdat,
au.updatedate
FROM
activities a
JOIN
activitiyusers au ON a.detailsid = au.no
WHERE
name = 'Jack' AND a.type = 'redo';
# Given a known activity that has an id/no of '2',
# update the details for the activityuser related to that activity
UPDATE activitiyusers
SET
contact = '22222222',
age = 46,
code = 5
WHERE
no = (SELECT
detailsid
FROM
activities
WHERE
no = 2);
Given a known "repo" activity that has an id/no of '3', get all sub activities related to that activity along with details of the related activitiyuser
Note that this utilizes a mysql self join, ie we are joining the activities on itself to get subActivity rows that are related to a given redoActivity row.
SELECT
redoActivity.no AS redoactivityno,
subActivity.no AS subactivityno,
redoActivity.consultation AS redoactivityconsultation,
subActivity.consultation AS subactivityconsultation,
subActivity.lab,
redoActivity.token,
subActivity.type,
redoActivity.date AS redoactivitydate,
subActivity.date AS subactivitydate,
au.no AS userno,
au.name,
au.gender,
au.age,
au.contact,
au.secondarycontact,
au.place,
au.code,
au.createdat,
au.updatedate
FROM
activities subActivity
JOIN activities redoActivity ON subActivity.foreignkey = redoActivity.no
JOIN activitiyusers au ON redoActivity.detailsid = au.no
WHERE
redoActivity.no = 3;
i stumbled the following problem that i cannot solve
i have the following table in the database
CREATE TABLE `departments` (
`Company` int(11) NOT NULL,
`Department` varchar(32) NOT NULL,
`DepartmentName` varchar(40) NOT NULL,
`parentDepartment` varchar(32) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `departments` (`Company`, `Department`, `DepartmentName`, `parentDepartment`) VALUES
(1, '1', 'Company1 Ltd', '1'),
(1, '101', 'Information Technology', '1'),
(1, '10101', 'Hardware', '101'),
(1, '10102', 'Software', '101'),
(1, '102', 'Sales Department', '1'),
(1, '10201', 'Travelling', '101');
COMMIT;
basically its a list of departments in the company. Each department can be "nested" under another using the "parentDepartment" field.
Department field is the code of the department. But the numbering is irrelevant to the "structure".
what i want to achieve can be viewed in the picture bellow.
The question is how to sort this table out and keep the relationships visible?
Thank you
Try this:
SELECT *
FROM departments
ORDER BY department;
I need to insert a new row into the database and then only if a previous value in the row has changed.
--
-- Table structure
--
CREATE TABLE IF NOT EXISTS `macip` (
`intId` int(11) NOT NULL AUTO_INCREMENT,
`strPort` varchar(255) NOT NULL,
`strIp` varchar(255) DEFAULT NULL,
`strVlan` varchar(255) DEFAULT NULL,
`strMac` varchar(255) DEFAULT NULL,
PRIMARY KEY (`intId`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=7 ;
--
-- Test data
--
INSERT INTO `macip` (`intId`, `strPort`, `strIp`, `strVlan`, `strMac`) VALUES
(1, 'Gig1/0/1', '192.168.100.8', '10', 'AA-BB'),
(2, 'Gig1/0/1', '192.168.100.8', '10', 'CC-DD'),
(6, 'Gig1/0/1', '192.168.100.8', '20', 'AA-BB');
I have got a unchanging column strPort
Next want do INSERT like this:
First insert to database ('Gig1/0/1', '192.168.100.8', '10', 'AA-BB') = > do INSERT
Next insert to database ('Gig1/0/1', '192.168.100.8', '10', 'AA-BB') => do not insert, exists
Next insert to database ('Gig1/0/1', '192.168.100.8', '10', 'XX-EE') => do insert, changed MAC (or IP or VLAN or all this two/three values)
Next insert to database ('Gig1/0/1', '192.168.100.8', '10', 'XX-EE') => do not insert, exists
Next insert to database ('Gig1/0/1', '192.168.100.8', '10', 'AA-BB') => do insert, changed MAC (or IP or VLAN or all this two/three values), but there is a problem in my SQL query, because this value exists in table, I need to compare with previous row with strPort
This query doesn't work:
INSERT INTO macip (strPort, strIp, strVlan, strMac)
SELECT * FROM (SELECT 'Gig1/0/1', '192.168.100.8', '10', 'AA-BB') AS tmp
WHERE NOT EXISTS (
SELECT strIp, strVlan, strMac FROM macip WHERE
strIp = '192.168.100.8' AND strVlan = '10' AND strMac = 'AA-BB'
ORDER BY macip.`strPort` DESC LIMIT 1
) LIMIT 1;
I can't do a unique keys to columns, because SQL query return Exception.
How about just creating a unique constraint/index to prevent this problem?
create unique index idx_macip_strip_strvlan_strMac on macip(strIp, strVlan, strMac);
Then you can do the insert as:
INSERT INTO macip (strPort, strIp, strVlan, strMac)
SELECT 'Gig1/0/1', '192.168.100.8', '10', 'AA-BB'
ON DUPLICATE KEY SET strPort = VALUES(strPort);
The ON DUPLICATE KEY portion just prevents the INSERT from returning an error when there is a duplicate.
CREATE TABLE IF NOT EXISTS `myproducts` (
`uid` int(10) unsigned NOT NULL AUTO_INCREMENT,
`parent_id` int(10) unsigned DEFAULT NULL,
`type_id` varchar(64) COLLATE utf8_czech_ci NOT NULL DEFAULT 'NormalPage',
`name` varchar(255) COLLATE utf8_czech_ci NOT NULL DEFAULT '',
PRIMARY KEY (`uid`),
KEY `index_2` (`type_id`,`t`),
KEY `name` (`name`),
KEY `parent_id` (`parent_id`,`name`(48))
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci ROW_FORMAT=DYNAMIC AUTO_INCREMENT=189 ;
This is my insert statement.
INSERT INTO `mydb`.`myproducts` (`uid`, `parent_id`, `type_id`, `name`) VALUES ('',20, 'Product Category', 'WaterBottels');
Problem Description :
When i use this insert query in my system which is having mysql version 5.5.16 it is perfectly inserting the record but when i try this in another system which is also having mysql version 5.5.16 it is giving problem.
I do know we should pass NULL or '0' for the auto increment column , but my question why it is working for my instance.
As it is working for my instance , i am considering we can pass '' as the value for auto increment column. if so to work it out in other system do i need to change any mysql configurations.
Try executing this query to insert:
INSERT INTO `mydb`.`myproducts` (`parent_id`, `type_id`, `name`)
VALUES (20, 'Product Category', 'WaterBottels');
You don't need to specify the primary key column as that will be auto inserted.
Values is not required for AUTO_INCREMENT fields as it will be auto generated. so you can insert a row without specifying the value for column uid.
user either of the following
INSERT INTO `mydb`.`myproducts` (`uid`, `parent_id`, `type_id`, `name`) VALUES
(null,20, 'Product Category', 'WaterBottels');
OR
INSERT INTO `mydb`.`myproducts` ( `parent_id`, `type_id`, `name`) VALUES
(20, 'Product Category', 'WaterBottels');
Since You are using uid as a AUTO_INCREMENT.
MySQL uses the AUTO_INCREMENT keyword to perform an auto-increment feature.
By default, the starting value for AUTO_INCREMENT is 1, and it will increment by 1 for each new record.
You can use
INSERT INTO `mydb`.`myproducts` (`parent_id`, `type_id`, `name`) VALUES (20, 'Product Category', 'WaterBottels');
instead of
INSERT INTO `mydb`.`myproducts` (`uid`, `parent_id`, `type_id`, `name`) VALUES ('',20, 'Product Category', 'WaterBottels');
Since your column uid id auto incremented, you don't need to pass a value while insertion. Try this:
INSERT INTO `mydb`.`myproducts` (`parent_id`, `type_id`, `name`) VALUES (20, 'Product Category', 'WaterBottels');
This will work on all systems and your uid will get auto incremented.
Initial goal:
I would like to generate random and unique codes (6 digits) in a table.
I use a SQL query like this one to do that:
SELECT SUBSTRING(CRC32(RAND()), 1, 6) as myCode
FROM `codes`
HAVING myCode NOT IN (SELECT code FROM `codes`)
I asked me about how it will react when there will be no more available codes so I do the following test
Test context:
MySQL version: 5.5.20
MySQL Table:
CREATE TABLE `codes` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`code` VARCHAR( 10 ) NOT NULL ,
UNIQUE (
`code`
)
) ENGINE = InnoDB;
Initial data:
INSERT INTO `codes` (`id`, `code`)
VALUES (NULL, '1'), (NULL, '2'), (NULL, '3'), (NULL, '4'), (NULL, '5'), (NULL, '6'), (NULL, '7'), (NULL, '8');
SQL Query:
SELECT SUBSTRING(CRC32(RAND()), 1, 1) as myCode
FROM `codes`
HAVING myCode NOT IN (SELECT code FROM `codes`)
By execute this query, I expect that it will always return 9 because it is the only code of one digit which does not exists.
But the result is:
Sometime it return any rows
Sometime it return rows with values that already exists
I don't understand this behavior so if someone can help :)
So the big question is:
How MySQL can return rows with values that already exists?
Thanks
I would fill a sequencetable table with all the possible values, in sequence.
Then the random query just randomly selects records from the sequencetable, and each time it picks a record it deletes it. This way you will surely get all the numbers, without wasting time in finding a "hole" number (not already picked up).
CREATE TABLE `sequencetable`
(
`sequence` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`sequence`)
)
ENGINE=InnoDB
AUTO_INCREMENT=1;
Fill the sequence (no need for the AUTOINCREMENT actually).
DECLARE i INT;
SET i=1;
REPEAT
INSERT INTO sequencetable VALUES (i);
SET i=i+1;
UNTIL i>999999 END REPEAT;
Select a random record from the sequence (do this in a loop until records are available):
DECLARE sequencen INT;
SET sequencen =
(SELECT sequence FROM sequencetable ORDER BY RAND() LIMIT 1);
DELETE FROM sequencetable WHERE sequence = sequencen;