Here is my php/MySQL task:
I have a table POSTS that contains num field that is the primary key and other information fields about the post (author, title, etc.). I also have a table LIKE that contains a userId field that is the primary key and a field POST that corresponds to the num field in posts. Given a specific userID, I need to get all of the rows from the POSTS table that the userId 'likes'.
Table 1 - posts
-num
-author
-title
Table 2 - likes
-userId
-postId
This is all in php so my first idea was to get all of the rows from the LIKES table where the userId matches the one given and store those rows in an array. Then I would iterate through the array and for each row I would search get the row of the POSTS table where postId=POSTS.num. However, this seems like it would be rather slow, especially since each iteration through the array would be a separate mysql query.
I am assuming there is a faster way. Would it be to use a temporary table or is there a better way to join the tables? I have to assume that both tables contain many rows. I am a mysql novice so if there is a better solution please explain why it is better. Thank you in advance for you help!
Try the following query:
SELECT
`posts`.*
FROM
`likes`
INNER JOIN
`posts` ON
`posts`.num = `likes`.postId
WHERE
`likes`.Userid = {insert user id here}
Depending on your schema (not sure if each record in 'likes' has to be unique, you may want to use the DISTINCT keyword on your select to filter out duplicates.
SELECT poli.* FROM (
SELECT po.* FROM posts po
JOIN likes li
ON li.postId = po.num
WHERE li.userId = '$yourGivenUserId'
) AS poli
$yourGivenUserId is the given userId.
Related
just like the caption, how do i fetch information from foreign key instead of id?
Here are the first table:
and here are the second table:
i want to display product_name and unit_price instead of id, how to do it?
You need to use join
Your query should look something like this:
SELECT ft.id, pr.product_name, pr.unit_price from firsttable as ft join product as pr on ft.product_id = pr.product_id;
Where firsttable is the table of the first screenshot and product is the table from the second screenshot.
I don't know what you need from the first table so I just took a column id, however I do not know if you have this column. Here you just put whatever you need from the first table.
First a bit of background about the tables & DB.
I have a MySQL db with a few tables in:
films:
Contains all film/series info with netflixid as a unique primary key.
users:
Contains user info "ratingid" is a unique primary key
rating:
Contains ALL user rating info, netflixid and a unique primary key of a compound "netflixid-userid"
This statement works:
SELECT *
FROM films
WHERE
INSTR(countrylist, 'GB')
AND films.netflixid NOT IN (SELECT netflixid FROM rating WHERE rating.userid = 1)
LIMIT 1
but it takes longer and longer to retrieve a new film record that you haven't rated. (currently at 6.8 seconds for around 2400 user ratings on an 8000 row film table)
First I thought it was the INSTR(countrylist, 'GB'), so I split them out into their own tinyint columns - made no difference.
I have tried NOT EXISTS as well, but the times are similar.
Any thoughts/ideas on how to select a new "unrated" row from films quickly?
Thanks!
Try just joining?
SELECT *
FROM films
LEFT JOIN rating on rating.ratingid=CONCAT(films.netflixid,'-',1)
WHERE
INSTR(countrylist, 'GB')
AND rating.pk IS NULL
LIMIT 1
Or doing the equivalent NOT EXISTS.
I would recommend not exists:
select *
from films f
where
instr(countrylist, 'GB')
and not exists (
select 1 from rating r where r.userid = 1 and f.netflixid = r.netflixid
)
This should take advantage of the primary key index of the rating table, so the subquery executes quickly.
That said, the instr() function in the outer query also represents a bottleneck. The database cannot take advantage of an index here, because of the function call: basically it needs to apply the computation to the whole table before it is able to filter. To avoid this, you would probably need to review your design: that is, have a separate table to represent the relationship between movies and countries, which each tuple on a separate row; then, you could use another exists subquery to filter on the country.
The INSTR(countrylist, 'GB') could be changed on countrylist = 'GB' or countrylist LIKE '%GB%' if the countrylist contains more than the country.
Then don't select all '*' if you need only some columns details. Depends on the number of columns, the query could be really slow
I have two tables in a database. One stores names/details of users with an index ID; the other stores articles they have written, which just keeps the user's ID as a reference (field author). So far so simple. I can easily query a list of articles and include in the query a request for the user's name and status:
SELECT a.name, a.status, s.* FROM articles s, author a WHERE s.author=a.id
The problem comes when I occasionally have a second author credit, referenced in field author2. Up till now I've been doing what I assume is a very inefficient second query when I iterate through the results, just to get the second author's name and status from the table (pseudocode):
while ( fetch a row ) {
if (author2 != 0) {
query("SELECT name, status FROM author WHERE id=author2") }
etc. }
While this worked fine in PHP/MySQL (even if clunky), I'm forced to upgrade to PHP7/PDO and I'd like to get the benefits of unbuffered queries, so this nested query won't work. Obviously one simple solution would be to PDO->fetchALL() the entire results first before iterating all the result rows in a foreach loop and doing these extra queries per row.
But it would be far more efficient to get that second bit of data somehow incorporated into the main query, pulling from the author table using the second ID (author2) as well as the main ID, so that there are name2 and status2 fields added to each row. I just cannot see how to do it...
It should be noted that while the primary author ID field is ALWAYS non-zero, the author2 field will contain zero if there is no second ID, and there is NO author ID 0 in the author table, so any solution would need to handle an author2 ID of 0 by providing null strings or something in those fields, rather than giving an error. (Or far less elegantly, a dummy author ID 0 with null data could be added to the author table, I suppose.)
Can anyone suggest a revised original query that can avoid such secondary queries?
Never use commas in the FROM clause. Always use proper, explicit, standard JOIN syntax.
For your query, use LEFT JOIN:
SELECT s.*, a1.name, a1.status, a2.name, a2.status
FROM articles s LEFT JOIN
author a1
ON s.author = a1.id LEFT JOIN
author a2
ON s.author2 = a2.id
Gordon Linoff's answer looks like what you need.
I would have added this as a comment but it is too long of a message...
I just have a question/comment regarding normalization of the database. Would there ever be an instance when there is an author3? If so then you should probably have an ArticleAuthor table. Since you are rebuilding the code anyway this may be an improvement to consider.
I don't know the names and data types of the information you are storing so this is a primitive example of the structure I would suggest.
Table Article
ArticleID
ArticleData...
Table Author
AuthorID
AuthorName
AuthorStatus
Table ArticleAuthor
ArticleID
AuthorID
If the Status is dependent on the Author Article combination then AuthorStatus would be moved to ArticleAuthor table like this.
Table ArticleAuthor
ArticleID
AuthorID
Status
I have a table which has several thousand records.
I want to update all the records which have a duplicate firstname
How can I achieve this with a single query?
Sample table structure:
Fname varchar(100)
Lname varchar(100)
Duplicates int
This duplicate column must be updated with the total number of duplicates with a single query.
Is this possible without running in a loop?
update table as t1
inner join (
select
fname,
count(fname) as total
from table
group by fname) as t2
on t1.fname = t2.fname
set t1.duplicates = t2.total
I have a table which has several thousand records. I want to update all the records which have a duplicate firstname How can I achieve this with a single query?
Are you absolutely sure you want to store the number of the so called duplicates? If not, it's a rather simple query:
SELECT fname, COUNT(1) AS number FROM yourtable GROUP BY fname;
I don't see why you would want to store that number though. What if there's another record inserted? What if there are records deleted? The "number of duplicates" will remain the same, and therefore will become incorrect at the first mutation.
Create the column first, then write a query like:
UPDATE table SET table.duplicates = (SELECT COUNT(*) FROM table r GROUP BY Fname/Lname/some_id)
Maybe this other SO will help?
How do I UPDATE from a SELECT in SQL Server?
You might not be able to do this. You can't update the same table that you are selecting from in the same query.
I have following tables
articles_category
id title sef_title
articles_data
id cat_id title sef_title details
On each table "id" is the primary key and articles_data.cat_id is foreign key of articles_category
I need to fetch one latest article data for each articles category with following data.
articles_category.id
articles_category.title
articles_category.sef_title
articles_data.id
articles_data.cat_id
articles_data.title
articles_data.sef_title
articles_data.details
I tried with following query but it displays first article (oldest entry) rather than latest one.
SELECT
articles_category.id as article_cat_id, articles_category.sef_title as cat_sef_title, articles_category.title as cat_title,
articles_data.id, articles_data.cat_id as listing_cat_id, articles_data.title, articles_data.sef_title, articles_data.details
FROM articles_category, articles_data
WHERE articles_category.id = articles_data.cat_id
GROUP BY articles_data.cat_id
ORDER BY articles_data.id DESC
if it's a one to many relation, try (untested):
SELECT *
FROM articles_category, articles_data
WHERE articles_category.id = articles_data.cat_id
AND articles_data.id in (
SELECT max(articles_data.id)
FROM articles_data GROUP BY cat_id
)
you are not guaranteed a particular row on a GROUP BY
and you should really use a date on your article as the max id is never guaranteed to be the latest article even if you are using autoincrement
ORDER affects the display of records after the GROUP function has been performed. The GROUP function recognizes the first record it sees in its search.
What you need to do is perform 2 queries. The first one should be
SELECT max(articles_data.id), articles_data.cat_id ...
GROUP BY articles_data.cat_id
The second query should fetch the associated records using those resultant primary keys.
A possibility is to create another value such as date_created and place a time stamp there when creating an entry.
Then you would just have to ORDER BY date.