SQL insert into select from multiple fields - php

I have a table 'users' with a column of 'ID'. I want to select 2 different 'ID's' based on 2 different parameters and insert them both into another table known as 'jobs'.
INSERT INTO jobs (customer_id, client_id)
SELECT id, id from users
WHERE username = ?
AND username = ?
Basically I want to get the ID of two different people and insert them both into the new table.
I would then bind the parameters to ?, and they would look something like 'john' and 'steve'. I have tried the code above but I know it is the wrong syntax. Any ideas would be greatly appreciated. Thanks

You could use a self-join:
INSERT INTO jobs
(customer_id, client_id)
SELECT customer.id, client.id
FROM users customer
JOIN users client ON customer.username = ? AND client.username = ?
Or, you could use subqueries:
INSERT INTO jobs
(customer_id, client_id)
VALUES (
(SELECT id FROM users WHERE username = ?),
(SELECT id FROM users WHERE username = ?)
)

Well, you could use subquerys
INSERT INTO jobs (customer_id, client_id)
VALUES (
(SELECT field from table where id = 2),
(SELECT field from table2 where id = 12)
)
I'm not pretty sure about the sintax, since I haven't tested, but I'm guessing it could solve it.
I often use such things in WHERE or in the SELECT statement. Just remember to return a single field and a single row in the subquerys.

Related

Mark all selected columns after SELECT Statement

I am selecting a random selection of a table and want to mark the selected columns. I have an 'exported' column which is binary and is set 0 by default. When selecting it I want it to become 1. I thought of combining a SELECT and INSERT statement like:
SELECT id, status, vorname, nachname, strasse, hnr, plz, ort, telefon1, telefon2
FROM adressen
WHERE (vorname LIKE ? OR nachname LIKE ?)
ORDER BY RAND() LIMIT ?
AND INSERT INTO adressen (exported) VALUES '1'
but this seems to be not the right approach. The select statement works perfectly fine just as I want it to be but I don't know how to set the exported column to 1 for every selected row. Since the data is selected randomly I can't just do an insert statement after it since it won't match the same selected ones.
Save the results in a temporary table and then use update:
CREATE TABLE temp_results AS
SELECT id, status, vorname, nachname, strasse, hnr, plz, ort, telefon1, telefon2
FROM adressen
WHERE (vorname LIKE ? OR nachname LIKE ?)
ORDER BY RAND()
LIMIT ?;
Then:
update adressen a join
temp_results r
on a.id = r.id
set exported = 1;
Note: This assumes that id is unique. If it is not, use the primary key on the table.
I also suspect that your query probably wants something like exported = 0.

How to update value when moving row to another table

I have 2 tables:
Table1
Table2
When I move a row from table1 to table2, I also want to update the datetime field and 1 more field.
Say both table have identical column like this:
id
shipped_by
datetime
other_column
I have the following sql line, but it is not working of course. But I want to have it something like that.
$query = "INSERT INTO table2
SELECT * FROM table1
WHERE id = '$id' UPDATE table2
SET shipped_by='$shipped_by', datetime='$datetime'";
The variable $shipped_by selects the userid, and $datetime date from now.
Can anyone help me with this sql code to make it work? I cannot figure it out.
Thank you.
To insert data form table1 with some column data modified can be done with insert and select without update.. select * should be used here, each column must be listed except for modified ones..
$query = "INSERT INTO table2
SELECT id, '$shipped_by', '$datetime', other_column FROM table1
WHERE id = '$id'";

How to UPDATE rows in one table where there duplictaes in another

I would be massively grateful if someone can help me write a query to update our orders system due to a dupe issue.
We have an orders table and a customers table.
I've identified some duplicate rows in our customers table where the email address and password are the same on unique rows - and are associated with unique live orders by CustomerNumber which exists in each table. This is bad as when a customer logs in to their account, they won't see all of their orders, rather they'll only see the orders associated with the highest customer ID (see login SQL below)
Identify duplicate user accounts:
SELECT
emailaddress,
PASSWORD,
count(*)
FROM
scustomers
JOIN orders ON orders.customernumber = customers.CustomerNumber
WHERE Completed = 1
GROUP BY
emailaddress,
PASSWORD
HAVING
count(*) > 1
Login SQL:
SELECT * FROM scustomers WHERE EmailAddress = :EmailAddress AND (Password = :Password) ORDER BY CustomerNumber DESC LIMIT 0,1
I need to write a query that:
Updates the "orders" table
Updates the "CustomerNumber" column
Sets the "CustomerNumber" column to be the highest "CustomerNumber"
WHERE the "customers" table has more than 1 rows with has an
identical "Email" and "Password" column
Where do I start?!
Our system has been fixed so that any customer order a new product by logging in will always use the highest possible associated CustomerNumber so this really is about fixing existing data.
UPDATE:
I've never used SQL Fiddle, but here is some sample data that I hope will help you.. help me!
CUSTOMERS:
customernumber, email, password
3272, jwilson#email.com, 9a098e0bade9b4f2ac4ecdf86111cf7e
10001, jwilson#email.com, 9a098e0bade9b4f2ac4ecdf86111cf7e
ORDERS:
ordernumber,customernumber,status
123457, 3272, 'LIVE'
123456, 10001, 'LIVE'
I need to update OrderNumber: 123457 to have the CustomerNumber of 10001, not 3272.
Step 1 : create a temporary column to store the correct CustomerNumber
ALTER TABLE scustomers
ADD COLUMN id_tmp INT NOT NULL;
Step 2 : retrieve the correct CustomerNumber
UPDATE scustomers
INNER JOIN
(
SELECT
emailaddress,
PASSWORD,
MAX(CustomerNumber) AS id
FROM
scustomers
GROUP BY
emailaddress,
PASSWORD
) AS duplicate ON scustomers.emailaddress = duplicate.emailaddress AND scustomers.PASSWORD = duplicate.PASSWORD
SET id_tmp = id;
Step 3 : update order table with the correct CustomerNumber
UPDATE orders
INNER JOIN scustomers ON orders.customerNumber = customers.CustomerNumber
SET orders.customernumber = id_tmp;
Step 4 : delete duplicate customers
DELETE FROM scustomers
WHERE customernumber <> id_tmp;
Step 5 : remove the temporary column
ALTER TABLE scustomers
DROP COLUMN id_tmp;
I am just giving idea about sql query you need to write for loop
SELECT GROUP_CONCAT( customernumber) , i.email
FROM scustomers i INNER JOIN ( SELECT k.email FROM scustomers k GROUP BY k.email
HAVING COUNT( `customernumber` ) >1 )j ON i.email = j.email GROUP BY i.email
Out put :
----------------------------
customernumber Email
---------------------------
1,2,3 ss#ss.ss
After this all duplicate will come in on field.explode the new customernumber get last value in that array (Ex: 3 is last value)
update `orders` set `customernumber`='last array value(Ex: 3)' WHERE `customernumber` in (customernumber from above query(1,2,3) )
For delete duplicate records
DELETE n1 FROM scustomers n1, scustomers n2 WHERE n1.customernumber< n2.customernumber AND n1.email= n2.email

Accessing Row from Mysql DB by chaining query of foreign key from another table

I'm having difficulty trying to find the best way to get my results from a table. I want to get the targeted row from a table by one using the primary key from another using a foreign key.
The tables are would be set similar to this(minus a lot of other attributes for space):
user Table:
user_Id(pk)
name
type
venue_Id(unique/indexed)
venue Table:
venue_Id(fk)
rating
Logic flow is: user_Id is provided by a session variable. Query DB table 'user' to find that user. Go to type of user to identify if user is person or venue. Assuming user is venue, go to DB table 'venue' and query table for rating using foreign key from unique/indexed venue_Id from user table.
The query looks like
SELECT rating FROM `venue` WHERE `user_Id` = '$user_Id' AND `type` = 'venue'
Is this possible, and if so, what is the correct way to go about it?
You have a few ways to retrieve this information.
Using JOIN:
SELECT v.rating
FROM venue v INNER JOIN user u
ON v.venue_id= u.venue_id
AND u.`user_Id` = '$user_Id' AND u.`type` = 'venue'
Using an IN sub-query
SELECT rating
FROM venue
WHERE venue_id IN (SELECT venue_id FROM user
WHERE `user_Id` = '$user_Id' AND `type` = 'venue')
BTW, you should consider protect your code from potential SQL Injections
Its a bit unclear you explained that way.
From what I get, there is 2 table User and Venue.
In User table u have: user_id, venue_id, name, type.
While in Venue table u have: venue_id, rating.
You are expecting to get rating (Venue Table) while you use the WHERE clause in user_id and type which both stored on User Table.
Your Query:
SELECT rating FROM venue WHERE user_Id = '$user_Id' AND type = 'venue'
It is impossible to get it done like above because you are selecting from venue table while user_id and type is not from venue table. So it will make it unidentified even you have chaining the FK. Because FK will only to show and make some constraint to parent child table.
The query should be something like this:
SELECT rating FROM venue v JOIN user u on v.venue_id = u.venue_id WHERE u.user_Id = '$user_Id' AND u.type = 'venue'
Correct me if I am wrong..
Combining rows from two tables based on the tables having columns with equal values is called an equi-join operation, it's the pattern we typically use to "follow" foreign key relationships.
As an example:
$sql = "SELECT v.rating
FROM `venue` v
JOIN `user` s
ON s.venue_Id = v.venue_Id
AND s.type` = 'venue'
WHERE s.user_Id` = '" . mysqli_real_escape_string($con, $user_Id) ."'"
This isn't the only pattern, there are several other query forms that will return an equivalent result.
As an example of using an EXISTS predicate:
$sql = "SELECT v.rating
FROM `venue` v
WHERE EXISTS
( SELECT 1
FROM `user` s
WHERE s.venue_Id = v.venue_Id
AND s.type` = 'venue'
AND s.user_Id` = '"
. mysqli_real_escape_string($con, $user_Id)
."'"
)";
The original query appears to be vulnerable to SQL Injection; the example queries demonstrate the use of the mysqli_real_escape_string function to "escape" unsafe values and make them safe to include in SQL text. (That function would only be appropriate if you are using the mysqli interface. Using prepared statements with bind placeholders is another approach.

update (or insert) multiple rows in one query

I am trying to update multiple rows in a table at once (or insert them if they do not exist) given settings and an array of user id's.
An example of how I select all rows from the settings table for all users of specific computers of a specific account. This is the result set which I need to insert values in or update if they exist.
$stmt = $db->prepare("
SELECT settings.*
FROM
( SELECT account_id, computer_id
FROM computers
ORDER BY computer_id ASC LIMIT 0, ".$_SESSION['user']['licenses']."
) as c
LEFT JOIN users
on users.computer_id = c.computer_id
LEFT JOIN accounts
on accounts.account_id = c.account_id
LEFT JOIN settings
on settings.user_id = users.user_id
WHERE accounts.account_id = ".$_SESSION['user']['account_id']."
");
What I am trying to do :
I am trying to update/insert three columns (enabled, status, and user_id) in the settings table for only those user ids listed in the array. Enabled and status values will be the same for all, but the user_id will be different for each.
$users = array(12, 36, 43, 56, 76)
$binding = array(
'enabled' => 1,
'status' => 2,
'user_id' => from the array
);
If my thought process is correct I can create a virtual table from my statement listed above then use ON DUPLICATE KEY UPDATE to insert/update on the results of that virtual table?
Is this possible? If so, example, tips, or point in the right direction? The way I have working involves a foreach loop for each user id in the given array so there will be x number of queries depending on its count. If I can cut that to only one that would be great!
UPDATE:
Ok, I am totally confused now... this is an attempt for defined values which is not working... and I still need a way to do so for every user_id in my array as mentioned above. Don't I need to 'save' my entire FROM clause AS a new reference as well?
$stmt = $db->prepare("
INSERT INTO settings (user_id, enabled, status)
VALUES (:user_id, :enabled, :alert_user)
SELECT user_id, enabled, status
FROM
( SELECT account_id, computer_id
FROM computers
ORDER BY computer_id ASC LIMIT 0, ".$_SESSION['user']['licenses']."
) as c
LEFT JOIN users
on users.computer_id = c.computer_id
LEFT JOIN accounts
on accounts.account_id = c.account_id
LEFT JOIN settings
on settings.user_id = users.user_id
WHERE accounts.account_id = ".$_SESSION['user']['account_id']."
ON DUPLICATE KEY UPDATE enabled = VALUES(enabled), status = VALUES(status)
");
$binding = array(
'enabled' => 1,
'alert_user' => 4,
'user_id' => 6
);
$stmt->execute($binding);
Yes, your thinking is correct. It should be something like this:
INSERT INTO settings (user_id, enabled, status)
SELECT user_id, enabled, status
FROM ... -- rest of your query here
ON DUPLICATE KEY UPDATE enabled = VALUES(enabled), status = VALUES(status)
VALUES(colname) in the ON DUPLICATE KEY UPDATE clause gets the value that would have been inserted if there hadn't been a dupliate.
OK, based on your comment, I think this may be what you want:
INSERT INTO settings (user_id, enabled, status)
SELECT :user_id, :enabled, :status
FROM ...
JOIN ...
JOIN ...
WHERE ...
ON DUPLICATE KEY UPDATE enabled = VALUES(enabled), status = VALUES(status)
If the join returns any rows, this will insert or update the specified row. If it doesn't find any rows, no insert/update will be done.
You should probably be using inner joins rather than left joins, if you don't want anything returned when there are no matches in the tables being joined with.

Categories