Insert Select Query - mysql

I have 2 tables articles and users.
I want to insert title, content and name into the article table.
I have the the users id stored in a session, is there a way using an insert select query to add title, content and name to the article table whilst getting the name from the users table using the id.
Something like:
INSERT INTO article (title, content, name) VALUES ($post['title'], $post['content'], name) SELECT name FROM users WHERE id = mySessionId

use INSERT INTO..SELECT statement,
$title = $post['title'];
$content = $post['content'];
$insertStatement = "INSERT INTO article (title, content, name)
SELECT '$title', '$content', name
FROM users
WHERE id = mySessionId";
As a sidenote, the query is vulnerable with SQL Injection if the value(s) of the variables came from the outside. Please take a look at the article below to learn how to prevent from it. By using PreparedStatements you can get rid of using single quotes around values.
How to prevent SQL injection in PHP?

Related

INSERT INTO with joins?

I got trouble inserting data to a table that has joins to other tables, I've never done that before and the searchs I went through didn't help much.
I have an article page with a "comment" form that I want to send to my "comment" table. The "comment" table has joins with my "user" and "article" tables (to get which article the comment is part of, and which user sent it)
My comment table columns : comment_id, article_id, author_id, submitted_at, content
My user table columns :
user_id, username, password
My article table columns : article_id, preview_image, title, description, body, publishedAt, author_id
So this is what my query looks like :
public function setComment() {
try{
$stmt = $this->connection()->prepare("INSERT INTO comment (article_id, author_id, submitted_at, content) (SELECT comment.article_id, comment.author_id, submitted_at, content
FROM comment INNER JOIN user ON comment.author_id = user.user_id INNER JOIN article ON comment.article_id = article.article_id)");
$stmt->bindParam(':article_id', $_GET['id'], PDO::PARAM_INT);
$stmt->bindParam(':author_id', $_GET['id'], PDO::PARAM_INT);
$stmt->bindParam(':content', $_POST['comment'], PDO::PARAM_STR);
$stmt->execute();
} catch (PDOException $e){
echo $e->getMessage();
}
}
Well there is no error.... the only problem here is, when I submit my form all my rows in the comment table are duplicated by 2 lol... I just want to add a new row with the data in my bindParam()
So what's wrong?
BY THE WAY during my searchs I've seen people don't specify VALUE() when inserting to a table that has joins. So how do I insert the data that are in my bindParam()? That's weird
EDIT :: FOUND IT!! Actually I didn't need to use a SELECT at all
The correct query was :
INSERT INTO comment (article_id, author_id, submitted_at, content)
VALUES (:article_id, :author_id, NOW(), :content)
I had an error telling me "SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails"... So I thought I needed to join the tables or something but the actual problem was because in my query I bound the author_id to $_GET['id'] (that was 9)... and there is no user with the id of 9 in my user table. Shame on me
I used $_GET['id'] because I don't know how to properly get the id of the user sending the comment (and bindParam doesn't like it when I just use an integer)... with the session maybe idk, but that's a problem for another time

Adding constrains to data inserted in a MySQL table

I have a mysql database that is represented in this ER-Diagram. I want to add a constrain when I create ConcertSongs table that says: 'Don't allow adding songs to a concert whose band did not sing this song'. How can I do that?
Any help is appreciated!
If you are trying to input by relating song to band do this:
INSERT INTO ConcertSongs (SongID, ConcertID) SELECT AlbumSOngs.SongID, Concert.ConcertID WHERE ConcertSongs.SongID = AlbumSongs.SongID AND AlbumSongs.AlbumID = Albums.AlbumID;
If you are relating to concert ID also then you will need to Alias in a CASE like this:
SELECT col1, col2, etc. (case when (state1 = '' and state2 = '')
THEN
//new SQL
ELSE
//SQL
END)
as state from table;
Depending on how you complicated your tables i advice adding new columns to use for relating them to each other, this would decrease SQL run time, and make it easier for you.

mysql insert with value, with selected data from another table

I have a MySQL problem I can not get to solve. I have a mysql to manage a virtual user dovecot installation, that uses two tables (one for the aliases, another for the domains).
The table aliases has these fields: domain_id(INT), source(VARCHAR), destination(VARCHAR), whereas table domains has only two fields: id (INT AUTO INC) and name (VARCHAR).
Although I'm able to select aliases that belong to a given domain by issuing:
SELECT valias.* FROM aliases AS valias
JOIN domains AS vdomains ON valias.domain_id=vdomains.id
WHERE vdomains.name = "domain_name";
I can not get to work to insert a new alias, specifing the domain name. something like this:
INSERT INTO valias(domain_id, source, destination)
VALUES (id, 'canto', 'george')
SELECT id FROM aliases
JOIN domains AS vdomains ON aliases.domain_id=vdomains.id
WHERE vdomains.name = "domain_name";
Does somebody know how to solve this problem?
My experience is mainly in MS SQL Server, but I reckon it should go the same way in MySQL:
INSERT INTO valias(domain_id, source, destination)
SELECT id, 'canto', 'george' FROM vdomains
WHERE name = 'domain_name';
Either I'm missing something here or your query seems a bit to overingeenered. How about this:
INSERT INTO aliases(domain_id, source, destination)
VALUES (id, 'canto', 'george')
JOIN domains ON domains.id = aliases.domain_id
WHERE domains.name = 'domain name'
Try this,
INSERT INTO valias(domain_id, source, destination)
SELECT id,'canto', 'george'
FROM aliases
JOIN domains AS vdomains
ON aliases.domain_id=vdomains.id
WHERE vdomains.name = "domain_name";

MySql - Best way to do this kind of query

I need to return a single row with some datas taken from some tables not related each others.
So, for example, my actual queries are these (I done it trought a PHP script) :
$query=mysql_query("SELECT trackid FROM tracklist WHERE usersub='".$_SESSION['nickname']."'",$mydb);
echo mysql_num_rows($query);
$query=mysql_query("SELECT trackid FROM comments WHERE usercom='".$_SESSION['nickname']."'",$mydb);
echo mysql_num_rows($query);
$query=mysql_query("SELECT vote FROM vote WHERE uservote='".$_SESSION['nickname']."'",$mydb);
echo mysql_num_rows($query);
$query = mysql_query("SELECT datereg FROM users WHERE nickname='".$_SESSION['nickname']."'",$mydb);
echo mysql_result($query,0,'datereg');
But this will call the MySql server 4 times.
Whats your suggestion to better this situation?
If the tables are not related then you will have to make 4 seperate calls
If the tables COULD be related by foreign keys then you could join them in some way and possibly cut down your sql calls
Ultimately though if you need all of the data then you'll have to request it from the database
You could use a UNION. And, btw, mysql_result is poor. And FFS don't forget to sanitize your inputs!
<?php
$nickname = mysql_escape_string($_SESSION['nickname']);
$sql = "
SELECT COUNT(trackid) AS n FROM tracklist WHERE usersub='{$nickname}'
UNION
SELECT COUNT(trackid) FROM comments WHERE usercom='{$nickname}'
UNION
SELECT COUNT(vote) FROM vote WHERE uservote='{$nickname}'
UNION
SELECT datereg FROM users WHERE nickname='{$nickname}'
";
$result = mysql_query($sql, $db);
while ($row = mysql_fetch_assoc($result)) {
echo $row['n'];
}
?>
I wouldn't really recommend this as it's a bit of a mess combining "count" values with a date in the same column, but you can do it. It's the direct answer to your question.
Well, you could create a fifth table and use it as an index.
If all the values { trackid, vote, datareg } are integers, the index table could contain three columns - nickname, value, and table. When you add records to one of the other tables, add a corresponding record to the index table.
For example,
INSERT INTO vote (vote, uservote, ...) VALUES (123, 'abc', ...);
INSERT INTO myindex (nickname, nvalue, ntable) VALUES ('abc', 123, 'vote');
(I wouldn't actually store the table name as a string but as a numeric value, but you get the idea)
Then on a query, you just SELECT nvalue, ntable FROM myindex WHERE nickname = 'abc';
You will possibly get more than one row.
I think that this is a lot of work and you are better off sticking with the four original queries.
Have you tried combining the select statement together like
SELECT .. Actually.
Maybe you should normalise your database and set up links between your tables...
Edit :: And i'm not sure how you're preparing yourself against mysql injection, but be careful with where your $_SESSION[] comes from
If all the selects return a single row:
$query=mysql_query("
(SELECT trackid FROM tracklist WHERE usersub='".$_SESSION['nickname']."'") as tracklist,
(SELECT trackid FROM comments WHERE usercom='".$_SESSION['nickname']."'") as trackid,
(SELECT vote FROM vote WHERE uservote='".$_SESSION['nickname']."'") as vote,
(SELECT datereg FROM users WHERE nickname='".$_SESSION['nickname']."'") as datereg
"

MySQL Insert Select

Ran into a bit of trouble when trying to insert records into my DB from my forum
What it does when you create a thread is make an entry into 2 tables. First the forum_threads table with information on the thread title, description, poster, post time, etc. It will use thread_id with AUTO_INTEGER to generate the threads ID.
I then need to get that thread_id from the forum_threads and then put that as the thread_id in the forum_posts table.
I'm not sure if theres anyway I can select a row based on its ID after I just inserted it. Would I just have to select the most recent ID? Would that leave a margin of error? Other thought I had was to select based on user name and post time.
Thoughts?
<?php
if (isset($_POST['submit'])) {
$thread_sql = "
INSERT INTO forum_threads (
user_id,
forum_id,
thread_postdate,
thread_title,
thread_description,
thread_icon
) VALUES (
'$_SESSION[user_id]',
'$_GET[f]',
'$date',
'$_POST[topictitle]',
'$_POST[topicdescription]',
'$_POST[posticon]'
)
";
$thread_query = #mysqli_query ($db_connect, $thread_sql);
$post_sql = "
INSERT INTO forum_posts (
user_id,
thread_id,
post_message,
post_date
) VALUES (
'$_SESSION[user_id]',
'',
'$_POST[content]',
'$date'
)
";
$post_query = #mysqli_query ($db_connect, $post_sql);
}
?>
To first answer your question directly, the function mysql_insert_id() will return the ID that was assigned to the most recently inserted row. There's no guesswork involved; MySQL will happily tell you (through its own built-in LAST_INSERT_ID() function) what ID it assigned.
On a separate note, I see that you're directly inserting values from $_POST into your SQL statement. Never, ever, EVER do that. This exposes your application to SQL injection attacks.
Either use the mysql_real_escape_string() function to properly escape the values for use in a SQL statement, or, since you're already using mysqli_ functions, use placeholders (? values) to create a prepared statement.
MySqli_Insert_Id () will return the last auto generated ID. Call this function immediately after you insert your new thread.
INSERT
INTO forum_threads (…)
VALUES (…)
INSERT
INTO forum_posts (thread_id, …)
VALUES (LAST_INSERT_ID(), …)
You can just use the last_insert_id to get the ID of the row you just inserted; don't worry about anybody else inserting a row just after, the last_insert_id is per-connection, so unless they used your connection, you're safe.
There is an API-level call to retrieve this so you don't need to ask the server specifically.
Oh yes, also, do not use the # operator in PHP, ever, google for it if you want to know why it's bad.
Use MySQL's last_insert_id() function in sql code or the php wrapper for it mysql_insert_id() in a php script. These will give you the last auto_increment number generated in your connection. So it's thread safe.