すべてのテーブルをデータで埋めるために、多くの選択/更新を含む非常に大きな関数を作成しました。テーブルに入力しようとしましたが、関数を呼び出すときに #1452 エラーを受け取りました
SELECT insert_tune("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S")
エラーがどのように見えるか
#1452 - Cannot add or update a child row: a foreign key constraint fails (`rbase`.`tunes`, CONSTRAINT `tunes_ibfk_1` FOREIGN KEY (`riddim_fk`) REFERENCES `riddims` (`riddim_id`) ON DELETE SET NULL ON UPDATE CASCADE)
データベースのレイアウトは次のようになります。
CREATE TABLE artists (
artist_id INT AUTO_INCREMENT PRIMARY KEY,
artist_name varchar(100) UNIQUE,
artist_aka varchar(255) UNIQUE
) ENGINE = 'InnoDB';
CREATE TABLE labels (
label_id SMALLINT AUTO_INCREMENT PRIMARY KEY,
label_name varchar(100) UNIQUE,
label_aka varchar(255) UNIQUE
) ENGINE = 'InnoDB';
CREATE TABLE producers (
producer_id SMALLINT AUTO_INCREMENT PRIMARY KEY,
producer_forename varchar(100),
producer_nickname varchar(100) UNIQUE,
producer_lastname varchar(100)
) ENGINE = 'InnoDB';
CREATE TABLE years (
year_id TINYINT AUTO_INCREMENT PRIMARY KEY,
year_value varchar(4) UNIQUE
) ENGINE = 'InnoDB';
CREATE TABLE genres (
genre_id TINYINT AUTO_INCREMENT PRIMARY KEY,
genre_name varchar(10) UNIQUE
) ENGINE = 'InnoDB';
CREATE TABLE flags (
flag_id TINYINT AUTO_INCREMENT PRIMARY KEY,
flag_name varchar(12) UNIQUE
) ENGINE = 'InnoDB';
CREATE TABLE tags (
tag_id SMALLINT AUTO_INCREMENT PRIMARY KEY,
tag_name varchar(16) UNIQUE
) ENGINE = 'InnoDB';
CREATE TABLE sources (
source_id TINYINT AUTO_INCREMENT PRIMARY KEY,
source_name varchar(30) UNIQUE
) ENGINE = 'InnoDB';
CREATE TABLE riddims (
riddim_id INT AUTO_INCREMENT PRIMARY KEY,
riddim_name varchar(40) UNIQUE,
riddim_aka varchar(255) UNIQUE,
genre_fk TINYINT,
youtube varchar(11) UNIQUE,
image varchar(11) UNIQUE,
FOREIGN KEY (genre_fk) REFERENCES genres(genre_id) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE = 'InnoDB';
CREATE TABLE tunes (
tune_id INT AUTO_INCREMENT PRIMARY KEY,
riddim_fk INT DEFAULT NULL,
artist_fk INT DEFAULT NULL,
tune_name varchar(60) DEFAULT NULL,
tune_aka varchar(255) DEFAULT NULL,
label_fk SMALLINT DEFAULT NULL,
producer_fk SMALLINT DEFAULT NULL,
year_fk TINYINT DEFAULT NULL,
lyrics TEXT DEFAULT NULL,
flag_fk TINYINT,
tag_fk SMALLINT,
source_fk TINYINT,
last_modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (riddim_fk) REFERENCES riddims(riddim_id) ON DELETE SET NULL ON UPDATE CASCADE,
FOREIGN KEY (artist_fk) REFERENCES artists(artist_id) ON DELETE SET NULL ON UPDATE CASCADE,
FOREIGN KEY (producer_fk) REFERENCES producers(producer_id) ON DELETE SET NULL ON UPDATE CASCADE,
FOREIGN KEY (year_fk) REFERENCES years(year_id) ON DELETE SET NULL ON UPDATE CASCADE,
FOREIGN KEY (flag_fk) REFERENCES flags(flag_id) ON DELETE SET NULL ON UPDATE CASCADE,
FOREIGN KEY (tag_fk) REFERENCES tags(tag_id) ON DELETE SET NULL ON UPDATE CASCADE,
FOREIGN KEY (source_fk) REFERENCES sources(source_id) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE = 'InnoDB';
そして、テーブルを埋めるために使用している関数は次のようになります
CREATE FUNCTION insert_tune(
riddim varchar(40),
riddim_a varchar(255),
yt varchar(11),
img varchar(11),
artist varchar(100),
artist_a varchar(255),
tune varchar(60),
tune_a varchar(255),
genre varchar(10),
label varchar(100),
label_a varchar(255),
producer_fn varchar(100),
producer_nn varchar(100),
producer_ln varchar(100),
year varchar(4),
lrx TEXT,
flag varchar(12),
tag varchar(16),
source varchar(30)
)
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE cRiddim, cArtist, cLabel, cProducer, cRiddimArtist, cRiddimTune, cArtistTune, cRiddimArtistTune INT;
/* Testing if the tables already contain certain records/entries */
SELECT COUNT(*) FROM riddims WHERE riddim_name = riddim INTO cRiddim;
SELECT COUNT(*) FROM artists WHERE artist_name = artist INTO cArtist;
SELECT COUNT(*) FROM labels WHERE label_name = label INTO cLabel;
SELECT COUNT(*) FROM producers WHERE producer_nickname = producer_nn INTO cProducer;
SELECT COUNT(*) FROM tunes WHERE artist_fk = (SELECT artist_id FROM artists WHERE artist_name = artist) AND tune_name = tune AND ISNULL(riddim_fk) INTO cArtistTune;
SELECT COUNT(*) FROM tunes WHERE riddim_fk = (SELECT riddim_id FROM riddims WHERE riddim_name = riddim) AND tune_name = tune AND ISNULL(artist_fk) INTO cRiddimTune;
SELECT COUNT(*) FROM tunes WHERE riddim_fk = (SELECT riddim_id FROM riddims WHERE riddim_name = riddim) AND artist_fk = (SELECT artist_id FROM artists WHERE artist_name = artist) AND ISNULL(tune_name) INTO cRiddimArtist;
SELECT COUNT(*) FROM tunes WHERE riddim_fk = (SELECT riddim_id FROM riddims WHERE riddim_name = riddim) AND artist_fk = (SELECT artist_id FROM artists WHERE artist_name = artist) AND tune_name = tune INTO cRiddimArtistTune;
/*
##########
# GENRES #
##########
*/
IF genre NOT IN ('') AND NOT ISNULL(genre) THEN
INSERT IGNORE INTO genres (genre_name) VALUES (genre);
END IF;
/*
###########
# RIDDIMS #
###########
*/
IF cRiddim < 1 AND riddim NOT IN ('') AND NOT ISNULL(riddim) THEN
INSERT INTO riddims (
riddim_name,
riddim_aka,
youtube,
image
)
VALUES (
riddim,
IF(riddim_a NOT IN (''), riddim_a, NULL),
IF(yt NOT IN (''), yt, NULL),
IF(img NOT IN (''), img, NULL)
);
ELSE
UPDATE riddims SET
riddim_aka = IFNULL(riddim_aka, IF(NOT ISNULL(riddim_a) AND riddim_a NOT IN (''), riddim_a, NULL)),
genre_fk = IFNULL(genre_fk, IF(NOT ISNULL(genre) AND genre NOT IN (''), (SELECT genre_id FROM genres WHERE genre_name = genre), NULL)),
youtube = IFNULL(youtube, IF(NOT ISNULL(youtube) AND youtube NOT IN (''), youtube, NULL)),
image = IFNULL(img, IF(NOT ISNULL(img) AND img NOT IN (''), img, NULL))
WHERE
riddim_name = riddim;
END IF;
/*
###########
# ARTISTS #
###########
*/
IF cArtist < 1 AND artist NOT IN ('') AND NOT ISNULL(artist) THEN
INSERT INTO artists (
artist_name,
artist_aka
)
VALUES (
artist,
IF(artist_a NOT IN (''), artist_a, NULL)
);
ELSE
UPDATE artists SET
artist_aka = IFNULL(artist_aka, IF(NOT ISNULL(artist_a) AND artist_a NOT IN (''), artist_a, NULL))
WHERE
artist_name = artist;
END IF;
/*
##########
# LABELS #
##########
*/
IF cLabel < 1 AND label NOT IN ('') AND NOT ISNULL(label) THEN
INSERT INTO labels (
label_name,
label_aka
)
VALUES (
label,
IF(label_a NOT IN (''), label_a, NULL)
);
ELSE
UPDATE labels SET
label_aka = IFNULL(label_aka, IF(NOT ISNULL(label_a) AND label_a NOT IN (''), label_a, NULL))
WHERE label_name = label;
END IF;
/*
#############
# PRODUCERS #
#############
*/
IF cProducer < 1 AND producer_nn NOT IN ('') AND NOT ISNULL(producer_nn) THEN
INSERT INTO producers (
producer_forename,
producer_nickname,
producer_lastname
)
VALUES (
IF(producer_fn NOT IN (''), producer_fn, NULL),
producer_nn,
IF(producer_ln NOT IN (''), producer_ln, NULL)
);
ELSE
UPDATE producers SET
producer_forename = IFNULL(producer_forename, IF(NOT ISNULL(producer_fn) AND producer_fn NOT IN (''), producer_fn, NULL)),
producer_lastname = IFNULL(producer_lastname, IF(NOT ISNULL(producer_ln) AND producer_ln NOT IN (''), producer_ln, NULL))
WHERE
producer_nickname = producer_nn;
END IF;
/*
#########
# YEARS #
#########
*/
IF year NOT IN ('') AND NOT ISNULL(year) THEN
INSERT IGNORE INTO years (year_value) VALUES (year);
END IF;
/*
#########
# FLAGS #
#########
*/
IF flag NOT IN ('') AND NOT ISNULL(flag) THEN
INSERT IGNORE INTO flags (flag_name) VALUES (flag);
END IF;
/*
########
# TAGS #
########
*/
IF tag NOT IN ('') AND NOT ISNULL(tag) THEN
INSERT IGNORE INTO tags (tag_name) VALUES (tag);
END IF;
/*
###########
# SOURCES #
###########
*/
IF source NOT IN ('') AND NOT ISNULL(source) THEN
INSERT IGNORE INTO sources (source_name) VALUES (source);
END IF;
/*
#########
# TUNES #
#########
*/
IF cArtistTune > 0 THEN
UPDATE tunes SET
riddim_fk = IFNULL(riddim_fk, IF(NOT ISNULL(riddim) AND riddim NOT IN (''), (SELECT riddim_id FROM riddims WHERE riddim_name = riddim), NULL)),
tune_aka = IFNULL(tune_aka, IF(NOT ISNULL(tune_a) AND tune_a NOT IN (''), tune_a, NULL)),
label_fk = IFNULL(label_fk, IF(NOT ISNULL(label) AND label NOT IN (''), (SELECT label_id FROM labels WHERE label_name = label), NULL)),
producer_fk = IFNULL(producer_fk, IF(NOT ISNULL(producer_nn) AND producer_nn NOT IN (''), (SELECT producer_id FROM producers WHERE producer_nickname = producer_nn), NULL)),
year_fk = IFNULL(year_fk, IF(NOT ISNULL(year) AND year NOT IN (''), (SELECT year_id FROM years WHERE year_value = year), NULL)),
lyrics = IFNULL(lyrics, IF(NOT ISNULL(lrx) AND lrx NOT IN (''), lrx, NULL)),
flag_fk = IFNULL(flag_fk, IF(NOT ISNULL(flag) AND flag NOT IN (''), (SELECT flag_id FROM flags WHERE flag_name = flag), NULL)),
tag_fk = IFNULL(tag_fk, IF(NOT ISNULL(tag) AND tag NOT IN (''), (SELECT tag_id FROM tags WHERE tag_name = tag), NULL)),
source_fk = IFNULL(source_fk, IF(NOT ISNULL(source) AND source NOT IN (''), (SELECT source_id FROM sources WHERE source_name = source), NULL))
WHERE
tune_name = tune AND artist_fk = (SELECT artist_id FROM artists WHERE artist_name = artist);
ELSEIF cRiddimTune > 0 THEN
UPDATE tunes SET
artist_fk = IFNULL(artist_fk, IF(NOT ISNULL(artist) AND artist NOT IN (''), (SELECT artist_id FROM artists WHERE artist_name = artist), NULL)),
tune_aka = IFNULL(tune_aka, IF(NOT ISNULL(tune_a) AND tune_a NOT IN (''), tune_a, NULL)),
label_fk = IFNULL(label_fk, IF(NOT ISNULL(label) AND label NOT IN (''), (SELECT label_id FROM labels WHERE label_name = label), NULL)),
producer_fk = IFNULL(producer_fk, IF(NOT ISNULL(producer_nn) AND producer_nn NOT IN (''), (SELECT producer_id FROM producers WHERE producer_nickname = producer_nn), NULL)),
year_fk = IFNULL(year_fk, IF(NOT ISNULL(year) AND year NOT IN (''), (SELECT year_id FROM years WHERE year_value = year), NULL)),
lyrics = IFNULL(lyrics, IF(NOT ISNULL(lrx) AND lrx NOT IN (''), lrx, NULL)),
flag_fk = IFNULL(flag_fk, IF(NOT ISNULL(flag) AND flag NOT IN (''), (SELECT flag_id FROM flags WHERE flag_name = flag), NULL)),
tag_fk = IFNULL(tag_fk, IF(NOT ISNULL(tag) AND tag NOT IN (''), (SELECT tag_id FROM tags WHERE tag_name = tag), NULL)),
source_fk = IFNULL(source_fk, IF(NOT ISNULL(source) AND source NOT IN (''), (SELECT source_id FROM sources WHERE source_name = source), NULL))
WHERE
tune_name = tune AND riddim_fk = (SELECT riddim_id FROM riddims WHERE riddim_name = riddim);
ELSEIF cRiddimArtist > 0 THEN
UPDATE tunes SET
tune_name = IFNULL(tune_name, IF(NOT ISNULL(tune) AND tune NOT IN (''), tune, NULL)),
tune_aka = IFNULL(tune_aka, IF(NOT ISNULL(tune_a) AND tune_a NOT IN (''), tune_a, NULL)),
label_fk = IFNULL(label_fk, IF(NOT ISNULL(label) AND label NOT IN (''), (SELECT label_id FROM labels WHERE label_name = label), NULL)),
producer_fk = IFNULL(producer_fk, IF(NOT ISNULL(producer_nn) AND producer_nn NOT IN (''), (SELECT producer_id FROM producers WHERE producer_nickname = producer_nn), NULL)),
year_fk = IFNULL(year_fk, IF(NOT ISNULL(year) AND year NOT IN (''), (SELECT year_id FROM years WHERE year_value = year), NULL)),
lyrics = IFNULL(lyrics, IF(NOT ISNULL(lrx) AND lrx NOT IN (''), lrx, NULL)),
flag_fk = IFNULL(flag_fk, IF(NOT ISNULL(flag) AND flag NOT IN (''), (SELECT flag_id FROM flags WHERE flag_name = flag), NULL)),
tag_fk = IFNULL(tag_fk, IF(NOT ISNULL(tag) AND tag NOT IN (''), (SELECT tag_id FROM tags WHERE tag_name = tag), NULL)),
source_fk = IFNULL(source_fk, IF(NOT ISNULL(source) AND source NOT IN (''), (SELECT source_id FROM sources WHERE source_name = source), NULL))
WHERE
artist_fk = (SELECT artist_id FROM artists WHERE artist_name = artist) AND riddim_fk = (SELECT riddim_id FROM riddims WHERE riddim_name = riddim);
ELSEIF cRiddimArtistTune < 1 THEN
IF tune NOT IN ('') AND NOT ISNULL(tune) AND artist NOT IN ('') AND NOT ISNULL(artist) THEN
INSERT INTO tunes (
riddim_fk,
artist_fk,
tune_name,
tune_aka,
label_fk,
producer_fk,
year_fk,
lyrics,
flag_fk,
tag_fk,
source_fk
)
VALUES (
IF(NOT ISNULL(riddim) AND riddim NOT IN (''), riddim, NULL),
(SELECT artist_id FROM artists WHERE artist_name = artist),
tune,
IF(NOT ISNULL(tune_a) AND tune_a NOT IN (''), tune_a, NULL),
IF(NOT ISNULL(label) AND label NOT IN (''), (SELECT label_id FROM labels WHERE label_name = label), NULL),
IF(NOT ISNULL(producer_nn) AND producer_nn NOT IN (''), (SELECT producer_id FROM producers WHERE producer_nickname = producer_nn), NULL),
IF(NOT ISNULL(year) AND year NOT IN (''), (SELECT year_id FROM years WHERE year_value = year), NULL),
IF(NOT ISNULL(lrx) AND lrx NOT IN (''), lrx, NULL),
IF(NOT ISNULL(flag) AND flag NOT IN (''), (SELECT flag_id FROM flags WHERE flag_name = flag), NULL),
IF(NOT ISNULL(tag) AND tag NOT IN (''), (SELECT tag_id FROM tags WHERE tag_name = tag), NULL),
IF(NOT ISNULL(source) AND source NOT IN (''), (SELECT source_id FROM sources WHERE source_name = source), NULL)
);
END IF;
IF tune NOT IN ('') AND NOT ISNULL(tune) AND riddim NOT IN ('') AND NOT ISNULL(riddim) THEN
INSERT INTO tunes (
riddim_fk,
artist_fk,
tune_name,
tune_aka,
label_fk,
producer_fk,
year_fk,
lyrics,
flag_fk,
tag_fk,
source_fk
)
VALUES (
(SELECT riddim_id FROM riddims WHERE riddim_name = riddim),
IF(NOT ISNULL(artist) AND artist NOT IN (''), (SELECT artist_id FROM artists WHERE artist_name = artist), NULL),
tune,
IF(NOT ISNULL(tune_a) AND tune_a NOT IN (''), tune_a, NULL),
IF(NOT ISNULL(label) AND label NOT IN (''), (SELECT label_id FROM labels WHERE label_name = label), NULL),
IF(NOT ISNULL(producer_nn) AND producer_nn NOT IN (''), (SELECT producer_id FROM producers WHERE producer_nickname = producer_nn), NULL),
IF(NOT ISNULL(year) AND year NOT IN (''), (SELECT year_id FROM years WHERE year_value = year), NULL),
IF(NOT ISNULL(lrx) AND lrx NOT IN (''), lrx, NULL),
IF(NOT ISNULL(flag) AND flag NOT IN (''), (SELECT flag_id FROM flags WHERE flag_name = flag), NULL),
IF(NOT ISNULL(tag) AND tag NOT IN (''), (SELECT tag_id FROM tags WHERE tag_name = tag), NULL),
IF(NOT ISNULL(source) AND source NOT IN (''), (SELECT source_id FROM sources WHERE source_name = source), NULL)
);
END IF;
IF artist NOT IN ('') AND NOT ISNULL(artist) AND riddim NOT IN ('') AND NOT ISNULL(riddim) THEN
INSERT INTO tunes (
riddim_fk,
artist_fk,
tune_name,
tune_aka,
label_fk,
producer_fk,
year_fk,
lyrics,
flag_fk,
tag_fk,
source_fk
)
VALUES (
(SELECT riddim_id FROM riddims WHERE riddim_name = riddim),
(SELECT artist_id FROM artists WHERE artist_name = artist),
IF(NOT ISNULL(tune) AND tune NOT IN (''), tune, NULL),
IF(NOT ISNULL(tune_a) AND tune_a NOT IN (''), tune_a, NULL),
IF(NOT ISNULL(label) AND label NOT IN (''), (SELECT label_id FROM labels WHERE label_name = label), NULL),
IF(NOT ISNULL(producer_nn) AND producer_nn NOT IN (''), (SELECT producer_id FROM producers WHERE producer_nickname = producer_nn), NULL),
IF(NOT ISNULL(year) AND year NOT IN (''), (SELECT year_id FROM years WHERE year_value = year), NULL),
IF(NOT ISNULL(lrx) AND lrx NOT IN (''), lrx, NULL),
IF(NOT ISNULL(flag) AND flag NOT IN (''), (SELECT flag_id FROM flags WHERE flag_name = flag), NULL),
IF(NOT ISNULL(tag) AND tag NOT IN (''), (SELECT tag_id FROM tags WHERE tag_name = tag), NULL),
IF(NOT ISNULL(source) AND source NOT IN (''), (SELECT source_id FROM sources WHERE source_name = source), NULL)
);
END IF;
ELSEIF cRiddimArtistTune > 0 THEN
UPDATE tunes SET
tune_aka = IFNULL(tune_aka, IF(NOT ISNULL(tune_a) AND tune_a NOT IN (''), tune_a, NULL)),
label_fk = IFNULL(label_fk, IF(NOT ISNULL(label) AND label NOT IN (''), (SELECT label_id FROM labels WHERE label_name = label), NULL)),
producer_fk = IFNULL(producer_fk, IF(NOT ISNULL(producer_nn) AND producer_nn NOT IN (''), (SELECT producer_id FROM producers WHERE producer_nickname = producer_nn), NULL)),
year_fk = IFNULL(year_fk, IF(NOT ISNULL(year) AND year NOT IN (''), (SELECT year_id FROM years WHERE year_value = year), NULL)),
lyrics = IFNULL(lyrics, IF(NOT ISNULL(lrx) AND lrx NOT IN (''), lrx, NULL)),
flag_fk = IFNULL(flag_fk, IF(NOT ISNULL(flag) AND flag NOT IN (''), (SELECT flag_id FROM flags WHERE flag_name = flag), NULL)),
tag_fk = IFNULL(tag_fk, IF(NOT ISNULL(tag) AND tag NOT IN (''), (SELECT tag_id FROM tags WHERE tag_name = tag), NULL)),
source_fk = IFNULL(source_fk, IF(NOT ISNULL(source) AND source NOT IN (''), (SELECT source_id FROM sources WHERE source_name = source), NULL))
WHERE
artist_fk = (SELECT artist_id FROM artists WHERE artist_name = artist) AND riddim_fk = (SELECT riddim_id FROM riddims WHERE riddim_name = riddim) AND tune_name = tune;
END IF;
RETURN 0; /** add more/better returns & values to determine what data was inserted **/
END
そこにいるすべてのデータベースウィザードに、ご容赦ください。私はこのようなことに慣れていないので、機能が少し肥大化している可能性があります。
とにかく、いくつかの調査によると、親テーブルに存在しない行を指す外部キー列がある場合に上記のエラーが発生することがわかりました。奇妙な点は、テーブルがすべて空であることです。外部キー列が誤って独自のテーブルを指している場合にも発生する可能性がありますが、ここでもそうではありません(私が読んだ同様の問題を理解している限り)。
関数のスコープ内で (デバッグ目的で) SELECT CONCAT() を使用することは許可されていないため、エラーが発生する理由や場所はわかりませんが、 tunes.riddim_fk にデータを挿入する関数が処理されます。
また、riddim_id、genre_id など (親テーブルの ID) を PRIMARY KEY と AUTO_INCREMENT に設定すると、「NOT NULL」を指定していないにもかかわらず、phpMyAdmin はこれらの列に対して「NULL: no」と表示するようになりました。キーの1つが自動的に列をNOT NULLに設定していると思います。
IEにNULLを追加しているため、エラーが発生している可能性があります。関数パラメーター "riddim" が "" (空の文字列) に設定されている場合、riddim_fk 列は? 実際の関数テスト呼び出し (上記のように) とは異なり、空の文字列をパラメーターとして関数に渡さなかったと思います。
助けていただければ幸いです。
編集:タイプミス。