简体   繁体   中英

how to best design the DB in this situation

At a glance, the database schema looks like this:

在此处输入图片说明

The schema has to be in 3rd normal form (and I am aware that hotels.average_rating suggests otherwise, try to oversee that, since the database is not fully designed yet). This is for a tourist recommendation system.

The SQL:

SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";

CREATE TABLE `activities` (
  `activity_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `activity_name` varchar(277) COLLATE utf8_bin NOT NULL,
  PRIMARY KEY (`activity_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

CREATE TABLE `bookings` (
  `from_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `to_date` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `belong_user` int(10) unsigned NOT NULL,
  `belong_hotel` int(10) unsigned NOT NULL,
  `rating` int(3) unsigned NOT NULL,
  KEY `belong_user` (`belong_user`),
  KEY `belong_hotel` (`belong_hotel`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

CREATE TABLE `countries` (
  `cuntry_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `country_name` varchar(20) COLLATE utf8_bin NOT NULL,
  PRIMARY KEY (`cuntry_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

CREATE TABLE `hotels` (
  `hotel_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `hotel_name` varchar(128) COLLATE utf8_bin NOT NULL,
  `hotel_stars` int(3) NOT NULL,
  `hotel_description` text COLLATE utf8_bin NOT NULL,
  `average_price` float unsigned NOT NULL,
  `average_rating` float unsigned NOT NULL,
  `total_rooms` int(10) unsigned NOT NULL,
  `free_rooms` int(10) unsigned NOT NULL,
  `belong_region` int(10) unsigned NOT NULL,
  PRIMARY KEY (`hotel_id`),
  KEY `belong_region` (`belong_region`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

CREATE TABLE `hotels_activity_offers` (
  `belong_hotel` int(10) unsigned NOT NULL,
  `belong_activity` int(10) unsigned NOT NULL,
  UNIQUE KEY `belong_hotel_2` (`belong_hotel`,`belong_activity`),
  KEY `belong_hotel` (`belong_hotel`),
  KEY `belong_activity` (`belong_activity`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

CREATE TABLE `regions` (
  `region_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `belong_country` int(10) unsigned NOT NULL,
  `region_name` varchar(255) COLLATE utf8_bin NOT NULL,
  PRIMARY KEY (`region_id`),
  KEY `belong_country` (`belong_country`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

CREATE TABLE `regions_activity_offers` (
  `belong_region` int(10) unsigned NOT NULL,
  `belong_activity` int(10) unsigned NOT NULL,
  KEY `belong_region` (`belong_region`),
  KEY `belong_activity` (`belong_activity`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

CREATE TABLE `users` (
  `user_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `username` varchar(20) COLLATE utf8_bin NOT NULL,
  `password` varchar(40) COLLATE utf8_bin NOT NULL COMMENT 'MD5',
  `first_name` varchar(20) COLLATE utf8_bin NOT NULL,
  `last_name` varchar(20) COLLATE utf8_bin NOT NULL,
  `email` varchar(255) COLLATE utf8_bin NOT NULL,
  `is_admin` tinyint(1) NOT NULL,
  `is_active` tinyint(1) NOT NULL,
  PRIMARY KEY (`user_id`),
  KEY `is_active` (`is_active`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

CREATE TABLE `users_favourite_activities` (
  `belong_user` int(10) unsigned NOT NULL,
  `belong_activity` int(10) unsigned NOT NULL,
  UNIQUE KEY `belong_user_2` (`belong_user`,`belong_activity`),
  KEY `belong_user` (`belong_user`),
  KEY `belong_activity` (`belong_activity`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;


ALTER TABLE `bookings`
  ADD CONSTRAINT `bookings_ibfk_3` FOREIGN KEY (`belong_hotel`) REFERENCES `hotels` (`hotel_id`) ON DELETE CASCADE,
  ADD CONSTRAINT `bookings_ibfk_2` FOREIGN KEY (`belong_user`) REFERENCES `users` (`user_id`) ON DELETE CASCADE;

ALTER TABLE `hotels`
  ADD CONSTRAINT `hotels_ibfk_1` FOREIGN KEY (`belong_region`) REFERENCES `regions` (`region_id`) ON DELETE CASCADE;

ALTER TABLE `hotels_activity_offers`
  ADD CONSTRAINT `hotels_activity_offers_ibfk_2` FOREIGN KEY (`belong_activity`) REFERENCES `activities` (`activity_id`) ON DELETE CASCADE,
  ADD CONSTRAINT `hotels_activity_offers_ibfk_1` FOREIGN KEY (`belong_hotel`) REFERENCES `hotels` (`hotel_id`) ON DELETE CASCADE;

ALTER TABLE `regions`
  ADD CONSTRAINT `regions_ibfk_1` FOREIGN KEY (`belong_country`) REFERENCES `countries` (`cuntry_id`) ON DELETE CASCADE;

ALTER TABLE `regions_activity_offers`
  ADD CONSTRAINT `regions_activity_offers_ibfk_2` FOREIGN KEY (`belong_activity`) REFERENCES `activities` (`activity_id`) ON DELETE CASCADE,
  ADD CONSTRAINT `regions_activity_offers_ibfk_1` FOREIGN KEY (`belong_region`) REFERENCES `regions` (`region_id`) ON DELETE CASCADE;

ALTER TABLE `users_favourite_activities`
  ADD CONSTRAINT `users_favourite_activities_ibfk_1` FOREIGN KEY (`belong_user`) REFERENCES `users` (`user_id`) ON DELETE CASCADE,
  ADD CONSTRAINT `users_favourite_activities_ibfk_2` FOREIGN KEY (`belong_activity`) REFERENCES `activities` (`activity_id`) ON DELETE CASCADE;
  1. The question is: how to best add a "user activity log" feature which stores the activities a user has taken part to? Note that both regions and hotels can have activities, and I need to be able to tell whether that activity has taken place in a region or in a hotel. Referential integrity should be guaranteed.

  2. Present a query (it should use JOIN shouldn't it?) which lists all users and their activities along with the hotel id or region id. (the one which is not applicable can be NULL if required).

Simple solutions are better - so preferably without stored procedures or anything which digs too much in mysql-specific features.

Your database is not normalized - and the way you've done it looks like a poster-child for why normalization is a good idea.

hotels.average_rating?

WTF?

While it can make sense to denormalize your data - this is not how to do it. Think about what you need to do when a user submits a hotel rating - you need to recalculate the value based on all the ratings submitted. If instead you held a sum_of_ratings (or even retained the current average) and a number of ratings then you could calculate the new values based on the hotel record and the new rating without having to look at the other ratings.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM