How To: Insert into column where the value is on another table - mysql

Summarize the Problem:
I want to write a booking code. I had a little problem, that I wanted to insert a value into the booked table that is in another table called house_info.
The detail of booked & house_info database is below:
Booked Table
ID_Booking | House_Name | House_ID | House_No | House_Qty | House_Price |
1 | Rose House | 1 | RH01 | 1 | |
2 | Rose House | 1 | RH02 | 1 | |
House Info Table
House_ID | HouseState_Name | House_Qty | House_Price |
1 | Garden City | 8 | 40000|
2 | Electronic City | 10 | 1000000|
I want to insert the House_Price value on the house_info table into the House_Price column on booked table every time users input on the Booking Form.
Background you've already tried:
I already tried this using a trigger on booked table like below:
Trigger on Booked Table (Before Insert)
IF NEW.House_ID= '1' THEN SET
NEW.House_Price = 40000;
ELSEIF NEW.House_ID= '2' THEN SET
NEW.House_Price = 1000000;
But I realize this is not dynamic because when the company want to change the price of each HouseState_Name he needs to change it from the trigger. So I think what I needed is a query from PHP that can calls the value of each HouseState_Name and hold it on an array and place it or insert it when the Book Query passed (I hope my logic is true, I'm sorry if it's false).
I already tried to search too for the query's to use. But I didn't know how am I going to use the query.
Some Codes:
Booking.php
require 'Connection.php';
//Check Connection
if ($conn->connect_error){
die("Connection Failed: ". $conn->connect_error);
}
//Check for Submit
if (filter_has_var(INPUT_POST, 'Submit')) {
//Get Form Data
$CustomerEmail= htmlspecialchars($_POST["Email"], ENT_QUOTES);
$House_Name= htmlspecialchars($_POST["HouseName"], ENT_QUOTES);
$House_ID = htmlspecialchars($_POST["HouseID "], ENT_QUOTES);
$House_No = htmlspecialchars($_POST["HouseNo "], ENT_QUOTES);
//Validate the data fields
if (!empty($CustomerEmail) && !empty($House_Name)) {
//Passed
if (filter_var($CustomerEmail, FILTER_VALIDATE_EMAIL) === false) {
//Failed
$msg = 'Please use a valid email';
header("location: ../GardenCity.php?error=PleaseUseValidEmail");
} else {
//Passed
echo "Creating a Booking.<br>";
//Inserting the Booking Data into Database
$sql = "INSERT INTO `booked`(`ID_Booking`, `CustomerEmail`, `House_Name`, `House_ID`, `House_No`)
VALUES (NULL, '$CustomerEmail', '$House_Name', '$House_ID ', '$House_No', '', '')";
if ($conn->query($sql) === TRUE) {
header("location: ../GardenCity.php");
} else {
echo "Error: " . $sql . "<br><br>" . $conn->error;
}
}
} else {
header("location: ../GardenCity.php?error=EmptyFields");
}
}
$conn -> close();
Expected Results:
Before Update the price
Database Looks
ID_Booking | House_Name | House_ID | House_No | House_Qty | House_Price |
1 | Rose House | 1 | RH01 | 1 | |
2 | Rose House | 1 | RH02 | 1 | |
3 | Rose House | 1 | RH03 | 1 | 40000|
House_ID | HouseState_Name | House_Qty | House_Price |
1 | Garden City | 7 | 40000|
2 | Electronic City | 10 | 1000000|
After Update the price
Database Looks
ID_Booking | House_Name | House_ID | House_No | House_Qty | House_Price |
1 | Rose House | 1 | RH01 | 1 | |
2 | Rose House | 1 | RH02 | 1 | |
3 | Rose House | 1 | RH03 | 1 | 40000|
4 | Rose House | 1 | RH04 | 1 | 200000|
House_ID | HouseState_Name | House_Qty | House_Price |
1 | Garden City | 6 | 200000|
2 | Electronic City | 10 | 1000000|
I hope this is well explained. Please let me know if there's any confusing statements or questions. I will say many thanks to you all if this is answered because I'm so stuck at this and my brain won't work.

I think this could work, basically using a subquery just to fetch the price, that should achieve the same result as your insert trigger, but without using fixed prices.
INSERT INTO `booked` (
`ID_Booking`,
`CustomerEmail`,
`House_Name`,
`House_ID`,
`House_No`,
`House_Qty`,
`House_Price`
) VALUES (
NULL,
'$CustomerEmail',
'$House_Name',
'$House_ID',
'$House_No',
'1',
(SELECT House_Price FROM house_info WHERE House_ID = '$House_ID')
)
Edit: I set House_Qty at 1, change it according to your needs :)
Maybe you can use the same subquery in your trigger directly instead (haven't tested it) :
SET NEW.House_Price =
(SELECT House_Price FROM house_info WHERE House_ID = NEW.House_id);
Assuming your House_ID are unique :)

I would expect to see a schema more or less like this:
houses(house_id*,name)
house_prices(house_id*,price_start_date*,price)
bookings(booking_id*,customer_id,total)
booking_detail(booking_id*,house_id*,start_date,end_date)
* = (component of) PRIMARY KEY
After some reflection, it should be apparent that your present concerns evaporate with this design.

Insert Into booked_table (ID_Booking, House_Name, House_Id, House_No, House_Qty, House_Price)
Select 1, House_Name, House_ID, 'RHXX', House_Qty, (SELECT House_Price FROM house_info WHERE House_ID = MM1.House_ID) From booked_table MM1
Where
NOT EXISTS(
SELECT *
FROM booked_table MM2
WHERE MM2.ID_Booking > MM1.ID_Booking
);
Fiddle: https://www.db-fiddle.com/f/7Bt3ZTQqbjs1jKzJe34qSF/0
I dont included the increment of the ID_Booking and House_No.
If you want to increase the House_Price, just do that with another query.

You can construct such an UPDATE statement with INNER JOINs one of which's in the subquery as a self-JOIN for booked table, put after your existing INSERT statement :
update house_info h join (
select b1.House_Price, b2.House_ID
from booked b1
join ( select House_ID,max(ID_Booking) as ID_Booking
from booked
group by House_ID
) b2
on b1.House_ID = b2.House_ID and b1.ID_Booking = b2.ID_Booking
) bb on bb.House_ID = h.House_ID
set h.House_Price = bb.House_Price;
but I should admit that your tables' design is not good, because of repeating columns they hold the same information in each.
Demo

Related

How can I insert data to table B with more columns than table A with the same ID (ID matches from both tables)?

So here is my problem, how can i do this :
user with ID = 7 from table A with 3 columns want to insert data to table B with 4 columns but with the same id.
Table A :
| Id | name | password |
| 7 | john | password |
| 9 | mark | password |
| 12 | yuta | password |
Table B :
| Id | user_id | food | drink |
| 1 | 7 | oats | milk |
| 2 | 9 | fish | water |
| 3 | 12 | pear | fanta |
How can i achieve table b in 1 query? both id in both table are primary keys and im using mysql
here's the code i was trying to do :
INSERT INTO table_b SET food = :food, drink = :drink, ( user_id) SELECT a.id FROM table_a u WHERE EXISTS (SELECT * WHERE name = :name AND password = :password)
i know the query is wrong but thats the closest i can do. pls help thank you
You should just use a unique code to link them together.
you can have the code stored in a variable like this
$unique = time().rand(1000, 9999);
//You should have something like this 16659154332358
Create a column that will recieve this value in your database.
Now they have a relationship

Insert concatenated values from multiple rows as new row in MySQL query

I currently have a table with columns for "field_type" (username, city, state), "user_id", and "value". The user_id column obviously has lots of repeats. I'd like to merge the city and state data into a single "location" field_type value. I need something that will:
for every integer in the user_id column:
-check if there exist corresponding (not null) table rows for field_type "city" and "state"
-if yes, insert a new row into the table with field_type "location" which concatenates the corresponding city and state values for that user_id
I haven't worked with MySQL much so I don't really know where to start. I've tried to simplify the problem a bit - it's actually a somewhat more complicated wordpress table and I'm trying to reformat the data to be compatible with a new plugin, but this covers the basics of what has to happen so I should hopefully be able to extrapolate an actual solution from the answers. Thanks for any pointers!
Edit: Current structure looks like this:
|-id (key)-|- field_type -|- user_id -|- value -|
| 1 | username | 1 | Joe |
| 2 | city | 1 | Albany |
| 3 | state | 1 | NY |
| 4 | username | 2 | Bob |
| 5 | city | 2 | Toledo |
| 6 | state | 2 | OH |
And I would like to get something like this:
|-id (key)-|- field_type -|- user_id -|- value ---------|
| 1 | username | 1 | Joe |
| 2 | city | 1 | Albany |
| 3 | state | 1 | NY |
| 4 | username | 2 | Bob |
| 5 | city | 2 | Toledo |
| 6 | state | 2 | OH |
| 7 | location | 1 | Albany, NY |
| 8 | location | 2 | Toledo, OH |
Duplicate user_id values are how it's supposed to work, so they don't need to be removed.
You could use an INSERT ... SELECT query to do this:
INSERT INTO yourtable
SELECT 'location' AS field_type, t1.user_id, CONCAT(t1.value, ' ', t2.value) AS value
FROM yourtable t1
JOIN yourtable t2 ON t2.user_id = t1.user_id AND t1.field_type = 'city' AND t2.field_type = 'state'
WHERE t1.value IS NOT NULL AND t2.value IS NOT NULL
Demo on dbfiddle
Since you are mentioned that there are duplicates with the same user_id.
I don't think inserting a new row will be a good idea.
So have written an update query to update the existing data.
You can later cleanup the duplciates.
UPDATE your_table SET locations = CONCAT_WS('-', state, city) where city is not null or state is not null

How to design schema, display a message to it's owner, but if owner is unspecified, display to all user?

I have the schema like this,
message
+------------+----------+
| id | text |
+------------+----------+
| 1 | message1 |
| 2 | message2 |
| 3 | message3 |
+------------+----------+
user_message
+------------+-------------+
| user_id | message_id |
+------------+-------------+
| 1 | 1 |
| 1 | 2 |
| 2 | 2 |
+------------+-------------+
because the message3 is no owner, it owned to all user.
So, the user1 has message1, message2 and message3,
the user2 has message2 and message3.
And I need write the sql to query user1's messages,
SELECT
*
FROM
message AS a
JOIN
user_message AS b ON a.id = b.message_id AND b.user_id = 1
UNION ALL
SELECT
*
FROM
message AS a
LEFT JOIN
user_message AS b ON a.id = b.message_id
WHERE
b.user_id IS NULL
Does this design correct?
Or I should add the message3 to all users, like this?
+------------+-------------+
| user_id | message_id |
+------------+-------------+
| 1 | 1 |
| 1 | 2 |
| 2 | 2 |
| 1 | 3 |
| 2 | 3 |
+------------+-------------+
But if I have a new user, I wish the new user own message3, I need to write extra code to do this.
How do I do it correctly?
EDIT:
I made a mistake above, I lost a case is one user can has many messages.
As suggested by Neville Kuyt.
I like the "no surprises".
And I change the column name and schema to
message
+------------+----------+
| id | text |
+------------+----------+
| 1 | message1 |
| 2 | message2 |
| 3 | message3 |
+------------+----------+
user_message
+------------+-------------+-------------+
| id | user_id | message_id |
+------------+-------------+-------------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 2 |
| 4 | null | 3 |
+------------+-------------+-------------+
Now, the query will be
SELECT
*
FROM
user_message AS a
JOIN
message AS b ON a.message_id = b.id
WHERE
user_id = 1 OR user_id IS NULL;
"Correct" is a tricky thing to get right in schema design. I generally favour the "no surprises" approach - someone should be able to understand what's going on by looking at the schema and the data, without reading the documentation. I also favour "don't repeat yourself".
You offer two candidate solutions.
The first solution contains a surprise - columns with the name "id" are usually the primary key for a table; in this case, the "id" column is actually a foreign key to the "users" table. To reduce this level of surprise, I'd create the column "user_id" to contain the foreign key. If "user_id" is also the primary key in your business domain, you can just rename the column.
The second surprise is that the column contains foreign key data to the user table which don't exist, but which invoke special behaviour - they are sent to all users. A less surprising solution would be for that value to be "null", rather than a non-existent value. When you create user 3, you update the appropriate record in message.
Your schema then becomes
message
+----------------+----------+
| id |user_id | text |
+-------+--------+----------+
| 1 | 1 | message1 |
| 2 | 2 | message2 |
| 3 | null | message3 |
+-------+--------+----------+
Your second option contains another surprise - data in "messages" changes as a side-effect of a change to "user" (when you create a new user, you have to delete all the messages to other users with the ID of that user). It has the benefit of being explicit - every message/user combination is stored, but I don't like the side-effect.
You can use exists and not exists:
select m.*
from message m
where exists (select 1
from user u
where u.message_id = m.id and
u.user_id = 1
) or
not exists (select 1
from user u
where u.message_id = m.id
);

How to insert data for one column for all the rows in single query in Mysql?

+----+------------+------------+------------+----------+
| id | phone_no | join_date | city | blood_gp |
+----+------------+------------+------------+----------+
| 1 | 80077672xx | 1997-07-19 | Delhi | NULL |
| 2 | 80077642xx | 1998-07-19 | New Delhi | NULL |
| 3 | 80477642xx | 1999-07-19 | Mumbai | NULL |
| 4 | 80077654xx | 1997-05-31 | Kolkata | NULL |
+----+------------+------------+------------+----------+
I want to enter all the blood groups at once . Is there a way to do so ?
you can use single query with select and update
UPDATE table1 , (SELECT * FROM table2 where 1) src
SET table1.blood_gp = src.filed2 where 1 ;
if you want to insert multiple row data using single query then use this code
INSERT INTO yourtable (x,y,z) VALUES (a1,a2,a3), (b1,b2,b3);
or if you want to update one column value all filed then use this code
update yourtable set blood_gp = 'yourvalue' where 1;
if any problem then inform me
Just make an update query without where clause.
update table set blood_gp = 'value'
That's generalize query.

mysql group rows in joined query

Im stumbling upon a problem where i need to retrieve data from the following tables
events
+-------+---------+---------+
| e_id | e_title | e_link |
+-------+---------+---------+
| 1 | Event 1 | event_1 |
| 2 | Event 2 | event_2 |
| 3 | Event 3 | event_3 |
| 4 | Event 4 | event_4 |
| 5 | Event 5 | event_5 |
+-------+---------+---------+
reservations
+-------+---------+---------+
| r_id | r_e_id | r_u_id |
+-------+---------+---------+
| 1 | 2 | 1 |
| 2 | 2 | 3 |
| 3 | 5 | 4 |
| 4 | 2 | 4 |
| 5 | 1 | 1 |
+-------+---------+---------+
users
+-------+---------+----------+
| u_id | u_name | u_gender |
+-------+---------+----------+
| 1 | One | Male |
| 2 | Two | Male |
| 3 | Three | Female |
| 4 | Four | Male |
| 5 | Five | Female |
+-------+---------+----------+
I want to display an event page with the users that are subscribed to that event, like follows:
Event 2
Users:
- One
- Three
- Four
I have the following query with the problem that this one only displays the first user (so in this case Four), which makes sense because the mysql_fetch_assoc() is not in a while() loop.
$result = mysql_query("
SELECT events.e_title, reservations.*, users.u_name
FROM events
JOIN reservations
ON events.e_id = reservations.r_e_id
JOIN users
ON reservations.r_u_id = users.u_id
WHERE events.e_link = '".mysql_real_escape_string($_GET['link'])."'
");
$show = mysql_fetch_assoc($result);
What should i change in my query to make it work the way i want?
EDIT:
The solution from Teez works perfect, but wat if i want to attach more info, say for a link? My desired output is something like this:
Event 2
Users:
- User 1 Male
- User 3 Female
- User 4 Male
How am i going to achieve that? And eventually i even want to split the users by gender. So one list for females and one for males
SECOND EDIT:
I'm stunned with the result so far, but to complete it i want to sort the users by gender, like so:
Event 2
Users male:
- User 1 Male
- User 4 Male
Users female:
- User 3 Female
but how?
Best way will be first make a 2D array containing all events with respective users
Like below:
while( $show = mysql_fetch_assoc($result))
{
$events[$show['e_id']][]=$show['u_name'];
$uid[$show['e_id']][]=$show['u_id'];
}
Then loop arround above array for displaying :
foreach($events ad $key=>$users)
{
echo "Event ".$key."<br>";
echo "Users : <br>";
foreach($users as $ukey=>$name)
{
echo " -<a href='domain.com/user/".$uid[$key][$ukey]."'>".$name."</a>;
}
}
So with each call of mysql_fetch_assoc you want to have the event details and a list of usernames? In MySQL you can use GROUP_CONCAT for this purpose, although it is quite limited and error-prone. You should rather put mysql_fetch_assoc() in a loop to build an array of users. Anyway, here is the GROUP_CONCAT solution:
$result = mysql_query("
SELECT events.e_title, GROUP_CONCAT(users.u_name) e_reservation_users
FROM events
JOIN reservations ON events.e_id = reservations.r_e_id
JOIN users ON reservations.r_u_id = users.u_id
WHERE events.e_link = '".mysql_real_escape_string($_GET['link'])."'
GROUP BY 1
");
$show = mysql_fetch_assoc($result);
$show will then be
array('e_title' => '...', 'e_reservation_users' => '...,...,...').