I am trying to replicate a forum function by getting the last reply of a post.
For clarity, see PHPBB: there are four columns, and the last column is what I like to replicate.
I have my tables created as such:
discussion_id (primary key)
user_id
parent_id
comment
status
pubdate
I was thinking of creating a Link Table that would update for each time the post is replied to.
The link table would be as follow:
discussion_id (primary key)
last_user_id
last_user_update
However, I am hoping that theres a advance query to achieve this method. That is, grabbing each Parent Discussion, and finding the last reply in each of those Parent Discussions.
Am I right that there is such a query?
Here is a update.
I am still having a little trouble but I feel like I am almost there.
My current query:
SELECT
`discussion_id`,
`parent_id`,
`user_id` as `last_user_id`,
`user_name` as `last_user_name`
FROM `table1`, `table2`
WHERE `table1`.`id` = `table2`.`user_id`
Results:
discussion_id---------parent_id-----last_user_id-------last_user_name
30---------------------NULL-------------3--------------raiku
31---------------------30---------------2--------------antu
32---------------------30---------------1--------------admin
33---------------------NULL-------------3--------------raiku
Adding this:
GROUP BY `parent_id`
Turns it into:
discussion_id---------parent_id-----last_user_id-------last_user_name
32---------------------30---------------1--------------admin
33---------------------NULL-------------3--------------raiku
But I want it to turn it into:
discussion_id---------parent_id-----last_user_id-------last_user_name
30---------------------NULL-------------3--------------raiku
32---------------------30---------------1--------------admin
33---------------------NULL-------------3--------------raiku
Id 30, and ID 33 share the same parent_id: NULL but they are the "starting thread" or the "parent post"
They should not be combined, how would I go on by "Grouping" but "ignoring" null values?
This query will take the highest (thus assuming latest) discussion per parent_id. Not the neatest solution however ...
select discussion_id, user_id, pubdate
from tablename
where discussion_id in
(
select max(discussion_id)
from tablename
group by parent_id
)
You could try something like this:
SELECT parent.discussion_id,
child.discussion_id as last_discussion_id,
child.user_id as last_user_id,
child.pubdate as last_user_update
FROM Discussion parent
INNER JOIN Discussion child ON ( child.parent_id = parent.discussion_id )
LEFT OUTER JOIN Discussion c ON ( c.parent_id = parent.discussion_id AND c.discussion_id > child.discussion_id)
WHERE c.discussion_id IS NULL
The left join to Discussion c will not match when you have the post with the highest id, which should be the row that you want.
You want GROUP BY. This should work out OK:
SELECT MAX(`pubdate`), `discussion_id`, `user_id` FROM `table` GROUP BY `parent_id`
You'll obviously need to fill in an appropriate the WHERE clause and LIMIT as needed.
Related
I have been trying to do this in many ways suggested.
Note: we do not want aggregate function or Partition since this is just a small part of whole Stored procedure and this is client requirement to not have it, so not in option and not possible duplicate of other existing answers / questions
I have a messages table, which has a column from and to, a foreign key to the user table, basically which user sends to whom at simplest. I also have other columns which are isSnoozed and snoozeAt for if the message is snoozed.
So the ordering is according to case. If messages is snoozed then consider snoozeAt time to Order or if not then consider sendAt. (right now we can ignore this condition while ordering, But I mentioned this since we cannot take simply MAX(id) )
I need to get recent most message from messages group by from user id
messages table like :
id -- to -- from -- isSnoozed -- snoozedAt -- sendAt ...
What I tried :
select * from ( select * from messages order by sendAt DESC) as TEMP GROUP BY TEMP.from
I tried many similar approaches but none worked.
I wasted many paid hours but can't find an approach which meets my exact requirement
NOTE: Please ignore typo in query if any, since I cant type in exact query table and names, So i typed in directly here
I figured this out by doing something like this, which could be explained in a simplified way:
select * from message where message.id in (
select
( select id from message where message.from = user.id order by CASE isSnoozed WHEN 0 THEN sendAt ELSE snoozeAt END DESC limit 1) as id
from user where user.id in ( select friends.`whoIsAdded` from friends where friends.`whoAdded` = myId)
) order by CASE isSnoozed WHEN 0 THEN sendAt ELSE snoozeAt END DESC
If I understand correctly, you just want the largest value in one of two columns. Assuming the values are never NULL, you can use greatest():
select m.*
from messages m
where greatest(m.sendAt, m.snoozedAt) =
(select max(greatest(m2.sendAt, m2.snoozedAt))
from messages m2
where m2.from = m.from
);
If the columns can be NULL, then you can use coalesce() to give them more reasonable values.
Hi: struggling with retrieving only those emails from my marketingImport table that do not exist in my hardBounce table.
I tried various approaches to the LEFT JOIN, but I'm always getting the entire marketingTable (all 300K records). I should be only getting about 220K records, since there are about 80K 'bad' emails in my hardBounce table: those should be excluded from my results.
I also tried replacing WHERE with AND (to make it part of the ON clause), but got same results.
This is my SQL:
SELECT marketingImport.email FROM marketingImport
LEFT JOIN hardBounce ON marketingImport.email = hardBounce.email
WHERE hardBounce.email IS NULL;
Tables:
-marketingImport contains a field 'email' which is a varchar(255), nullable index
-hardBounce contains a single field 'email' which is a varchar(255), nullable UNIQUE index (not PK)
What am I missing? I did read all posts...and my eyes are now watering...
Thank you.
How about using a subquery instead of LEFT JOIN?
SELECT marketingImport.email
FROM marketingImport
WHERE marketingImport.email NOT IN (
SELECT hardBounce.email
FROM hardBounce
);
Try to use NOT EXISTS:
SELECT marketingImport.email FROM marketingImport
WHERE NOT EXISTS (
SELECT 1 FROM hardBounce WHERE hardBounce.email = marketingImport.email
);
And I think there may be null value in hardBounce, so you can get all the the emails from marketingImport.
I'm having an odd problem, and I don't have the slightest idea of why it isn't working.
I have the following query that I constructed:
SELECT servers.id, servers.name, servers.address, servers.port, servers.up, servers.down, servers.genre, servers.score, servers.version, servers.country, ROUND( AVG( reviews.average ) , 0 ) AS review
FROM servers
INNER JOIN reviews ON servers.id = reviews.server
ORDER BY servers.score DESC
This query was working fine a few weeks ago. It is meant to get many fields from the "servers" table, and the average field from the "reviews" table where the server in the "reviews" table is the same as the id in the "servers" table.
Like I said, this query was working fine before. Yesterday I noticed that a vital part of my site wasn't working, and I figured out that this query is failing.
I've confirmed that is returning exactly 1 row (when, at the moment, it should be returning 4, because there are 4 entries in the "servers" table.)
This is what phpMyAdmin gives me when I execute that query:
id name address port up down genre score version country review
NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL
Could anybody enlighten me? I've come here as a last resort, because I am stuck.
As mentioned in the comments, try changing the INNER JOIN to a LEFT OUTER JOIN which will return servers, regardless if there is a matched row in the review table or not. Also, you didn't post your schema, but double check the reviews.server column in the reviews table, it may be server_id instead. Another issue, you are doing an AVG which is a grouped calculation, but you have no GROUP BY clause, so I would suggest adding it, so your full query should look like:
SELECT servers.id, servers.name, servers.address, servers.port, servers.up, servers.down, servers.genre, servers.score, servers.version, servers.country, ROUND( AVG( reviews.average ) , 0 ) AS review
FROM servers
LEFT OUTER JOIN reviews ON servers.id = reviews.server # might be reviews.server_id
GROUP BY reviews.server
ORDER BY servers.score DESC
More info about GROUP BY functions.
-- Update --
SELECT servers.id, servers.name, servers.address, servers.port, servers.up, servers.down, servers.genre, servers.score, servers.version, servers.country, IFNULL(ROUND(AVG(reviews.average)), 0) AS review
FROM servers
LEFT OUTER JOIN reviews ON servers.id = reviews.server
GROUP BY servers.id
ORDER BY servers.score DESC
I have one table reports, which contains all info and read reports which just has Report ID and ID (of owner of the report)
I'm trying to do this statment (correct me if theres better out there) so it gets all the reports ID from read reports which match ID 1, and pick out all the details from reports for it. (Report ID's are the same on reports and read reports)
But this statement is giving me back no rows:
SELECT a.*
FROM `Reports` AS a,
(SELECT `Report ID` FROM `Read Reports` WHERE `Id` = 1) AS b
WHERE a.`Report ID` = b.`Report ID`;
Whats wrong with it/how can I improve it?
Thanks,
EDIT: My bad, it works fine!! Id 1 had no reports. Close this. :L
EDIT2: Still post if you have improvements though :P
Try this:
SELECT a.*, (SELECT `Report ID` FROM `Read Reports` WHERE `Id` = 1) AS b_report_id
FROM `Reports` AS a
HAVING a.`Report ID` = b_report_id;
There seems to be nothing wrong with your query and it should return the records unless there are no matching records. But if you say that there do exist matching records, I'd suggest that you re-read your query to confirm that you are using the right column names, i.e. not replaced "Id" with "Report ID"?
Can you give a snapshot of your data in your post?
By the way, the below query should be better because it does not involve derived table:
SELECT `a`.*
FROM `Reports` AS `a`
INNER JOIN `Read Reports` AS `b` ON `a`.`Report ID` = `b`.`Report ID`
WHERE `b`.`Id` = 1;
I have following tables:
products_match:
atcode varchar(6)
valcode varchar(100)
id_prod varchar(15)
products:
asin varchar(15)
title varchar(155)
Example content of products_match table:
atcode='type'
valcode='wifi'
id_prod='1SC52DD'
atcode='type'
valcode='ram'
id_prod='11DD5ER'
There are multiple kwywords in this table.
I'm budilding a simple search engine - I need to display products matching multiple criteria, example:
select products where atcode='type' AND valcode='wifi' AND valcode='brand' AND 'valcode' = 'Sony'
Do I need to apply self joins for every group of arguments here?
Right now I have following query:
SELECT * FROM products_match a
JOIN products b ON a.id_prod=b.asin
JOIN assortment_match c ON a.id_prod=c.id_prod
WHERE c.atcode='brand' AND c.valcode='sony'
ORDER BY sales_rank ASC LIMIT 0,60
however it returns no products.
Can anybody help me solve this issue?
Edit
I've been told that I should use one self join for every group of keywords. What do you think?
One method is that for each match, you could use an EXISTS subquery.
AND EXISTS (select 1 from products_match
where id_prod = a.id_prod
and atcode = 'type' and valcode = 'wifi')