mySQL, Error 1215 - foreign key contraint - foreign-keys

My last foreign key (FK_kunde_id) in the bottom I get the following error: 1215 Cannot add foreign key constraint. This is my secound day of SQL programming so I'm trying my best solving it, but gotten completly stuck.
* I've searched through many forums for foreign key problems. But as it's exatcly the same as FK_film_id I would assume this should work as film_id is the primary key in film.film_id
* The speeling is exactly the same.
Anyone know what creates this error from the provided code underneath:
create database utleie
create table utleie.kunder (
kunde_id mediumint not null auto_increment,
fnavn varchar(45) not null,
enavn varchar(45) not null,
mobil int(8) null,
epost varchar(45) null,
gate varchar(45) null,
gatenr varchar(5) null,
postnr int null,
primary key (kunde_id) );
create table utleie.postnummerr (
postnr int not null,
poststed varchar(45) not null,
primary key (postnr) );
create table utleie.film (
film_id int not null auto_increment,
tittle varchar(45) not null,
årstall int(4) null,
regisor varchar(45) null,
genre varchar(3) null,
primary key (film_id) );
create table utleie.genre (
genre_code varchar(3) not null,
genre varchar(45) not null,
primary key (genre_code) );
alter table kunder add constraint FK_postnr foreign key (postnr) references postnummerr(postnr);
alter table film add constraint FK_genre foreign key (genre) references genre(genre_code);
create table utleie.utleie_oversikt (
utleie_id int not null auto_increment,
film_id int not null,
kunde_id int not null,
primary key (utleie_id) );
alter table utleie_oversikt
add constraint FK_film_id
foreign key (film_id) references film(film_id);
alter table utleie_oversikt
add constraint FK_kunde_id
foreign key (kunde_id) references kunder(kunde_id);

Foreign key references must be the exact same type. In this case, you are using mediumint and int, which are not the same size.
You'd actually need to change your create statement
create table utleie.utleie_oversikt (
utleie_id int not null auto_increment,
film_id int not null,
kunde_id mediumint not null,
primary key (utleie_id) );
or, you can change it to an int on your kinder table.

Related

How can I speed up loading from a sqlite database? (sqlite3_step is very slow)

I have maybe about 1,000,000 rows to load into C++ objects (through about 10,000 SELECTS). I've profiled the load, and note that the sqlite3_step statement here is the bottleneck.
sqlite3_stmt *stmt;
std::string symbol = stock->getSymbol();
boost::format sql("SELECT date,open,high,low,close,volume FROM Prices WHERE symbol=\"%s\" ORDER BY date DESC");
sql % symbol;
if (sqlite3_prepare_v2(databaseHandle_, sql.str().c_str(), -1, &stmt, NULL) == SQLITE_OK) {
while (sqlite3_step(stmt) == SQLITE_ROW) {
int date = sqlite3_column_int(stmt, 0);
float open = sqlite3_column_double(stmt, 1);
float high = sqlite3_column_double(stmt, 2);
float low = sqlite3_column_double(stmt, 3);
float close = sqlite3_column_double(stmt, 4);
int volume = sqlite3_column_int(stmt, 5);
Price *price = new Price(new Date(date), open, close, low, high, volume);
stock->add(price);
}
} else {
std::cout << "Error loading stock" << std::endl;
}
I am using the amagalmated sqlite.h/c version 3.15.0. Any ideas how I can speed up performance?
More info:
CREATE TABLE Prices (symbol VARCHAR(10) NOT NULL, date INT(11) NOT NULL, open DECIMAL(6,2) NOT NULL, high DECIMAL(6,2) NOT NULL,low DECIMAL(6,2) NOT NULL, close DECIMAL(6,2) NOT NULL, volume INT(10) NOT NULL, PRIMARY KEY (symbol, date))
CREATE INDEX `PricesIndex` ON `Prices` (`symbol` ,`date` DESC)
EXPLAIN QUERY PLAN SELECT * FROM Prices WHERE symbol="TSLA" ORDER BY date DESC;
returns
SEARCH TABLE PRICES USING INDEX PricesIndex (symbol=?)
Further Note: Such SELECTs as shown above take 2ms in SQLite Browser for Mac Execute SQL.
Your index already speeds up searching for matching rows, and returns them in the correct order so that no separate sorting step is required.
However, the database still has to look up the corresponding table row for each index entry.
You can speed up this particular query by creating a covering index on all the used columns:
CREATE INDEX p ON Prices(symbol, date, open, high, low, close, volume);
But instead of duplicating all data in the index, it would be a better idea to make this table a clustered index:
CREATE TABLE Prices (
symbol VARCHAR(10) NOT NULL,
date INT(11) NOT NULL,
open DECIMAL(6,2) NOT NULL,
high DECIMAL(6,2) NOT NULL,
low DECIMAL(6,2) NOT NULL,
close DECIMAL(6,2) NOT NULL,
volume INT(10) NOT NULL,
PRIMARY KEY (symbol, date)
) WITHOUT ROWID;

Error 1452 Child Error. Stumped Please Help, Exam on this today

Here is my forward engineering script after creating the ER diagram:
SET #OLD_UNIQUE_CHECKS=##UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET #OLD_FOREIGN_KEY_CHECKS=##FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET #OLD_SQL_MODE=##SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';
DROP SCHEMA IF EXISTS `jocubooks` ;
CREATE SCHEMA IF NOT EXISTS `jocubooks` DEFAULT CHARACTER SET utf8 ;
USE `jocubooks` ;
DROP TABLE IF EXISTS `book` ;
CREATE TABLE IF NOT EXISTS `book` (
`ISBN` BIGINT(13) UNSIGNED NOT NULL,
`title` VARCHAR(100) NOT NULL,
`edition` VARCHAR(5) NULL,
`pubYear` YEAR NOT NULL,
PRIMARY KEY (`ISBN`),
UNIQUE INDEX `ISBN_UNIQUE` (`ISBN` ASC))
ENGINE = InnoDB;
DROP TABLE IF EXISTS `borrower` ;
CREATE TABLE IF NOT EXISTS `borrower` (
`borrowerId` INT NOT NULL AUTO_INCREMENT,
`firstName` VARCHAR(50) NULL,
`lastName` VARCHAR(50) NOT NULL,
PRIMARY KEY (`borrowerId`),
UNIQUE INDEX `borrowerId_UNIQUE` (`borrowerId` ASC))
ENGINE = InnoDB;
DROP TABLE IF EXISTS `bookStatus` ;
CREATE TABLE IF NOT EXISTS `bookStatus` (
`statusID` INT(2) NOT NULL,
`status` VARCHAR(45) NOT NULL,
PRIMARY KEY (`statusID`))
ENGINE = InnoDB;
DROP TABLE IF EXISTS `bookCopy` ;
CREATE TABLE IF NOT EXISTS `bookCopy` (
`bookId` INT NOT NULL AUTO_INCREMENT,
`loanPeriod` INT(3) NOT NULL DEFAULT 30 COMMENT 'in days',
`statusId` INT(2) NOT NULL,
`ISBN` BIGINT(13) UNSIGNED NOT NULL,
PRIMARY KEY (`bookId`),
INDEX `fk_bookCopy_bookStatus_idx` (`statusId` ASC),
INDEX `fk_bookCopy_book1_idx` (`ISBN` ASC),
CONSTRAINT `statusID`
FOREIGN KEY (`statusId`)
REFERENCES `bookStatus` (`statusID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_bookCopy_book1`
FOREIGN KEY (`ISBN`)
REFERENCES `book` (`ISBN`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
DROP TABLE IF EXISTS `bookLoan` ;
CREATE TABLE IF NOT EXISTS `bookLoan` (
`loanID` INT NOT NULL AUTO_INCREMENT,
`loanDate` DATE NOT NULL,
`returnDate` DATE NULL,
`borrowerId` INT NOT NULL,
`bookId` INT NOT NULL,
PRIMARY KEY (`loanID`),
INDEX `fk_bookLoan_borrower1_idx` (`borrowerId` ASC),
INDEX `fk_bookLoan_bookCopy1_idx` (`bookId` ASC),
CONSTRAINT `borrowerId`
FOREIGN KEY (`borrowerId`)
REFERENCES `borrower` (`borrowerId`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_bookLoan_bookCopy1`
FOREIGN KEY (`bookId`)
REFERENCES `bookCopy` (`bookId`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
SET SQL_MODE=#OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=#OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=#OLD_UNIQUE_CHECKS;
I then try to create triggers to help update some of the tables:
use jocubooks;
create trigger trigChangeStatus after insert on bookloan for each row
update bookcopy set statusID = 1 where bookId = NEW.bookId;
create trigger trigChangeStatusRet after update on bookloan for each row
update bookcopy set statusID = 0 where bookId = NEW.bookId;
I run into my child row error here, I have tried using 16 in the first Null value, thought it might have been auto increment:
Error Code: 1452. Cannot add or update a child row: a foreign key constraint fails (jocubooks.bookloan, CONSTRAINT borrowerId FOREIGN KEY (borrowerId) REFERENCES borrower (borrowerId) ON DELETE NO ACTION ON UPDATE NO ACTION)
insert into bookloan values (NULL, DATE(NOW()), NULL, 5, 8);
update bookloan set returnDate = DATE(NOW()) where loanId = 3;
SELECT * FROM bookcopy;

How to Compare my sql columns dynamically

I am not able to get idea about the following requirement. The example table follows.
CREATE TABLE `test` (
`Id` INT NOT NULL,
`Name` VARCHAR(45) NULL,
`did_fk` INT NULL,
`adid_fk` INT NULL,
PRIMARY KEY (`Id`));
INSERT INTO test (id,name,did_fk,adid_fk)
VALUES
(1,'Rajesh',1,1),
(2,'Neeli',2,2),
(3,'Satish',3,3),
(4,'Ganesh',4,5),
(5,'Murali',9,10);
Here I need to compare the "id" with _fk columns i.e. did_fk & adid_fk. The "id" should be equal to did_fk & as well as adid_fk. If any of them is not true, then I should get that row.Here I need to get the rows 4 & 5.Since "_fk" columns are not equal to "id" value.Problem is "_fk" columns are not fixed. But "id" name is fixed.
SELECT * FROM `test` WHERE `Id` != `did_fk` OR `Id` != `adid_fk`
If your dynamic columns ends with _fk or some another suffix you can try to create SP like following
CREATE DEFINER=`root`#`localhost` PROCEDURE `GetNonEqualFkValues`(IN tableName varchar(255))
BEGIN
DECLARE c_name VARCHAR(255);
DECLARE done INT DEFAULT FALSE;
DECLARE curs CURSOR FOR select column_name from information_schema.columns where column_name like '%_fk';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN curs;
SET #q = concat("SELECT * FROM ", tableName, " WHERE 1!=1 ");
get_col: LOOP
FETCH curs INTO c_name;
IF done THEN
LEAVE get_col;
END IF;
SET #q = CONCAT(#q, " OR ", c_name," != id");
END LOOP get_col;
PREPARE stmt1 FROM #q;
EXECUTE stmt1;
END
And then invoke for concrete table like
call GetNonEqualFkValues('test')
The code isn't perfect, but it works for me and I think idea should be clear.

How can I re-use a MySQL++ query object to call multiple stored procedures?

#include <iostream>
#include <mysql++.h>
using namespace std;
int main() {
// Get database access parameters from command line
const char* db = "enet", *server = "192.168.1.108", *user = "root", *pass =
"123456";
// Connect to the sample database.
mysqlpp::Connection conn(false);
conn.set_option(new mysqlpp::MultiStatementsOption(true));
if (conn.connect(db, server, user, pass)) {
mysqlpp::Query query = conn.query();
query << "call CreateTable('test1', 'generic', 0, 1, 2, 3,4,5,6,7,8,9,10,NOW());";
query.execute();
query.reset();
query << "call CreateTable('test2', 'generic', 0, 1, 2, 3,4,5,6,7,8,9,10,NOW());";
query.execute();
query.reset();
return 0;
} else {
cerr << "DB connection failed: " << conn.error() << endl;
return 1;
}
return 0;
}
I want to use mysql++ query to execute procedure "CreateTable" many times, and i reset the query at last, but no matter how, just the first query works, the last does not, my problem is that:
how to make all of queries work?
-- create table --
delimiter $$
drop procedure if exists CreateTable $$
create procedure CreateTable(
IN tableName VARCHAR(20),
IN dbName VARCHAR(20),
IN INT_RegDevID INTEGER,
IN Dec_Long DECIMAL(24,16),
IN Dec_Lat DECIMAL(24,16),
IN Dec_Height DECIMAL(10,6),
IN Dec_Direction DECIMAL(10,6),
IN AverageSpeed DECIMAL(10,6),
IN Dec_Base VARCHAR(10),
IN MCC INTEGER,
IN MNC INTEGER,
IN LAC INTEGER,
IN CI INTEGER,
IN Dec_LocaDate TIMESTAMP)
-- -------------------------------------------------------------------------------
-- -------------------------------------------------------------------------------
begin
-- the test variable
-- Warning: the encoding can result many problem!!!
declare varTableName VARCHAR(32) default NULL;
set #varTableName = NULL;
set #table_prefix = "posinfo_";
set #table_params = "(
`Int_LocaID` int(11) NOT NULL auto_increment,
`INT_RegDevID` int(11) NOT NULL default '0',
`Dec_Long` decimal(24,16) NOT NULL default '0.0000000000000000',
`Dec_Lat` decimal(24,16) NOT NULL default '0.0000000000000000',
`Dec_Height` decimal(10,6) NOT NULL default '0.000000',
`Dec_Direction` decimal(10,6) NOT NULL default '0.000000',
`Dec_ MaxSpeed` decimal(10,6) NOT NULL default '0.000000',
`Dec_ MinSpeed` decimal(10,6) NOT NULL default '0.000000',
`AverageSpeed` decimal(10,6) NOT NULL default '0.000000',
`Var_PosInfo` varchar(50) character set latin1 NOT NULL default '',
`Var_Remark` varchar(200) character set latin1 NOT NULL default '',
`Date_LocaDate` timestamp NOT NULL default CURRENT_TIMESTAMP,
`Dec_Base` varchar(10) character set latin1 NOT NULL,
`MCC` int(11) NOT NULL COMMENT '',
`MNC` int(11) NOT NULL COMMENT '',
`LAC` int(11) NOT NULL COMMENT '',
`CI` int(11) NOT NULL COMMENT '',
PRIMARY KEY (`Int_LocaID`)
) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=gbk;";
set #varCreate = CONCAT("create table ", dbName,".",#table_prefix, tableName, #table_params);
-- the insert operation
set #insertOperation = CONCAT("insert into ", dbName,".",#table_prefix, tableName,
"(INT_RegDevID,Dec_Long,Dec_Lat,Dec_Height,Dec_Direction,AverageSpeed,
Dec_Base,MCC,MNC,LAC,CI,Date_LocaDate) values(",INT_RegDevID,",",Dec_Long,
",",Dec_Lat,",",Dec_Height,",",Dec_Direction,",",AverageSpeed,",",Dec_Base,
",",MCC,",",MNC,",",LAC,",",CI,",NOW())");
-- find the target table
-- Look care about the "' '" !
set #getTargetTable = CONCAT("select TABLE_NAME into #varTableName from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='",
dbName, "' and TABLE_NAME='", #table_prefix, tableName,"'");
-- -------------------------------------------------------------------------------
-- -------------------------------------------------------------------------------
PREPARE getTargetTable from #getTargetTable;
execute getTargetTable;
select #varTableName;
set varTableName = #varTableName;
if varTableName is NULL then
-- create new table
PREPARE newTable
from #varCreate;
execute newTable;
-- do insert operation
PREPARE insertOperation
from #insertOperation;
execute insertOperation;
else
-- do insert operation
PREPARE insertOperation
from #insertOperation;
execute insertOperation;
end if;
end $$
delimiter ;
above, are the procedure.
There are several bugs here:
You've turned off exceptions (conn(false)) but you're also not checking return values for error codes. Your second execute() call is failing, but without asking the Query object why, you're running blind.
Instead of adding error checking to all MySQL++ calls, though, I think it's cleaner to allow MySQL++ to throw exceptions (conn()) and wrap the whole thing in a try block.
You don't need the MultiStatementsOption to do what you're asking the way you currently show. You have two separate statements here, not one compound statement. That in combination with the semicolons may be confusing MySQL, which is why the second call fails.
The mysql command line tool demands semicolons to terminate SQL statements, but when using a database API like MySQL++, they're only necessary to separate multiple statements.
You can either combine both CREATE statements into a single string (and one execute()) or you can drop the semicolons and the MultiStatementsOption.
The reset() calls between queries haven't been necessary since MySQL++ 2.x. The only reason the method is still available is that it's necessary if you want to reuse a Query object that had been used for template queries; they're the only type that still don't auto-reset, for fairly obvious reasons.

"delete from table" doesn't delete table?

I create "database.db" and everything goes ok but why wouldn't it delete the table at the end? Everytime i run it, i get "table already exist" error message on creating the table.
int main()
{
sqlite3 *db; //Database Handle
char *zErr;
int rc;
char *sql;
rc = sqlite3_open("database.db", &db);
if(rc)
{
cout << "Can't open database: " << sqlite3_errmsg(db) << endl;;
sqlite3_close(db);
exit(1);
}
sql = "create table test(PID int primary key, Name text)"; //sql query
rc = sqlite3_exec(db, sql, NULL, NULL, &zErr); //execute sql statement
if(rc != SQLITE_OK)
{
if (zErr != NULL)
{
cout << "SQL error: " << zErr << endl;
sqlite3_free(zErr);
}
}
else
{
sql = "insert into test values (1,'John')";
rc = sqlite3_exec(db, sql, NULL, NULL, &zErr);
sql = "insert into test values (2,'Smith')";
rc = sqlite3_exec(db, sql, NULL, NULL, &zErr);
}
//delete the table on exit.
rc = sqlite3_exec(db, "delete from test", NULL, NULL, &zErr);
sqlite3_close(db);
return 0;
}
Also, can the primary keys be auto-generated following the last greater key existing in database?
You need to use drop table. delete deletes rows in the table.
rc = sqlite3_exec(db, "drop table test", NULL, NULL, &zErr);
SQLite will auto-increment an integer field declared as the primary key. See here.
You use a DELETE command to delete rows of a table.
You use a DROP command to drop a whole table or other DB item.
To create the table you can also use CREATE TABLE IF NOT EXISTS if you aren't sure if it exists.
To get your auto generated row ids use: id INTEGER PRIMARY KEY in your CREATE TABLE command.
Use DROP TABLE.
From SQLite docs:
The usual algorithm is to give the newly created row a ROWID that is one larger than the largest ROWID in the table prior to the insert.
The DML "delete from test" does delete all the rows from the table test. If you wish to drop the table, try "delete table test" or "drop table" instead.