I am looking at using a SQL software to store and query objects with a loose schema.
We know that an object corresponds to a row of an SQL table, and it's attributes correspond to columns. By 'loose schema', I mean that an object can have attributes that are not hardwired to the table's (rather tables') structure. An arbitrary (attribute,value) can be attached to an object.
Let me illustrate with a specific example:
For the given objects:
<subject>
name:data structures
tag:CS
description:easy
desired_seniority:5.0
<subject>
name:microprocessors
tag:CS,electronics <multi-valued
description:easy
desired_seniority:5.5 <numeric
and
<teacher>
name:John Doe
tag:electronics
seniority:5.8
The query will be
For each teacher,
return all subjects whose tags match and
whose desired seniority is less than or equal to the teacher's
The teacher 'John Doe' will be matched with subject 'microprocessors' because they share the tag 'electronics' and his seniority 5.8 is greater than the subject's desired seniority 5.5
Note that I have used numeric (queries do comparison) and multi-valued (queries do an 'is in' match) string in the strings.
What exactly: I am looking for the right data model and corresponding queries that lets me simulate a loose schema on a SQL software.
I accept these constraints:
teacher and subject may be described by distinct tables
there will be one to one correspondence of attributes (if a query uses attribute 'x', all rows have attribute 'x1' and 'x2' of same type)
I saw http://www.igvita.com/2010/03/01/schema-free-mysql-vs-nosql/ and https://github.com/jamesgolick/friendly .
Yes, there are NoSQL databases and special ORMs. We use Solr (it's great!). But I would avoid increasing the complexity of the project by including them. The performance overhead of emulating a noSQL store is not a concern.
In MySql I would use something like this:
CREATE TABLE IF NOT EXISTS `subject` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`description` varchar(255) NOT NULL,
`desired_seniority` decimal(5,2) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;
INSERT INTO `subject` (`id`, `name`, `description`, `desired_seniority`) VALUES
(1, 'data structures', 'easy', 5.00),
(2, 'microprocesors', 'easy', 5.50);
CREATE TABLE IF NOT EXISTS `subject_tag` (
`subject_id` int(10) unsigned NOT NULL,
`tag_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`subject_id`,`tag_id`),
KEY `fk_subject_tag_tags` (`tag_id`),
KEY `fk_subject_tag_subject` (`subject_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `subject_tag` (`subject_id`, `tag_id`) VALUES
(1, 1),
(2, 1),
(2, 2);
CREATE TABLE IF NOT EXISTS `tag` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;
INSERT INTO `tag` (`id`, `name`) VALUES
(1, 'CS'),
(2, 'Electronics');
CREATE TABLE IF NOT EXISTS `teacher` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`surname` varchar(50) NOT NULL,
`seniority` decimal(5,2) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;
INSERT INTO `teacher` (`id`, `name`, `surname`, `seniority`) VALUES
(1, 'John', 'Doe', 5.80),
(2, 'John', 'Brown', 5.30);
CREATE TABLE IF NOT EXISTS `teacher_tag` (
`teacher_id` int(10) unsigned NOT NULL,
`tag_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`teacher_id`,`tag_id`),
KEY `fk_teacher_tag_tag1` (`tag_id`),
KEY `fk_teacher_tag_teacher` (`teacher_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `teacher_tag` (`teacher_id`, `tag_id`) VALUES
(1, 2);
ALTER TABLE `subject_tag`
ADD CONSTRAINT `fk_subject_tag_tag` FOREIGN KEY (`tag_id`) REFERENCES `tag` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `fk_subject_tag_subject` FOREIGN KEY (`subject_id`) REFERENCES `subject` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE `teacher_tag`
ADD CONSTRAINT `fk_teacher_tag_tag` FOREIGN KEY (`tag_id`) REFERENCES `tag` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `fk_teacher_tag_teacher` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
And to get teachers with matched subjectes:
SELECT t.surname, t.name, GROUP_CONCAT( s.name SEPARATOR ' | ' ) AS subject_name
FROM teacher t
JOIN teacher_tag tt ON tt.teacher_id = t.id
JOIN subject_tag st ON st.tag_id = tt.tag_id
JOIN subject s ON st.subject_id = s.id
AND s.desired_seniority <= t.seniority
GROUP BY t.id
Related
I have tables that have been created like so:
CREATE TABLE `d_account` (
`id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
`account_name` varchar(128) CHARACTER SET utf8 NOT NULL,
`user_id` smallint(5) NOT NULL,
`type_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `FK_account_type` (`type_id`),
CONSTRAINT `FK_type` FOREIGN KEY (`type_id`) REFERENCES `d_types` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
);
CREATE TABLE `d_types` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(45) CHARACTER SET latin1 NOT NULL,
PRIMARY KEY (`id`)
);
How would I select all records that exist in both tables below using the foreign key where the d_type name equals ‘large’?
That's basically just a JOIN like this:
SELECT * FROM d_types t
JOIN d_account a ON t.id = a.type_id
WHERE t.name = 'large';
The * after select should be replaced by the columns you want to select.
This question already has answers here:
MySQL Creating tables with Foreign Keys giving errno: 150
(20 answers)
Closed 8 years ago.
Here's my schema:
-- Table 'users'
CREATE TABLE IF NOT EXISTS `users` (
`ID` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(50) COLLATE utf8_bin NOT NULL,
`password` varchar(100) COLLATE utf8_bin NOT NULL,
`registrationDate` datetime NOT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=1;
CREATE TABLE IF NOT EXISTS tasks (
id bigint(20) NOT NULL AUTO_INCREMENT,
description TEXT,
title TEXT,
type TEXT,
createdDate DATETIME NOT NULL,
finishedDate DATETIME,
user_id bigint(20) NOT NULL,
PRIMARY KEY (id),
CONSTRAINT user_fk FOREIGN KEY (user_id) REFERENCES USERS(ID) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=1;
I keep getting errno 150 when I try creating "tasks" table.
Looks like phpmyadmin on openshift is case sensitive, if you dig into the error you get this:
LATEST FOREIGN KEY ERROR
------------------------
140827 10:52:57 Error in foreign key constraint of table testing/tasks:
FOREIGN KEY (user_id) REFERENCES USERS(ID) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=1:
Cannot resolve table name close to:
(ID) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=1
In the below code, notice that i changed USERS to users in the second table creation code after REFERENCES.
Looks like this code works:
CREATE TABLE IF NOT EXISTS `users` (
`ID` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(50) COLLATE utf8_bin NOT NULL,
`password` varchar(100) COLLATE utf8_bin NOT NULL,
`registrationDate` datetime NOT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=1;
CREATE TABLE IF NOT EXISTS tasks (
id bigint(20) NOT NULL AUTO_INCREMENT,
description TEXT,
title TEXT,
type TEXT,
createdDate DATETIME NOT NULL,
finishedDate DATETIME,
user_id bigint(20) NOT NULL,
PRIMARY KEY (id),
CONSTRAINT user_fk FOREIGN KEY (user_id) REFERENCES users(ID) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=1;
I am developing round robin tournament and I have problem how to design database.
First I have season. Season contains list of tournament. Tournaments contains list of groups. Groups contains list participant. Then I have list of player. Different between player and participant is that participant is registered player which belongs to group. Then I have entity game which is defined by 2 participant and their score. So participant has list of games.
P = participant
G = game
P1 P2 P3
P1 X G1 G2
P2 G3 X G4
P3 G5 G6 X
Is this good model for my tournament ? I dont think so because I have duplicity in my db. G1 is just vice versa of G3 but I have no idea how to implement this model better
-- --------------------------------------------------------
--
-- Table structure for table `GAME`
--
CREATE TABLE IF NOT EXISTS `GAME` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`HOME_PARTICIPANT_ID` int(11) NOT NULL,
`AWAY_PARTICIPANT_ID` int(11) NOT NULL,
`HOME_SCORE` int(4) DEFAULT NULL,
`AWAY_SCORE` int(4) DEFAULT NULL,
PRIMARY KEY (`ID`),
KEY `HOME_PARTICIPANT_ID` (`HOME_PARTICIPANT_ID`),
KEY `AWAY_PARTICIPANT_ID` (`AWAY_PARTICIPANT_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
-- --------------------------------------------------------
--
-- Table structure for table `GROUPS`
--
CREATE TABLE IF NOT EXISTS `GROUPS` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`NAME` varchar(255) NOT NULL,
`TOURNAMENT_ID` int(11) NOT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `NAME` (`NAME`,`TOURNAMENT_ID`),
KEY `TOURNAMENT_ID` (`TOURNAMENT_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
-- --------------------------------------------------------
--
-- Table structure for table `PLAYER`
--
CREATE TABLE IF NOT EXISTS `PLAYER` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`NAME` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`SURNAME` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`CLUB` varchar(255) DEFAULT NULL,
`USER_ID` int(11) NOT NULL,
PRIMARY KEY (`ID`),
KEY `USER_ID` (`USER_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
-- --------------------------------------------------------
--
-- Table structure for table `PARTICIPANT`
--
CREATE TABLE IF NOT EXISTS `PARTICIPANT` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`POINTS` int(4) NOT NULL DEFAULT '0',
`RANK` int(4) DEFAULT NULL,
`GROUP_ID` int(11) NOT NULL,
`PLAYER_ID` int(11) NOT NULL,
`SCORE` varchar(10) NOT NULL DEFAULT '0:0',
PRIMARY KEY (`ID`),
KEY `PLAYER_ID` (`PLAYER_ID`),
KEY `GROUP_ID` (`GROUP_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
-- --------------------------------------------------------
--
-- Table structure for table `SEASON`
--
CREATE TABLE IF NOT EXISTS `SEASON` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`NAME` varchar(255) NOT NULL,
PRIMARY KEY (`ID`),
KEY `USER_ID` (`USER_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
-- --------------------------------------------------------
--
-- Table structure for table `TOURNAMENT`
--
CREATE TABLE IF NOT EXISTS `TOURNAMENT` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`NAME` varchar(255) NOT NULL,
`SEASON_ID` int(11) NOT NULL,
PRIMARY KEY (`ID`),
KEY `SEASON_ID` (`SEASON_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
--
-- Constraints for table `GAME`
--
ALTER TABLE `GAME`
ADD CONSTRAINT `GAME_ibfk_1` FOREIGN KEY (`HOME_PARTICIPANT_ID`) REFERENCES `PARTICIPANT` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `GAME_ibfk_2` FOREIGN KEY (`AWAY_PARTICIPANT_ID`) REFERENCES `PARTICIPANT` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE;
--
-- Constraints for table `GROUPS`
--
ALTER TABLE `GROUPS`
ADD CONSTRAINT `GROUPS_ibfk_1` FOREIGN KEY (`TOURNAMENT_ID`) REFERENCES `TOURNAMENT` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE;
--
-- Constraints for table `PARTICIPANT`
--
ALTER TABLE `PARTICIPANT`
ADD CONSTRAINT `PARTICIPANT_ibfk_1` FOREIGN KEY (`GROUP_ID`) REFERENCES `GROUPS` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `PARTICIPANT_ibfk_2` FOREIGN KEY (`PLAYER_ID`) REFERENCES `PLAYER` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE;
--
-- Constraints for table `TOURNAMENT`
--
ALTER TABLE `TOURNAMENT`
ADD CONSTRAINT `TOURNAMENT_ibfk_1` FOREIGN KEY (`SEASON_ID`) REFERENCES `SEASON` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE;
If you say you have duplicity then you need re-visit your design. Have you ever used Enhanced relationship diagrams? This is a good tool to make sure you have a correct database design for you.
This is a good website to help you if you haven't done this before: http://users.csc.calpoly.edu/~jdalbey/205/Lectures/HOWTO-ERD.html
A tournament is just a binary tree. You can use a nested set or an adjacency list.
This is my database:
-- Host: localhost
-- Generation Time: Feb 04, 2011 at 01:49 PM
-- Server version: 5.0.45
-- PHP Version: 5.2.5
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
--
-- Database: `myepguide`
--
-- --------------------------------------------------------
--
-- Table structure for table `channel1`
--
CREATE TABLE IF NOT EXISTS `channel1` (
`id` mediumint(255) NOT NULL auto_increment,
`channel` varchar(255) default NULL,
PRIMARY KEY (`id`),
KEY `channel` USING BTREE (`channel`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
--
-- Dumping data for table `channel1`
--
INSERT INTO `channel1` (`id`, `channel`) VALUES
(1, 'BBC One'),
(3, '<i>ITV1</i>'),
(2, '<i>ITV2 </i>');
-- --------------------------------------------------------
--
-- Table structure for table `myepguide`
--
CREATE TABLE IF NOT EXISTS `myepguide` (
`id` mediumint(9) NOT NULL auto_increment,
`programme` varchar(255) NOT NULL,
`channel` varchar(255) default NULL,
`airdate` datetime NOT NULL,
`displayair` datetime NOT NULL,
`expiration` datetime NOT NULL,
`episode` varchar(255) default '',
`setreminder` varchar(255) NOT NULL default '<img src="alert.gif" height="16" width="22"> Set Reminder',
PRIMARY KEY (`id`),
KEY `programme1` USING BTREE (`programme`),
KEY `channel2` USING BTREE (`channel`),
KEY `episode` (`episode`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
--
-- Dumping data for table `myepguide`
--
INSERT INTO `myepguide` (`id`, `programme`, `channel`, `airdate`, `displayair`, `expiration`, `episode`, `setreminder`) VALUES
(1, 'Casualty', '<i>BBC One </i>', '2011-05-18 14:30:00', '2011-05-18 14:30:00', '2011-05-18 15:00:00', 'No Fjords in Finland', '<img src="alert.gif" height="16" width="22"> Set Reminder');
-- --------------------------------------------------------
--
-- Table structure for table `episode`
--
CREATE TABLE IF NOT EXISTS `episode` (
`id` mediumint(9) NOT NULL auto_increment,
`episode` varchar(255) default NULL,
PRIMARY KEY (`id`),
KEY `episode` USING BTREE (`episode`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
--
-- Dumping data for table `episode`
--
INSERT INTO `episode` (`id`, `episode`) VALUES
(1, 'No Fjords in Finland'),
(2, 'Casualty 25th Special'),
(3, 'Palimpsest');
-- --------------------------------------------------------
--
-- Table structure for table `programme`
--
CREATE TABLE IF NOT EXISTS `programme` (
`id` mediumint(255) NOT NULL auto_increment,
`programme` varchar(255) default NULL,
PRIMARY KEY (`id`),
KEY `programme1` USING BTREE (`programme`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ;
--
-- Dumping data for table `programme`
--
INSERT INTO `programme` (`id`, `programme`) VALUES
(1, 'Casualty');
--
-- Constraints for dumped tables
--
--
-- Constraints for table `myepguide`
--
ALTER TABLE `myepguide`
ADD CONSTRAINT `myepguide_ibfk_1` FOREIGN KEY (`programme`) REFERENCES `myepguide` (`programme`) ON UPDATE CASCADE,
ADD CONSTRAINT `myepguide_ibfk_2` FOREIGN KEY (`channel`) REFERENCES `channel1` (`channel`) ON DELETE SET NULL ON UPDATE CASCADE;
I cannot get the 'episode` table to link to that in the table myepguide for some reason, in Phpmyadmin it always says "Relation not added".
Deleting and re-creating it did not work either, so how can I fix this?
All are stored in InnoDB format so I can't understand why this happened.
Any help is appreciated!
As mentioned in the comment, I am not quite sure what are you trying to link here, so for starters you could use this to get an idea of possible relationships.
EDIT
create table TvSeries (
TvSeriesID int not null auto_increment
-- , other fields here
) ENGINE=InnoDB ;
alter table TvSeries
add constraint pk_TvSeries primary key (TvSeriesID) ;
create table Episode (
TvSeriesID int not null
, EpisodeNo int not null
-- , other fields here
) ENGINE=InnoDB ;
alter table Episode
add constraint pk_Episode primary key (TvSeriesID, EpisodeNo)
, add constraint fk1_Episode foreign key (TvSeriesID) references TvSeries (TvSeriesID) ;
create table Channel (
ChannelID int not null
-- , other fields here
) ENGINE=InnoDB ;
alter table Channel
add constraint pk_Channel primary key (ChannelID);
create table Programme (
ChannelID int not null
, StartTime datetime not null
, TvSeriesID int not null
, EpisodeNo int not null
-- , other fields here
) ENGINE=InnoDB ;
alter table Programme
add constraint pk_Programme primary key (ChannelID, StartTime)
, add constraint fk1_Programme foreign key (ChannelID) references Channel (ChannelID)
, add constraint fk2_Programme foreign key (TvSeriesID, EpisodeNo) references Episode (TvSeriesID, EpisodeNo) ;
create table myEpisodeGuide (
TvSeriesID int not null
, EpisodeNo int not null
, ChannelID int not null
, StartTime datetime not null
, SetReminder int not null
-- , other fields here
) ENGINE=InnoDB ;
alter table myEpisodeGuide
add constraint pk_myEpisodeGuide primary key (TvSeriesID, EpisodeNo, ChannelID, StartTime)
, add constraint fk1_myEpisodeGuide foreign key (TvSeriesID, EpisodeNo) references Episode (TvSeriesID, EpisodeNo)
, add constraint fk2_myEpisodeGuide foreign key (ChannelID, StartTime) references Programme (ChannelID, StartTime) ;
I have two tables.
Table user:
CREATE TABLE IF NOT EXISTS `user` (
`user_id` int(20) NOT NULL AUTO_INCREMENT,
`ud_id` varchar(50) NOT NULL,
`name` text NOT NULL,
`password` text NOT NULL,
`email` varchar(200) NOT NULL,
`image` varchar(150) NOT NULL,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB
and mycatch:
CREATE TABLE IF NOT EXISTS `mycatch` (
`catch_id` int(11) NOT NULL AUTO_INCREMENT,
`catch_name` text NOT NULL,
`catch_details` text NOT NULL,
`longitude` float(10,6) NOT NULL,
`latitude` float(10,6) NOT NULL,
`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`image` varchar(150) NOT NULL,
`user_id` int(20) NOT NULL,
PRIMARY KEY (`catch_id`),
KEY `user_id` (`user_id`)
) ENGINE=InnoDB;
ALTER TABLE `mycatch`
ADD CONSTRAINT `mycatch_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`user_id`) ON DELETE CASCADE ON UPDATE CASCADE;
My goal is: I want to retrieve longitude and latitude from mycatch against given ud_id (from user) and catch_id (from mycatch) where ud_id = given ud_id and catch_id > given catch_id.
I used the query but fail to retrieve
SELECT ud_id=$ud_id FROM user
WHERE user_id =
(
SELECT user_id,longitude,latitude from mycatch
WHERE catch_id>'$catch_id'
)
The error is:
#1241 - Operand should contain 1 column(s)
First, try not to use subqueries at all, they're very slow in MySQL.
Second, a subquery wouldn't even help here. This is a regular join (no, Mr Singh, not an inner join):
SELECT ud_id FROM user, mycatch
WHERE catch_id>'$catch_id'
AND user.user_id = mycatch.user_id
Select m.longitude,m.latitude from user u left join mycatch m
on u.user_id =m.user_id
where u.ud_id=$ud_id and
m.catch_id >$catch_id