Find next occurrence from a reference table sql - mysql

I have searched many other questions, but cant find a usable comparison. I have a SQL table that has a list of all the rooms at our hotel. I want to know the next time each room is going to be occupied. There are two tables I am looking at, one contains the name and details of each room we have, for all intents it is a static table. The other table is a reservations table that shows check in and check out times, and has a column that references which room is being used.
Table Rooms
unique id name
1 Room 3
2 Room 4
3 Suite 1
4 Suite 2
5 Suite 3
Table Reservations
unique id start date room id
1 12/4/16 3
2 12/4/16 4
3 12/6/16 3
4 12/12/16 3
5 12/14/16 2
6 12/20/16 2
This would return only 3 values:
2 12/20/16
3 12/4/16
4 12/4/16
If also possible I would like the make it so that if a reservation is not found a null value is returned, so ultimately, the return value would be
Room Next Occurrence
1 null
2 12/20/16
3 12/4/16
4 12/4/16
5 null
Is there a way of doing this without my current php hack that runs 200 sql queries?
Thanks so much!

You can use left join
select rooms.id, rooms.name, reservations.`start date`
from Rooms
left join reservations on reservations.`room id` = Rooms.id
order by rooms.id

Related

Duplicate or unpredictable results in MySQL

I'm trying to join a few tables in MySQL. Our setup is a little unique so I try to explain as good as I can.
I have a table 'INVENTORY' that represents the current items on stock.
These items are stored in a table 'COMPONENT'
Components are being used in installations.
Every user can have multiple installations and the same component can be used in multiple installation as well.
To uniquely map a component to an installation, it can be assigned to a PRODUCT. a product as has a 1-1 relationship with an installation. A component is not directly related to an installation
To finally assign a product to a specific installation a mapping table COMPOMENT_PRODUCT is used.
Example:
A component is like a part, lets say a screw. This screw is used in a computer. The very same screw can be used on multiple computers. But each computer can only be used on one specific installation.
TABLE COMPOMENT_PRODUCT
COMPOMENT_ID PRODUCT_ID
1 1
1 2
2 1
2 2
So we have the components C1 and C2 relevant for two installations.
TABLE INVENTORY
COMPOMENT_ID INSTALLATION_ID ON_STOCK
1 1 5
1 2 2
What I want to achieve
Now, I want to retrieve the inventory state for all components. But, not every component has an inventory record. In these cases, the ON_STOCK value from the inventory shall be NULL
That means, for this example I'd expect the following results
COMPOMENT_ID PRODUCT_ID ON_STOCK
1 1 5
1 2 2
2 1 NULL
2 2 NULL
But executing this query:
SELECT DISTINCT
COMPONENT_PRODUCT.COMPONENT_ID,
COMPONENT_PRODUCT.PRODUCT_ID,
INVENTORY.ON_STOCK
FROM INVENTORY
RIGHT JOIN COMPONENT_PRODUCT ON COMPONENT_PRODUCT.COMPONENT_ID =
INVENTORY.COMPONENT_ID
returns the following resultset:
COMPONENT_ID PRODUCT_ID ON_STOCK
1 1 5
1 2 5
1 1 2
1 2 2
2 1 (null)
2 2 (null)
Now, my next thought was, "of course, this is how joins behave, okay I need to group the results". But the way SQL works, the aggregation is not entirely predictable. SO when I
GROUP BY COMPONENT_PRODUCT.COMPONENT_ID,COMPONENT_PRODUCT.PRODUCT_ID
I get this result:
COMPONENT_ID PRODUCT_ID ON_STOCK
1 1 5
1 2 5
2 1 (null)
2 2 (null)
I have prepared a Fiddle here: http://sqlfiddle.com/#!9/71ca87
What am I forgetting here? Thanks in advance for any pointers.
Try this query -
SELECT DISTINCT
COMPONENT_PRODUCT.COMPONENT_ID,
COMPONENT_PRODUCT.PRODUCT_ID,
INVENTORY.ON_STOCK
FROM INVENTORY
RIGHT JOIN COMPONENT_PRODUCT ON COMPONENT_PRODUCT.COMPONENT_ID =
INVENTORY.COMPONENT_ID
AND COMPONENT_PRODUCT.PRODUCT_ID = INVENTORY.INSTALLATION_ID

Edit product selling location using mysql

I'm building a e-Commerce platform (PHP + MySQL) and I want to add a attribute (feature) to products, the ability to specify (enable/disable) the selling status for specific city.
Here are simplified tables:
cities
id name
==========
1 Roma
2 Berlin
3 Paris
4 London
products
id name cities
==================
1 TV 1,2,4
2 Phone 1,3,4
3 Book 1,2,3,4
4 Guitar 3
In this simple example is easy to query (using FIND_IN_SET or LIKE) to check the availability of product for specific city.
This is OK for 4 city in this example or even 100 cities but will be practical for a large number of cities and for very large number of products?
For better "performance" or better database design should I add another table to table to JOIN in query (productid, cityid, status) ?
availability
id productid cityid status
=============================
1 1 1 1
2 1 2 1
3 1 4 1
4 2 1 1
5 2 3 1
6 2 4 1
7 3 1 1
8 3 2 1
9 3 3 1
10 3 4 1
11 4 3 1
For better "performance" or better database design should I add
another table
YES definitely you should create another table to hold that information likewise you posted rather storing in , separated list which is against Normalization concept. Also, there is no way you can gain better performance when you try to JOIN and find out the details pf products available in which cities.
At any point in time if you want to get back a comma separated list like 1,2,4 of values then you can do a GROUP BY productid and use GROUP_CONCAT(cityid) to get the same.

How can I merge data from two SQL tables?

I have two tables. Table "alldates" consists of date column called "nextdate". Table "availability" consists of multiple columns including a date column called "availdate". The "alldates" table primary key is the column "nextdate". The "availability" table primary key is a column called "event_num".
For explanation purposes let's say table "alldates" is populated with 16 rows, dates 10/01/2014 through 10/16/2014 and table "availability" is populated with 9 rows, like so:
Availdate Event_num Event Description
10/01/2014 3 Joe's birthday
10/04/2014 12 Bill's dentist appt
10/04/2014 5 Buy pizza
10/05/2014 6 Clean the house
10/07/2014 7 Go to theater
10/07/2014 8 Continue forward
10/09/2014 9 Mow the grass
10/11/2014 10 Take a nap
10/15/2014 11 Fix the clock
I need to create a new table that looks like this:
Availdate Event_num Event Description
10/01/2014 3 Joe's birthday
10/02/2014 (from table "alldates")
10/03/2014 (from table "alldates")
10/04/2014 12 Bill's dentist appt
10/04/2014 5 Buy pizza
10/05/2014 6 Clean the house
10/06/2014 (from table "alldates")
10/07/2014 7 Go to theater
10/07/2014 8 Continue forward
10/08/2014 (from table "alldates")
10/09/2014 9 Mow the grass
10/10/2014 (from table "alldates")
10/11/2014 10 Take a nap
10/12/2014 (from table "alldates")
10/13/2014 (from table "alldates")
10/14/2014 (from table "alldates")
10/15/2014 11 Fix the clock
10/16/2014 (from table "alldates")
Looks like a classic left join to me.
select a.nextdate as availdate,
b.event_num,
b.event_description
from alldates a
left join availability b
on a.nextdate = b.availdate
;
If both the table have same number of columns then you can probably do a UNION between them and order by the Availdate column
select * from
(
select Availdate,
Event_num,
Event Description
from alldates
UNION
select Availdate,
Event_num,
Event Description
from availability
) tab
order by Availdate
What you want is a LEFT OUTER JOIN. LEFT OUTER tells SQL to include rows from the first table, even if they don't have corresponding entries in the second. "Corresponding" is determined by the predicate, which is a condition telling the database how rows in one table are associated with rows in the other.
The below query will select all rows from alldates. For those whose nextdate matches a row's availdate in availability, each it will be displayed once per matching row. For those whose nextdate doesn't match anything from availability, event_num and event_description will be listed as NULL.
SELECT
alldates.nextdate,
availability.event_num,
availability.event_description
FROM
ALLDATES
LEFT JOIN availability
ON alldates.nextdate = availability.availdate;

How to record sequential collections of records in MySQL

Suppose I have a table that holds some type of record, say cooking instructions like "Fold the melted chocolate into the egg whites". The table contains a unique ID field and the string.
I want to build another table for recipes (each with a unique ID and a name), each of which would be a series of sequential instructions (some instructions would be used for several/many recipes).
What is the best way to structure my recipe table to map a recipe's unique ID to a sequential series of instructions (which IDs are not sequential)?
Try a normalized design like this:
recipe
id name
1 Recipe1
2 Recipe2
recipe_instruction
recipe_id instruction_id sortorder
1 5 1
1 3 2
1 4 3
2 6 1
2 7 2
2 3 3
To get the list of instructions for a specific recipe you can use this query:
SELECT i.the_string
FROM recipe_instruction AS ri
JOIN instruction AS i
ON ri.instruction_id = i.id
WHERE ri.recipe_id = 1
ORDER BY ri.sortorder

SQL query for multiple (one-to-many) tables in mysql database

I have a database with tours (group city tours with guide). What I need is a SQL query (for a mysql 5.1.54 database) that will eventually give me a PHP array with the information out of multiple tables combined. I'm able to accomplish this by doing a query just for the first 3 tables and then adding the information in table 4 and 5 within a foreach loop.
But, I need to use the query for searching/filtering (like: show all reservations where partner has id 9) so I need SQL to select the corresponding reservations.
Reservations with no partners (table 4) and/or guides (table 5) must be included.
All partners and guides must be included in the result (reservation can have more partners/guides)
All information in table 4 and 5 must be included (like the status from table 4).
A simplified version of the database:
Table 1: reservations:
id id_client id_tour
1 22 6
2 23 5
Table 2: clients (one reservation has one client):
id name
22 John
23 William
Table 3: tours (one reservation has one tour)
id name
5 big tour
6 small tour
Table 4: partners (one reservation can have multiple partners):
id id_reservation id_partner_type id_partner status
34 1 9 16 1
35 1 9 17 0
Table 5: guides (one reservation can have multiple guides):
id id_reservation id_guide
18 1 14
19 1 15
I have tried to work this out but I just can not get a query that does the job. I used GROUP_CONCAT to get the multiple partner and guide id's. Biggest problem I have is not being able to include the reservations that have no partners and/or guides like reservation 2.
To include all reservations that have no partners and guides you need to use OUTER JOINs, for example the following query will gives you all information from your tables 4, 5 including your condition:
Select p.*, g.*
from reservations r
left outer join partners p on p.id_reservation = r.id
left outer join guides g on g.id_reservation = r.id
where p.id_reservation is null and g.id_reservation is null