Mysql syntax using IN help! - php

i have a pictures table : pictures(articleid,pictureurl)
And an articles table : articles(id,title,category)
So, briefly, every article has a picture, and i link pictures with article using articleid column. now i want to select 5 pictures of articles in politic category.
i think that can be done using IN but i can't figure out how to do it.
Note: Please only one query, because i can do it by selecting articles firstly then getting the pictures.
Thanks

To get five pictures from articles in a category you could do this:
SELECT pictures.pictureurl
FROM articles, pictures
WHERE articles.id = pictures.articleid AND articles.category = 'politic'
ORDER BY [your sort criteria]
LIMIT 5;
You could consider rephrasing the question a bit.

If you are looking for an IN query instead of a JOIN this is an alternative to Alex's query:
SELECT pictureurl
FROM pictures
WHERE arcticleid IN (SELECT id FROM articles WHERE category='politic')
LIMIT 5

Rewritten for clarification (see comments):
If you like to keep your JOIN criteria separated from your SELECT criteria, you can write something like the below:
SELECT pictureurl
FROM pictures
JOIN articles ON id = articleid
WHERE category LIKE 'politics'
ORDER BY RAND()
LIMIT 5
I find the intent slightly clear when it's written like that, and maybe it's just me, but I have encountered complex queries written in the SELECT * FROM a, b, c form that worked under MySQL 4 which choke MySQL 5, whereas the above format works fine with both.
Also, if you use uniform ID column names for conformity, and to avoid confusing yourself in more complex scenarios, you can use the USING clause instead. So if articles ID column is also named articlesid, the JOIN could be written like so:
SELECT pictureurl
FROM pictures
JOIN articles USING (articleid)
...

You don't really need to use IN for this. IN serves when you nest queries or when you have a known set of values to check against.
To select 5 random images in the politics category:
SELECT pictureurl FROM articles, pictures WHERE pictures.articleid = articles.id AND articles.category = 'politics' ORDER BY RAND() LIMIT 5

Related

DISTINCT and RND() on joined tables

I’m really struggling with how to write a query which randomly selects 50 DISTINCT random titles from one table in my MySQL database and then selects 1 random excerpt from each title from a separate table. The first table is titles and the second is excerpts.
I’ve tried two queries nested together but this either doesn’t work or returns duplicate titles despite supposedly being DISTINCT.
Could somebody please, PLEASE help me with where I’m going wrong?!
My existing PHP:
$distincttitlequery = “SELECT DISTINCT titleid FROM titles ORDER BY rand() LIMIT 50”;
$distincttitleresult = mysql_query($cxn,$distincttitlequery);
while ($distinctqueryreturn = mysqli_fetch_assoc($distincttitlequery))
{
extract ($distinctqueryreturn);
$selectedtitle = $titleid;
$randomexcerptquery = “SELECT excerpts.titleid, excerpts.excerptid, excerpts.excerptsynopsis, title.titleid, title.title FROM excerpts INNER JOIN titles ON excerpts.titleid=title.titleid WHERE titleid = ‘$selectedtitle’ ORDER BY rand() LIMIT 1”;
$randomexcerptresults = mysql_query($cxn,$randomexcerptquery);
while ($randomexcerptreturn = mysqli_fetch_assoc($randomexcerptquery))
{
[ECHO RESULTS HERE]
}};
I’ve read in similar posts about GROUP BY but I need to create a query which deals with distinct, random and joined tables and I have absolutely no idea where to start!
My existing code uses DISTINCT on multiple columns and joins the tables but this leads to titles being repeated in returned results. I can LIVE with that but I’d love to perfect it!
Thank you in advance for your help with this.
In mysql 8 you can use row_number to get 1 random row per titleid
SELECT
titleid,title,excerptid,excerptsynopsis
FROM (
SELECT
e.titleid, e.excerptid, e.excerptsynopsis
,ROW_NUMBER() OVER( PARTITION BY e.titleid ORDER BY rand()) rn
, t.title
FROM excerpts e
INNER JOIN (SELECT DISTINCT titleid FROM titles ORDER BY rand() LIMIT 50) t ON e.titleid=t.titleid
) t1
WHERE rn = 1

Get the list of ten top publishers in database

I've got following tables in my MySQL database:
USERS
iduser nick password
ARTICLES
idarticles iduser text
How can I get by one SQL query the list of e.g. 10 top publishers of articles ordering by the count of added articles? Is there any way to do that? I'm using PHP to ask database.
Yes, this should be quite easy via JOIN and COUNT(). Something like the following
SELECT `users`.`iduser`, COUNT(`articles`.`idarticles`) AS `total_articles`
FROM `users`
INNER JOIN `articles` ON `users`.`iduser` = `articles`.`iduser`
GROUP BY `users`.`iduser`
ORDER BY `total_articles` DESC
LIMIT 10
A little explaining:
COUNT() will get you what it says - a count of all relevant entries in articles
INNER JOIN will pair all entries that belong together (defined via ON)
GROUP BY tells SQL that you are interested in various results, each differing by iduser (without this, you'd get all articles counted in the first returned row)
ORDER BY .. DESC is important to get the result in a descending order (so most published first)
LIMIT 10 does exactly that

Count how many of each distinct value is in SQL table

I am wondering if there is easy way to get number of how many rows of distinct values I have (bad explanation, I know)
Example: I have table, which registers views for my blog articles. I want to count, how many have viewed article a and how many b (I have many articles, I want to get top 10 most viewed articles)
So is there an easy way to get this with SQL, at the moment I did it with php arrays, I'm getting all the distinct rows in array, then I get how many of rows there is for every array value, then I sort array and echo first 10, but that is way too many queries, I was wondering, if there is way to do this with 1 query?
select
a.article_id,
a.title,
a.date,
/* Make sure to count a relevant view from the *views* table.
-- This makes sure that count returns 0 instead of 1 when
-- the article isn't viewed yet. */
count(v.article_id) as viewcount
from
Article a
/* Using left join here, to also include articles that are not viewed at all.
-- You can change this to an inner join if you don't want to include those. */
left join ArticleView v on v.article_id = a.article_id
group by
/* Group by article id, so count() actually counts per article. */
a.article_id
order by
/* Place the best viewed articles on top. */
count(v.article_id) desc
/* And return only 10 articles at most. */
limit 10
This query will return 10 articles, even if there are no 10 that have views at all. If you want to only return articles that actually have views, and you don't need other fields from the article table, you can simplify the query a little:
select
v.article_id,
count(v.article_id) as viewcount
from
ArticleView v
group by
v.article_id
order by
count(v.article_id) desc
limit 10
But the advantage of the first query is that you can also add other fields of 'a' to your query result, like the title. So this single query can actually return all the information you need to generate the entire top-10 list, while the second only provides a list of ids.
It is easy to do with sql grouping.
select articleid, count(*) from view_table group by articled
Obviously, you will need to change the tables and fields.

mysql join not working

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.

Selecting max value of one column, grouping by another is not working

I have a database full of media. For simplicity sake, lets say it has
Table: media
id
college_id
title
shares
I'm trying to get the articles with the most amount of shares from each college. So, in essence, get the top shared article from Cornell, USC, Syracuse.
I have been using this SQL command, but it doesn't return the most shared article from each college.
SELECT *
FROM media
GROUP BY college_id
ORDER BY shares DESC
Anyone have any ideas?
The shares column is an integer indicating the number of shares.
SELECT top 1 * from media group by college_id order by shares desc
That was my first thought... though I'm wondering if I'm missing something since this answer is a lot simpler than Adam's. If shares is the number of times it's been shared though this sound like what you're looking for.
Edit: I see now. Here's another way...
select m1.id, m1.college_id, m1.title, m1.shares
from media m1 join
(
select college_id, max(shares) max_shares
from media
group by college_id
) m2 on m1.college_id = m2.college_id and m1.shares = m2.max_shares
This will return more than one article per college in cases where there is a tie. I don't if you want that or not.
If we assume that shares column handles the share count query would be,
SELECT title,
Max(shares) AS max
FROM media
GROUP BY college_id
ORDER BY max DESC
But If we assume that shares column is an ID or sth, query would be,
SELECT title,
COUNT(shares) AS COUNT
FROM media
GROUP BY college_id
ORDER BY COUNT DESC
I suggest you to give more details next time.
You are looking for the MAX sql keyword
In MSSQL this works just fine
SELECT college_id,
Max(shares)
FROM media
GROUP BY college_id

Categories