For the following table:
I'd like to add a constraint that if IsBanned flag is set to true, the BannedOn field cannot be left empty (cannot be set to null).
How can I do this in MySQL? Here's my CREATE syntax:
CREATE TABLE IF NOT EXISTS `fa_ranking_system`.`Player` (
`PlayerID` INT NOT NULL AUTO_INCREMENT,
`FK_ServerID` INT NOT NULL,
`PlayerName` VARCHAR(15) NOT NULL,
`RegDate` DATETIME NOT NULL,
`IsBanned` TINYINT(1) NOT NULL,
`LastUpdatedOn` DATETIME NOT NULL,
`LastUpdatedBy` VARCHAR(20) NOT NULL,
`BannedOn` DATETIME NULL,
PRIMARY KEY (`PlayerID`, `FK_ServerID`),
INDEX `fk_Player_Server_idx` (`FK_ServerID` ASC),
CONSTRAINT `fk_Player_Server`
FOREIGN KEY (`FK_ServerID`)
REFERENCES `fa_ranking_system`.`Server` (`ServerID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
Actually, you can not define conditional structures in DDL syntax. Your field can be either NULL or NOT NULL - there's no third option (and it cannot depend of another field in structure)
But you can still emulate desired behavior via triggers. You can interrupt UPDATE/INSERT statement if incoming data is invalid in terms of your logic. That can be done via:
CREATE TRIGGER `bannedOnCheck`
BEFORE INSERT ON `fa_ranking_system`.`Player`
FOR EACH ROW
BEGIN
IF(new.IsBanned && new.BannedOn IS NULL) THEN
SIGNAL 'Integrity check failed: can not set banned without ban date'
END IF
END
Related
So I'm trying to migrate a table from MySQL to MSSQL (sql server migration assistant MySQL), but I get this error:
Migrating data...
Analyzing metadata...
Preparing table testreportingdebug.testcase...
Preparing data migration package...
Starting data migration Engine
Starting data migration...
The data migration engine is migrating table '`testreportingdebug`.`testcase`': > [SwMetrics].[testreportingdebug].[testcase], 8855 rows total
Violation of UNIQUE KEY constraint 'testcase$Unique'. Cannot insert duplicate key in object 'testreportingdebug.testcase'. The duplicate key value is (<NULL>, <NULL>).
Errors: Violation of UNIQUE KEY constraint 'testcase$Unique'. Cannot insert duplicate key in object 'testreportingdebug.testcase'. The duplicate key value is (<NULL>, <NULL>).
Completing migration of table `testreportingdebug`.`testcase`...
Migration complete for table '`testreportingdebug`.`testcase`': > [SwMetrics].[testreportingdebug].[testcase], 0 rows migrated (Elapsed Time = 00:00:00:01:352).
Data migration operation has finished.
0 table(s) successfully migrated.
0 table(s) partially migrated.
1 table(s) failed to migrate.
I've just copied three rows from my table, and this is what they look like:
'1', 'Pump# TimeToService', NULL, NULL, 'A general test case comment ...', '0'
'2', 'Config.SlaveMinimumReplyDelay', NULL, NULL, NULL, '0'
'3', 'Config.RESERVED', NULL, NULL, NULL, '0'
If you are wondering how the colons in the MySQL table is setup, here you go:
Is is because right, left and comment can be null?
DDL of table
CREATE TABLE `testcase` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`TestCaseName` varchar(150) DEFAULT NULL,
`Left` int(11) DEFAULT NULL,
`Right` int(11) DEFAULT NULL,
`Comment` text,
`Hidden` tinyint(4) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `Unique` (`Left`,`Right`)
) ENGINE=InnoDB AUTO_INCREMENT=10580 DEFAULT CHARSET=utf8
Had to remove the Unique part, since their are only NULL.
ALTER TABLE `testreportingdebug`.`testcase`
DROP INDEX `Unique`;
If you want the strict equivalent in SQL Server of your MySQL table you must create it like this :
CREATE TABLE testcase (
id int NOT NULL IDENTITY PRIMARY KEY,
TestCaseName varchar(150),
[Left] int,
[Right] int,
Comment VARCHAR(max),
[Hidden] tinyint DEFAULT 0,
);
CREATE UNIQUE INDEX X_testcase_right_left
ON testcase ([Left], [Right])
WHERE [Left] IS NOT NULL
AND [Right] IS NOT NULL;
By the way, column names "Right", "left", "hidden" are SQL / MS SQL Server reserved words and should not be used at anytime for SQL identifiers (table name, colum name, proc name...)
The complete list can be obtain here
On MySQL I have a problem regarding a constraint I'm making on the column "loueur_id" of my vehicle table. I'm trying to make it so when the column location have "disponible" or "en_revision" as value then the value of "loueur_id" become null but if the value of "location" is NULL then "loueur_id" value become the id of the customer who is renting the vehicle
CREATE TABLE IF NOT EXISTS `vehicule` (
`id` int NOT NULL AUTO_INCREMENT,
`typ` int NOT NULL UNIQUE,
`nb` int NOT NULL,
`caract` json NOT NULL,
`location` varchar(20),
`photo` varchar(20) NOT NULL,
`loueur_id` int,
PRIMARY KEY (`id`),
INDEX per_loueur (`loueur_id`),
FOREIGN KEY(`loueur_id`) REFERENCES `client`(`id`) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
ALTER TABLE `vehicule`
ADD CONSTRAINT CK_location CHECK ((`location` in('disponible', 'en_revision')))
ADD CONSTRAINT CK_loueur CHECK (`loueur_id` = CASE WHEN `location` in('disponible', 'en_revision' THEN NULL ELSE `loueur_id` END CASE));
This is what I tried to do but mysql said that I've made a syntax error on my last Check constraint. Can someone help me find the problem's solution please?
It is often simpler to express the constraints with boolean logic rather than with case expressions. I think this does what you want:
alter table `vehicule`
add constraint ck_location check ((location in('disponible', 'en_revision'))),
add constraint ck_loueur check (
(location in('disponible', 'en_revision') and loueur_id is null)
or (location is null and loueur_id is not null)
)
Note that check constraints are available starting MySQL 8.0.16 only. In earlier versions, they are parsed without errors, but not actually enforced.
You can do this with one constraint:
alter table `vehicule`
add constraint ck_vehicule_location_loueur_id
check ( (location in ('disponible', 'en_revision') and loueur_id is null) or
(location is null and loueur_id is not null)
);
I currently build a database and write stored procedures for an Android app. I am long time programmer and created some databases years ago, but did not really work with stored procedures until now. The problem that I have at the moment is that I find no right way to check if a given string (specified by stringId) and a given language (specified by languageId) does not exist, and if a translated string already exists before I go on and insert a new translated string into the table TranslatedStrings. I looked up many similar questions and lots of other websites and although some seem to have had the exact same problem their solution did work for them but not for me.
Here is my current Create Procedure script:
create procedure `InsertTranslatedString`(in stringId int(10) unsigned, in translationSource tinyint(3) unsigned, in translationLanguageId int(10) unsigned,
in translatedString mediumtext, out insertedTranslatedStringId int(10) unsigned, out returnValue int(10))
reads sql data
modifies sql data
begin
-- if the string id does not exists
if (select count(1) from `Strings` where `stringId` = stringId) = 0
then
-- return error code
set returnValue = -1;
set insertedTranslatedStringId = 0;
-- if the language id does not exists
elseif (select count(1) from `Languages` where `languageId` = translationLanguageId) = 0
then
-- return error code
set returnValue = -2;
set insertedTranslatedStringId = 0;
-- if the translated string already exists
elseif (select count(1) from `TranslatedStrings` where `stringId` = stringId and `languageId` = translationLanguageId) > 0
then
-- return error code
set returnValue = -3;
set insertedTranslatedStringId = 0;
-- if we are ready to go
else
-- insert the actual translated string
insert into TranslatedStrings (`stringId`, `languageId`, `value`, `translationSource`, `createdDateTime`)
values (stringId, translationLanguageId, translatedString, translationSource, now());
select #newTranslatedStringId := last_insert_id();
-- give back output parameters
set insertedTranslatedStringId = #newTranslatedStringId;
set returnValue = 0;
end if;
end $$
The creation of the procedure works like charm.
I call the procedure with call InsertTranslatedString(76, 0, 1, 'German (Germany)', #insertedTranslatedStringId, #returnValue); Both stringId 76 and languageId 1 do not exist.
When I make this call I notice that the if-elseif-elseif-else block skips the first if (stringId check) even though it should enter its then block. The procedure however enters the first elseif (languageId check) which works fine.
I also tried out if-checks like these: if not exists (select 1 from 'Strings' where 'stringId' = stringId) but there the exists() function seemed to always return true not matter if the select returned a row or no row; the procedure would then skip right through to the second elseif just because I used a elseif exists (select... there. The actual select however does not return any row if I run it separately. Very confusing.
Here are the three referenced tables:
CREATE TABLE `Languages` (
`languageId` int(10) unsigned NOT NULL,
`nameStringId` int(10) unsigned NOT NULL,
`languageCode` varchar(5) DEFAULT NULL,
`hiddenInSettings` tinyint(1) DEFAULT '0',
PRIMARY KEY (`languageId`),
KEY `FK_Languages_nameStringId` (`nameStringId`),
CONSTRAINT `FK_Languages_nameStringId` FOREIGN KEY (`nameStringId`) REFERENCES `Strings` (`stringId`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='contains all supported and automatically translated languages'
CREATE TABLE `Strings` (
`stringId` int(10) unsigned NOT NULL AUTO_INCREMENT,
`originalValue` mediumtext NOT NULL,
`originalLanguageId` int(10) unsigned NOT NULL,
PRIMARY KEY (`stringId`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='contains all language-independent strings instances'
CREATE TABLE `TranslatedStrings` (
`stringId` int(10) unsigned NOT NULL,
`languageId` int(10) unsigned NOT NULL,
`value` mediumtext NOT NULL,
`translationSource` tinyint(3) unsigned DEFAULT '0',
`createdDateTime` datetime DEFAULT NULL,
`lastModifiedDateTime` datetime DEFAULT NULL,
`incorrectTranslationState` tinyint(3) unsigned DEFAULT '0',
`incorrectTranslationReporterId` int(10) unsigned DEFAULT NULL,
`incorrectTranslationReportedDateTime` datetime DEFAULT NULL,
PRIMARY KEY (`stringId`,`languageId`),
KEY `FK_TranslatedStrings_languageId` (`languageId`),
KEY `FK_TranslatedStrings_incorrectTranslationReporterId` (`incorrectTranslationReporterId`),
CONSTRAINT `FK_TranslatedStrings_incorrectTranslationReporterId` FOREIGN KEY (`incorrectTranslationReporterId`) REFERENCES `Users` (`userId`) ON DELETE CASCADE,
CONSTRAINT `FK_TranslatedStrings_languageId` FOREIGN KEY (`languageId`) REFERENCES `Languages` (`languageId`) ON DELETE CASCADE,
CONSTRAINT `FK_TranslatedStrings_stringId` FOREIGN KEY (`stringId`) REFERENCES `Strings` (`stringId`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='contains all localized and automatically translated strings'
When I created the tables I did not create these KEY entries by the way, they were created by MySQL Server. Odd that they only resemble some of the CONSTRAINT entries and not all.
Since Strings only has a single-column primary key and no foreign keys I'm puzzled that its corresponding if-statement isn't triggered. What I am doing wrong?
I have a table horse and a view view_horse that selects every column from the horse table except the primary key (primary key is auto-increment integer) and then presents it to the user, I want to insert data into that views underlying table and naturally expect the primary key to be automatically generated. But I keep getting an SQL exception stating "field of view view_horse underlying doesn't have a default value" when I try to insert any data into it.
EDIT -
CREATE TABLE IF NOT EXISTS `TRC`.`horse` (
`horse_id` INT NOT NULL AUTO_INCREMENT,
`registered_name` VARCHAR(20) NOT NULL,
`stable_name` VARCHAR(20) NOT NULL,
`horse_birth_year` DATE NOT NULL,
`horse_height` DECIMAL(3,1) NOT NULL,
`horse_location` VARCHAR(50) NOT NULL DEFAULT 'TRC',
`arrival_date` DATE NOT NULL,
`passport_no` MEDIUMTEXT NULL,
`is_deceased` TINYINT(1) NOT NULL,
`arrival_weight` DECIMAL NOT NULL,
`horse_sex` VARCHAR(8) NOT NULL,
`microchip_no` VARCHAR(15) NULL,
`date_of_death` DATE NULL,
PRIMARY KEY (`horse_id`),
INDEX `fk_Horses_SexLookup1_idx` (`horse_sex` ASC),
CONSTRAINT `fk_Horses_SexLookup1`
FOREIGN KEY (`horse_sex`)
REFERENCES `TRC`.`lookup_sex` (`sex`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
USE `TRC`;
CREATE OR REPLACE VIEW `TRC`.`view_horse` AS SELECT
registered_name AS 'Registered Name',
stable_name AS 'Stable Name',
horse_birth_year AS 'Age',
horse_height AS 'Height',
arrival_weight AS 'Weight on Arrival',
horse_sex AS 'Sex',
horse_location AS 'Location',
arrival_date AS 'Date of Arrival',
passport_no AS 'Passport no.',
microchip_no AS 'Microchip no.',
is_deceased AS 'Alive?'
FROM `horse`;
If I insert into the view without specifying the columns it actually completes ok. But not when I give the columns as specified in the view.
You're not trying to INSERT into the actual VIEW are you? Insert into the TABLE, and SELECT from the VIEW.
Edit. Forget it; thanks for the correction Strawberry.
Here's a fiddle that illustrates inserting into the view: http://sqlfiddle.com/#!2/280aa6/1/0
I have a table in which there is a column name with SP varchar(10) NOT NULL. I want that column always to be unique so i created unique index on that column . My table schema as follows :
CREATE TABLE IF NOT EXISTS `tblspmaster` (
`CSN` bigint(20) NOT NULL AUTO_INCREMENT,
`SP` varchar(10) NOT NULL,
`FileImportedDate` date NOT NULL,
`AMZFileName` varchar(50) NOT NULL,
`CasperBatch` varchar(50) NOT NULL,
`BatchProcessedDate` date NOT NULL,
`ExpiryDate` date NOT NULL,
`Region` varchar(50) NOT NULL,
`FCCity` varchar(50) NOT NULL,
`VendorID` int(11) NOT NULL,
`LocationID` int(11) NOT NULL,
PRIMARY KEY (`CSN`),
UNIQUE KEY `SP` (`SP`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=10000000000 ;
Now i want that if anybody tries to insert duplicate record then that record should be inserted into a secondary table name tblDuplicate.
I have gone through this question MySQL - ignore insert error: duplicate entry but i am not sure that instead of
INSERT INTO tbl VALUES (1,200) ON DUPLICATE KEY UPDATE value=200;
can i insert duplicate row into another table ?
what changes needed to be done in main table scheme or index column ?
**Note : Data will be inserted by importing excel or csv files and excel files generally contains 500k to 800 k records but there will be only one single column **
I believe you want to use a trigger for this. Here is the MySQL reference chapter on triggers.
Use a before insert trigger. In the trigger, check if the row is a duplicate (maybe count(*) where key column value = value to be inserted). If the row is a duplicate, perform an insert into your secondary table.