Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Creating related tables allows you much greater freedom to query and extract relevant information. Here's a few links that you might find useful:</p> <p>You could start with these tutorials:<br> <a href="http://dev.mysql.com/tech-resources/articles/intro-to-normalization.html" rel="nofollow noreferrer">http://dev.mysql.com/tech-resources/articles/intro-to-normalization.html</a><br> <a href="http://net.tutsplus.com/tutorials/databases/sql-for-beginners/" rel="nofollow noreferrer">http://net.tutsplus.com/tutorials/databases/sql-for-beginners/</a></p> <p>There are also a couple of questions here on stackoverflow that might be useful:<br> <a href="https://stackoverflow.com/questions/2331838/normalization-in-plain-english">Normalization in plain English</a><br> <a href="https://stackoverflow.com/questions/1102590/what-exactly-does-normalization-do">What exactly does database normalization do?</a> </p> <p>Anyway, on to a possible solution. The following examples use your hotel rooms analogy.</p> <p>First, create a table to hold information about the hotel rooms. This table just contains the room ID and its name, but you could store other information in here, such as the room type (single, double, twin), its view (ocean front, ocean view, city view, pool view), and so on:</p> <pre><code>CREATE TABLE `room` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `name` VARCHAR(45) NOT NULL, PRIMARY KEY (`id`), UNIQUE INDEX `name_UNIQUE` (`name` ASC) ) ENGINE = InnoDB; </code></pre> <p>Now create a table to hold the changing room rates. This table links to the <code>room</code> table through the <code>room_id</code> column. The foreign key constraint prevents records being inserted into the <code>rate</code> table which refer to rooms that do not exist:</p> <pre><code>CREATE TABLE `rate` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT , `room_id` INT UNSIGNED NOT NULL, `date` DATE NOT NULL, `rate` DECIMAL(6,2) UNSIGNED NOT NULL, PRIMARY KEY (`id`), INDEX `fk_room_rate` (`room_id` ASC), CONSTRAINT `fk_room_rate` FOREIGN KEY (`room_id` ) REFERENCES `room` (`id` ) ON DELETE CASCADE ON UPDATE CASCADE) ENGINE = InnoDB; </code></pre> <p>Create two rooms, and add some daily rate information about each room:</p> <pre><code>INSERT INTO `room` (`id`, `name`) VALUES (1, 'A'), (2, 'B'); INSERT INTO `rate` (`id`, `room_id`, `date`, `rate`) VALUES ( 1, 1, '2010-07-01', 200), ( 2, 1, '2010-07-02', 200), ( 3, 1, '2010-07-03', 150), ( 4, 1, '2010-07-04', 150), ( 5, 1, '2010-07-05', 150), ( 6, 1, '2010-07-06', 200), ( 7, 1, '2010-07-07', 200), ( 8, 1, '2010-07-08', 100), ( 9, 1, '2010-07-09', 100), (10, 2, '2010-07-01', 300), (11, 2, '2010-07-02', 300), (12, 2, '2010-07-03', 250), (13, 2, '2010-07-04', 250), (14, 2, '2010-07-05', 350), (15, 2, '2010-07-06', 300), (16, 2, '2010-07-07', 300), (17, 2, '2010-07-08', 200), (18, 2, '2010-07-09', 200); </code></pre> <p>With that information stored, a simple <code>SELECT</code> query with a <code>JOIN</code> will show you the all the daily room rates:</p> <pre><code>SELECT room.name, rate.date, rate.rate FROM room JOIN rate ON rate.room_id = room.id; +------+------------+--------+ | A | 2010-07-01 | 200.00 | | A | 2010-07-02 | 200.00 | | A | 2010-07-03 | 150.00 | | A | 2010-07-04 | 150.00 | | A | 2010-07-05 | 150.00 | | A | 2010-07-06 | 200.00 | | A | 2010-07-07 | 200.00 | | A | 2010-07-08 | 100.00 | | A | 2010-07-09 | 100.00 | | B | 2010-07-01 | 300.00 | | B | 2010-07-02 | 300.00 | | B | 2010-07-03 | 250.00 | | B | 2010-07-04 | 250.00 | | B | 2010-07-05 | 350.00 | | B | 2010-07-06 | 300.00 | | B | 2010-07-07 | 300.00 | | B | 2010-07-08 | 200.00 | | B | 2010-07-09 | 200.00 | +------+------------+--------+ </code></pre> <p>To find the start and end dates for each room rate, you need a more complex query:</p> <pre><code>SELECT id, room_id, MIN(date) AS start_date, MAX(date) AS end_date, COUNT(*) AS days, rate FROM ( SELECT id, room_id, date, rate, ( SELECT COUNT(*) FROM rate AS b WHERE b.rate &lt;&gt; a.rate AND b.date &lt;= a.date AND b.room_id = a.room_id ) AS grouping FROM rate AS a ORDER BY a.room_id, a.date ) c GROUP BY rate, grouping ORDER BY room_id, MIN(date); +----+---------+------------+------------+------+--------+ | id | room_id | start_date | end_date | days | rate | +----+---------+------------+------------+------+--------+ | 1 | 1 | 2010-07-01 | 2010-07-02 | 2 | 200.00 | | 3 | 1 | 2010-07-03 | 2010-07-05 | 3 | 150.00 | | 6 | 1 | 2010-07-06 | 2010-07-07 | 2 | 200.00 | | 8 | 1 | 2010-07-08 | 2010-07-09 | 2 | 100.00 | | 10 | 2 | 2010-07-01 | 2010-07-02 | 2 | 300.00 | | 12 | 2 | 2010-07-03 | 2010-07-04 | 2 | 250.00 | | 14 | 2 | 2010-07-05 | 2010-07-05 | 1 | 350.00 | | 15 | 2 | 2010-07-06 | 2010-07-07 | 2 | 300.00 | | 17 | 2 | 2010-07-08 | 2010-07-09 | 2 | 200.00 | +----+---------+------------+------------+------+--------+ </code></pre> <p>You can find a good explanation of the technique used in the above query here:<br> <a href="http://www.sqlteam.com/article/detecting-runs-or-streaks-in-your-data" rel="nofollow noreferrer">http://www.sqlteam.com/article/detecting-runs-or-streaks-in-your-data</a></p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload