I have a table topics. And I have two queries which select different data, one for the table votings and one from the table messages. topics has a field m_group which is a foreign key for messages. This field can either be NULL or a group for entries in messages (group is a field in this table). If this field is set to a group, it should perform query 1 to select all messages or if it is not set it should perform query 2 to select all votings for this specific topic. I'm using Postgres and PHP on an Apache Webserver.
Now my question is what is the recommended way to go. I came up with two solutions (not sure if solution 2 is actually possible, haven't tried it yet).
Solution 1
First select the field m_group. Then determine if it is set via PHP and perform the associated query.
Solution 2
Use a IF THEN ELSE statement
Basically the query should then look something like this
IF t.m_group IS NULL
THEN
query2
ELSE
query1
As already mentioned, I'm not sure if solution 2 is possible. What would be the best way to handle this? Solution 1 performs two queries, I think this is inefficient.
UPDATE
As mentioned above, it should perform the queries for a specific topic. You have the id of this topic. How can you specify this in solution 2? And does the IF THEN ELSE statement already know the alias t for topics, if that is specified in the queries?
If I understand you right, you need to use two subqueries as sets of data, while you should use one of them as a source depending on what's in the m_group field. Your second approach is good if you only select a few rows. However, if you need to grab a lot of data from the table, this way you will need to perform too many subqueries. I would rather first grab all the data you need from topics and then select what you need with both queries.
Pseudo SQL query will look like that:
with t1 as (select t.id, group_m, ... from topics t where t.m_group is not null),
t2 as (select t.id, ... from topics t where t.m_group is null)
select id, title, SUM(subtable_id) AS votes
from query1
join t1 on t1.id = query1.id and...
union
select id, title, SUM(subtable_id) AS votes
from query2
join t2 on t2.id = query2.id and...
Related
First table:
Second table:
In the first Table, there will be multiple given_to with same taskid, and specific to that taskid i have set task in 2nd table.
Is it possible to obtain the task of a same taskid from multiple users to be printed in a table? If so How can we achieve it?
If possible, I also want to print the columns given_to of the task seperated by space.
Please Help
I'm not exactly sure I understood correctly what you want as a result, but as far as I get it you can achieve this with the correct SQL query, using a simple left join:
SELECT * FROM table1 LEFT JOIN table2 ON table1.taskid = table2.id
You might want to replace the SELECT * FROM ... part with the specific fields you are interested in.
For more information about joins (that is: merging results/columns from several tables into one query result) take a look at the MySQL reference manual on JOIN syntax.
I have two tables : items and comments.
I want to select all items which a user commented on.
For simplicity, lets assume the items table has two columns : item_id and item_content. Let the comments table have 3 columns user_id, item_id and comment_content.
I am given the user_id of the commenting user, I need to first select all the item_id from the comments table, where user_id = myUserId.
This is a basic query SELECT item_id FROM comments WHERE user_id = '$myUserId'.
Then I need to select the item_content for each item_id returned by the previous query.
I was thinking of doing a while($row = $my_first_query->fetch_array()) loop, and inside of it doing something like SELECT item_content FROM item WHERE item_id = $row["item_id"]
however this is a bit messy and I was wondering if there was a simpler way of doing this, by combining the two queries into one.
Use an INNER JOIN:
SELECT t1.*
FROM items t1
INNER JOIN comments t2
ON t1.item_id = t2.item_id
WHERE t2.user_id = myUserId
The approach you suggested of first querying the comments table and then looping over the result set is inefficient. In a join, MySQL can handle this algebra much faster than your PHP code.
Depending of what you want to do exactly, you can just use a JOIN clause. The "header" table info will be found within all rows, so it might not be what you want to do.
Another way would be to run two distinct queries, the first one unchanged and the second one with a join. You would then have one result with the header, and the other with all the details that you could go through. It's more performant than run the same query over and over network wise.
I have two tables: "users" and "posts." The posts table has a 'post' column and a 'poster_id' column. I'm working on a PHP page that shows the latest posts by everyone, like this:
SELECT * FROM posts WHERE id < '$whatever' LIMIT 10
This way, I can print each result like this:
id: 43, poster_id:'4', post: hello, world
id: 44, poster_id:'4', post: hello, ward
id: 45, poster_id:'5', post: oh hi!
etc...
Instead of the id, I would like to display the NAME of the poster (there's a column for it in the 'users' table)
I've tried the following:
SELECT *
FROM posts
WHERE id < '$whatever'
INNER JOIN users
ON posts.poster_id = users.id LIMIT 10
Is this the correct type of join for this task? Before learning about joins, I would query the users table for each post result. The result should end up looking similar to this:
id: 43, poster_id:'4', name:'foo', post: hello, world
id: 44, poster_id:'4', name:'foo', post: hello, ward
id: 45, poster_id:'5', name:'fee', post: oh hi!
etc...
Thanks for helping in advance.
WHERE clause must come after the FROM clause.
SELECT posts.*, users.* // select your desired columns
FROM posts
INNER JOIN users ON posts.poster_id = users.id
WHERE id < '$whatever'
LIMIT 10
the SQL Order of Operation is as follows:
FROM clause
WHERE clause
GROUP BY clause
HAVING clause
SELECT clause
ORDER BY clause
UPDATE 1
For those column names that exists on both tables, add an ALIAS on them so it can be uniquely identified. example,
SELECT post.colName as PostCol,
users.colName as UserCol, ....
FROM ....
on the example above, both tables has column name colName. In order to get them both, you need to add alias on them so in your front end, use PostCol and UserCol to get their values.
Try:
SELECT *
FROM posts
INNER JOIN users ON posts.poster_id = users.id
WHERE posts.id < '$whatever'
LIMIT 10
Got the syntax a little incorrect.
Should be
SELECT * FROM posts
INNER JOIN users ON posts.poster_id = users.id
WHERE id < '$whatever' LIMIT 10
The answers already given tell you the main reason for your query not working at all (ie the WHERE clause should come after the JOIN clauses), however, I'd like to make a couple of additional points:
I would suggest using an OUTER JOIN for this. It probably won't make much difference, but in the event of a post record having an invalid poster_id, an INNER JOIN will mean the record is dropped from the results, whereas an OUTER JOIN will mean that the record is included, but the values from the users table will be null. I imagine you don't want to ever have an invalid poster_id on the posts table, but broken data does happen even in the best regulated system, and it is helpful in these cases to still get the data from the query.
I would strongly suggest not doing SELECT *, and instead itemising the fields you want to get back from the query. SELECT * has a number of problems, but it's particularly bad when you have multiple tables in the query, because if you have fields with the same name on both tables, (eg id), then it becomes very hard to distinguish which one you're working with, as your PHP recordset won't include the table reference. Itemising the fields may make your query string longer, but it won't make it any slower - if anything it'll be quicker - and it will be easier to work with in the long run.
Neither of these points are essential; the query will work without them (as long as you switch the WHERE clause to after the JOIN), but they may improve your query and hopefully also improve your understanding of SQL.
I've been scratching my head at this problem all day and I simple just can't work it out. This is the first time I've attempted to try and use SQL Joining, while we do kinda get taught the basics I'm more into pushing a little more into the advanced stuff.
Basically I'm making my own forum, and I have two tables. f_topics (The threads) and f_groups (The forums, or categories). There is a relationship between topicBase in f_topics and groupID in f_groups, this shows which group each topic belongs to. Each topic has a unique ID called topicID and same for the groups, called groupID.
Basically, I'm trying to get all these columns into a single SELECT statement - The title of the topic, the date the topic was posted, the ID of the group the topic belongs in, and the name of that group. This is what I was trying to use, but the group always comes back as 1, even if the topic is in groupID 2:
$query=mysqli_query($link, "
SELECT `topicName`, `topicDate`, `groupName`, `groupID`
FROM `f_topics`
NATURAL JOIN `f_groups`
WHERE `f_topics`.`topicID`='$tid';
") or die("Failed to get topic detail E: ".mysqli_error());
var_dump(mysqli_fetch_assoc($query));
Sorry if this doesn't make much sense, and if my entire logic is completely wrong, if so could you suggest an alternate method?
Thanks for reading!
To join tables, you need to map the foreign keys. Assuming your groups table has an groupID field, this is how you'd join them:
SELECT `topicName`, `topicDate`, `groupName`, `groupID`
FROM `f_topics`
LEFT JOIN `f_groups`
ON `f_topics`.`groupID` = `f_groups`.`groupID`
WHERE`f_topics`.`topicID`='$tid';
So from what I gather there is a column in f_topics named "topicBase" which references the groupID column from the f_groups table.
Based on that assumption, you can perform either an INNER JOIN or a LEFT JOIN. INNER requires there be an entry in both tables while LEFT requires there only be data in f_topics.
SELECT
f_topics.topicName,
f_topics.topicDate
f_groups.groupName
f_groups.groupID
FROM
f_topics
INNER JOIN
f_groups
ON
f_topics.topicBase = f_groups.groupID
WHERE
f_topics.topicID = '$tid'
I recommend you avoid NATURAL JOIN.
Primarily because a working query can be broken by the addition of a new column in a referenced table, which matches a column name in the other referenced table.
Secondly, for any reader (reviewer) of the SQL, which columns are being matched to which columns is not clear, without a careful review of both tables. (And, if someone has added a column that has broken the query, it makes it even more difficult to figure out what the JOIN criteria used to be, before the column was added.
Instead, I recommend you specify the column names in a predicate in the ON clause.
It's also good practice to qualify all column references by table name, or preferably, a shorter table alias.
For simpler statements, I agree that this may look like unnecessary overhead. But once statements become more complicated, this pattern VASTLY improves the readability of the statement.
Absent the definitions of the two tables, I'm going to have to make assumptions, and I "guess" that there is a groupID column in both of those tables, and that is the only column that is named the same. But you specify that its the topicBase column in f_topics that matches groupID in f_groups. (And the NATURAL JOIN won't get you that.)
I think the resultset you want will be returned by this query:
SELECT t.`topicName`
, t.`topicDate`
, g.`groupName`
, g.`groupID`
FROM `f_topics` t
JOIN `f_groups` g
ON g.`groupID` = t.`topicBase`
WHERE t.`topicID`='$tid';
If its possible for the topicBase column to be NULL or to contain a value that does not match a f_groups.GroupID value, and you want that topic returned, with the columns from f_group returned as NULL (when there is no match), you can get that with an outer join.
To get that behavior, in the query above, add the LEFT keyword immediately before the JOIN keyword.
I am trying to query 2 tables in a database, each query having nothing to do with each other, other then being on the same page.
Query 1 - The first query on the page will retrieve text and images that are found throughout the page from Table A.
Query 2 - The second query will retrieve several products with a image, description and title for each product from Table B.
I know that putting the second query inside the first query's while loop would work but of course is very inefficient.
How can I and what is the best way to retrieve all the data I need through 1 query?
Thanks,
Dane
So all you want to know is if its ok to have 2 queries on the same webpage? Its A-OK. Go right ahead. Its completelly normal. No one expects a join between table news and table products. Its normal to usetwo queries to fetch data from two unrelated tables.
Use LEFT or INNER JOIN (depends on whether you want to display records from TableA that have no correspondent records in TableB)
SELECT a.*, b.*
FROM TableA a
[LEFT or INNER] JOIN TableB b ON (b.a_id = a.id)
If there's no way to relate the two tables to each other, then you can't use a JOIN to grab records from both. You COULD use a UNION query, but that presumes that you can match up fields from each table, as a UNION requires you to select the same number/type of fields from each table.
SELECT 'pageinfo' AS sourcetable, page.id, page.images, page.this, page.that
WHERE page.id = $id
UNION
SELECT 'product' AS sourcetable, products.id, products.image, product.other, product.stuff
But this is highly ugly. You're still forcing the DB server to do two queries in the background plus the extra work of combining them into a single result set, and then you have to do extra work to dis-entangle in your code to boot.
It's MUCH easier, conceptually and maintenance-wise, to do two seperate queries instead.