How do I use the information from existing MySQL tables to populate a new table. I have three tables each of which have a key that I want to include in the new table like so:
TRANSACTIONS TABLE
tr_id INT NOT NULL AUTO_INCREMENT
other columns
.
.
PEOPLE TABLE
p_id INT NOT NULL AUTO_INCREMENT
tr_id INT
other columns
.
.
HOLIDAYS TABLE
h_id INT NOT NULL AUTO_INCREMENT
tr_id INT
other columns
.
.
TRACKING TABLE
track_id INT NOT NULL AUTO_INCREMENT
tr_id
p_id
h_id
other columns
.
.
I'm not even sure that I need the p_id and h_id columns in the new table, because I just need to be able to get all the rows from the tracking table for a single tr_id, but they may come in useful, so I might leave them in there. (I do need them to create the rows in the new table because one transaction can relate to multiple people going on multiple holiday destinations and each row in the tracking table ust relate to a single destination for a single person, so for 2 people each going to the same 2 holiday destinations, there will be 4 rows in the tracking table)
I have tried:
INSERT INTO tracking (tr_id, p_id, h_id) VALUES
(SELECT t.tr_id, p.p_id, h.h_id
FROM transactions t
JOIN people p
JOIN holidays h
WHERE t.tr_id = p.tr_id
AND t.tr_id = h.tr_id);
but this is giving me an error.
Grateful for any advice on this. Many thanks.
You can skip the Values infront of select,
and you could use the keyword "USING" if you want to
connect the tables on a column that have the same name in both tables.
i should have used:
INSERT INTO tracking (tr_id, p_id, h_id)
SELECT tr_id, p_id, h_id
FROM transactions
LEFT JOIN people USING (tr_id)
LEFT JOIN holidays USING (tr_id)
There is a syntax error. When you use Join, it is followed by the ON keyword which specifies which columns need to match. The following query will work:
INSERT INTO tracking (tr_id, p_id, h_id) VALUES
(SELECT t.tr_id, p.p_id, h.h_id
FROM transactions t
JOIN people p
on t.tr_id = p.tr_id
JOIN holidays h
on t.tr_id = h.tr_id)
You can read more about JOINS over here
UPDATE
This should work:
INSERT INTO tracking (tr_id, p_id, h_id)
SELECT t.tr_id, p.p_id, h.h_id
FROM transactions t
JOIN people p
on t.tr_id = p.tr_id
JOIN holidays h
on t.tr_id = h.tr_id
Reference: MySQL Insert & Joins
The reference that I have provided does not use the VALUES keyword in the query. Strange syntax, but let me know if that works.
Related
I have 2 tables: operations with client processing data and customers with age data. I want create new table, vlookup and add new column Age from customers to operations, but it doesnot work:
CREATE TABLE new_schema.total AS (
SELECT new_schema.operations.Id_check,new_schema.operations.ID_client, new_schema.customers.Age
INNER JOIN Age ON new_schema.operations.ID_client=new_schema.customers.ID_client
);
You have some basic syntax errors. There's no FROM clause to specify the first table, and INNER JOIN must be followed by the table you're joining with, not a column.
And you said you wanted the new table to be named vlookup, but you created total instead.
CREATE TABLE new_schema.vlookup AS (
SELECT o.id_check, o.id_client, c.age
FROM new_schema.operations AS o
INNER JOIN new_schema.customers AS c ON o.id_client = c.id_client
);
I'm aware of the INSERT INTO table_name QUERY; however, I'm unsure how to go about achieving the desired result in this case.
Here's a slightly contrived example to explain what I'm looking for, but I'm afraid I cannot put it more succiently.
I have two tables in a database designed for a hotel.
BOOKING and CUSTOMER_BOOKING
Where BOOKING contains PK_room_number, room_type, etc. and CUSTOMER_BOOKING contains FK_room_number, FK_cusomer_id
CUSTOMER_BOOKING is a linking table (many customers can make many bookings, and many bookings can consist of many customers).
Ultimately, in the application back-end I want to be able to list all rooms that have less than 3 customers associated with them. I could execute this a separate query and save the result in the server-side scripting.
However, a more elegant solution (from my point of view) is to store this within the BOOKING table itself. That is to add a column no_of_bookings that counts the number of times the current PK_room_number appears as the foreign key FK_room_number within the CUSTOMER_BOOKING table. And why do this instead? Because it would be impossible for me to write a single complicated query which will both include the information from all ROOMS, among other tables, and also count the occurrences of bookings, without excluding ROOMS that don't have any bookings. A very bad thing for a hotel website attempting to show free rooms!
So it would look like this
BOOKING: PK_room_number (104B) room_type (double) room_price (high), no_of_bookings (3)
BOOKING: PK_room_number (108C) room_type (single) room_price (low), no_of_bookings (1)
CUSTOMER_BOOKING: FK_room_number (104B) FK_customer_id (4312)
CUSTOMER_BOOKING: FK_room_number (104B) FK_customer_id (6372)
CUSTOMER_BOOKING: FK_room_number (104B) FK_customer_id (1112)
CUSTOMER_BOOKING: FK_room_number (108C) FK_customer_id (9181)
How would I go about creating this?
Because it would be impossible for me to write a single complicated
query which will both include the information from all ROOMS, among
other tables, and also count the occurrences of bookings, without
excluding ROOMS that don't have any bookings.
I wouldn't say it's impossible and unless you're running into performance issues, it's easier to implement than adding a new summary column:
select b.*, count(cb.room_number)
from bookings b
left join customer_booking cb on b.room_number = cb.room_number
group by b.room_number
Depending on your query may need to use a derived table containing the booking counts for each room instead instead
select b.*, coalesce(t1.number_of_bookings,0) number_of_bookings
from bookings b
left join (
select room_number, count(*) number_of_bookings
from customer_booking
group by room_number
) t1 on t1.room_number = b.room_number
You have to left join the derived table and select coalesce(t1.number_of_bookings,0) in case a room does not have any entries in the derived table (i.e. 0 bookings).
A summary column is a good idea when you're running into performance issues with counting the # of bookings each time. In that case I recommend creating insert and delete triggers on the customer_booking table that either increment or decrement the number_of_bookings column.
You could do it in a single straight select like this:
select DISTINCT
b1.room_pk,
c1.no_of_bookings
from cust_bookings b1,
(select room_pk, count(1) as no_of_bookings
from cust_bookings
group by room_pk) c1
where b1.room_pk = c1.room_pk
having c1.no_of_bookings < 3
Sorry i used my own table names to test it but you should figure it out easily enough. Also, the "having" line is only there to limit the rows returned to rooms with less than 3 bookings. If you remove that line you will get everything and could use the same sql to update a column on the bookings table if you still want to go that route.
Consider below solutions.
A simple aggregate query to count the customers per each booking:
SELECT b.PK_room_number, Count(c.FK_customer_id)
FROM Booking b
INNER JOIN Customer_Booking c ON b.PK_room_number = c.FK_room_number
GROUP BY b.PK_room_number
HAVING Count(c.FK_customer_id) < 3; # ADD 3 ROOM MAX FILTER
And if you intend to use a new column no_of_booking, here is an update query (using aggregate subquery) to run right after inserting new value from web frontend:
UPDATE Booking b
INNER JOIN
(SELECT b.PK_room_number, Count(c.FK_customer_id) As customercount
FROM Booking b
INNER JOIN Customer_Booking c ON b.PK_room_number = c.FK_room_number
GROUP BY b.PK_room_number) As r
ON b.PK_room_number = r.PK_room_number
SET b.no_of_booking = r.customercount;
the following generates a list showing all of the bookings and a flag of 0 or 1 if the the room has a customer for each of the rooms. it will display some rooms multiple times if there are multiple customers.
select BOOKING.*,
case CUSTOMER_BOOKING.FK_ROOM_NUMBER is null THEN 0 ELSE 1 END AS BOOKING_FLAG
from BOOKING LEFT OUTER JOIN CUSTOMER_BOOKING
ON BOOKING.PK_room_numer = CUSTOMER_BOOKING.FK_room_number
summing and grouping we arrive at:
select BOOKING.*,
SUM(case when CUSTOMER_BOOKING.FK_ROOM_NUMBER is null THEN 0 ELSE 1 END) AS BOOKING_COUNT
from BOOKING LEFT OUTER JOIN CUSTOMER_BOOKING
ON BOOKING.PK_room_number = CUSTOMER_BOOKING.FK_room_number
GROUP BY BOOKING.PK_room_number
there are at least two other solutions I can think of off the top of my head...
There are 3 tables:
Users table
------------
|uid|username|
------------
Values table
------------------
|vid|values|checked|
------------------
Relations
-----------
|cid|uid|vid|
-----------
Relations table contains user ids related to value ids. How to select value id from values table that is not related to given user id in relations table?
EDIT:
What I tried so far:
SELECT vid FROM relations where uid=user_id //this gives me array of value ids
SELECT vid FROM values where vid!=vid1 AND vid!=vid2 .....
EDIT2:
Basic solution can be found here. But is there more efficient way? If table is very large for both values table and relations table basic solution is not efficient.
Which dbms are you using? Does it support the minus clause? If yes you can do something like this
select vid from values
minus
select vid from relations where uid = #user_id
this should give the vid's which are not mapped to a given user id
Another way to do this is through a not-exists clause (handy if your dbms doesn't support the minus clause)
select v.vid from values v where not exists (select 1 from relations r where
r.vid = v.vid and r.user_id = #user_id)
I would caution against using the not in clause though. Its performance is questionable and fails if the inner query returns a null value, which though is not possible in your case, but you should make it a habit to never use the 'not in' clause with a sub-query. Only use it when you have a list of literal values e.g. '... vid not in (1, 2, 3, 4)'. Whenever you have to 'Minus' something from one table based on values in another table use the 'not exists' and never 'not in'
I think you can execute a simple query like this (assuming that the data type of user identifier is int):
DECLARE #givenUserID int --local variable where you store the given user identifier
SELECT vid
FROM Values
WHERE vid NOT IN (SELECT vid FROM Relations where uid = #givenUserID)
Is it ok for you ?
select vid from values where vid not in (select vid from relations where uid = user_id)
I think something simple like this query will suffice.
If there is no uid for a particular entry in the value table, then there shouldn't be an entry in the relations table either.
SELECT vid
FROM values
LEFT JOIN relations on values.vid = relations.vid
WHERE relations.uid IS NULL
select distinct v.vid
from values v
left join relations r on (r.vid=v.vid)
where r.uid != user_id
It's unfortunate that MySQL doesn't support with; this is not going to perform very well, unfortunately.
If a Value is exactly 0 or 1 time in your Relations table, you can use a JOIN for that:
SELECT `Values`.`vid` FROM `Values`
LEFT JOIN `Relations` ON (`Values`.`vid` = `Relations`.`vid`)
WHERE `Relations`.`uid` != 1;
This will not work if a Value is more than 1 time in the Relations table because the WHERE would match another row with a different uid in this case. It is the same with a NOT IN, this could also match a different row with the same vid but another uid.
If every Value is at least once in the Relations table, the most efficient way is to query only the Relations table:
SELECT DISTINCT `Relations`.`vid` FROM `Relations`
WHERE `Relations`.`uid` != 1;
If a Value can be 0, 1, or more times in the Relations table, the best way is to use an EXISTS (see also taimur's answer):
SELECT `Values`.`vid` FROM `Values`
WHERE NOT EXISTS (
SELECT * FROM `Relations`
WHERE `Relations`.`vid` = `Values`.`vid` AND `Relations`.`uid` = 1
);
However, EXISTS is a bit slower than the IN or JOIN, so you should compare how the execution times are in your case.
Let's say I have a mySQL table called "user" that contains a userid and a password or something. Then I have other tables for different purposes, such as a table for their favorite food, which would contain their userid and favorite food.
Is there a way to query for tables that contains a specified userid and checks whether they have an entry in that table?
So if I have three tables called favorite_food, favorite_drink, and favorite_candy, but userid only had values in favorite_food and favorite_drink, I want the query to return favorite_food and favorite_drink.
I'm a beginner and I couldn't quite grasp the concept of linking. Userid is the primary key of user and the other tables reference it?
Read more about UNION. I think that this is what you need.
SELECT * from favorite_food where `userid` = 50
UNION
SELECT * from favorite_drink where `userid` = 50
UNION
SELECT * from favorite_candy where `userid` = 50
In SQL "linking" is represented by JOINs. Since (as you indicated) some users will not have 1 or 2 favorite objects we will need to use LEFT OUTER JOINs. Then we will have NULLs in the output in place of missing favorites.
In your case:
SELECT u.userid, f.food_name, d.drink_name, c.candy_name
FROM user u
LEFT JOIN favorite_food f ON u.userid=f.userid
LEFT JOIN favorite_drink d ON u.userid=d.userid
LEFT JOIN favorite_candy c ON u.userid=c.userid
ORDER BY u.user.id
This will give you favorites for all users in your user table.
It's my first time with mysql and I need some help. I couldn't find any solution to this probably because it's too easy or I'm too noob to look it up properly yet.
I want to make a query from multiple tables from my test database. Let's say tables are:
category (*id_category, *id_product)
product (*id_product, id_category, id_supplier, id_manufacturer)
manufacturer (*id_manufacturer, name)
supplier (*id_supplier, name)
The columns with * are integer primary key not null with auto_increment(starting from 1). The other id columns are just integer foreign keys(default null).
I need a query also including rows with null id_manufacturer and/or id_supplier on the product table. Those empty fields in the product table return value '0', so when I make a query like
SELECT category.id_product, manufacturer.name, supplier.name
FROM category, product, manufacturer, supplier
WHERE category.id_category = product.id_category AND manufacturer.id_manufacturer = product.id_manufacturer AND supplier.id_supplier = product.id_supplier;
None of the rows with null values(0)are shown.
I'd like you to point me in the most clean and efficient way to do it without changing table properties. Any help would be very much appreciated.
You need to use Left Join then.
SELECT category.id_product, manufacturer.name, supplier.name, P.ID_PRODUCT
FROM product
LEFT JOIN category C
ON C.id_category = P.id_category
LEFT JOIN manufacturer M
ON M.id_manufacturer = P.id_manufacturer
LEFT JOIN supplier S
ON S.id_supplier = P.id_supplier;
These will give all the rows of product table even if it has no corresponding row from other tables.