SQL query to get 10 last topics with replies - sql

I have a simple forum database and want to write SQL query to get
10 last topics (threads) with replies from 3 or more unique posters.
Result: Topic (thread) name | Last message text | User name | Date
UPDATED:
Here is what I tried:
SELECT thread.thread_id, thread.thread_name, message.thread_id,
COUNT(message.thread_id)
FROM thread, message
WHERE message.thread_id = thread.thread_id
GROUP BY message.thread_id
HAVING COUNT(message.thread_id) >= 3
LIMIT 10
But it returns 10 topics (threads) with 3 or more replies (but not 3 or more unique posters)
UPDATE 2:
SELECT message.thread_id AS ID, thread.thread_name AS topic
FROM message INNER JOIN thread
ON message.thread_id = thread.thread_id
GROUP BY message.thread_id
HAVING COUNT(*) >= 3
LIMIT 10
This also returns 10 topics with 3 or more replies
UPDATE 3, thanks #shawnt00
SELECT thread.thread_name AS 'Topic', message_text AS 'Message', person_nickname AS 'Nickname', message_date AS 'Date'
FROM thread,
(
SELECT thread.thread_id, MAX(message_date) AS last_date
FROM thread
INNER JOIN message ON message.thread_id = thread.thread_id
GROUP BY thread.thread_id
HAVING COUNT(DISTINCT message.person_id) >= 3
) AS temp
INNER JOIN message
ON message.thread_id = temp.thread_id AND message.message_date = temp.last_date
INNER JOIN person ON person.person_id = message.person_id
WHERE thread.thread_id = temp.thread_id
ORDER BY message.message_date DESC
LIMIT 10

with data as (
select p.thread_id, max(message_date) as last_date
from thread t inner join message m on m.thread_id = t.thread_id
group by p.thread_id
having count(distinct m.person_id) >= 3
)
select *
from data d
inner join message m
on m.thread_id = d.thread_id and m.message_date = m.last_date
inner join person p on p.person_id = m.person_id;
The only assumption is that there can't be ties on dates. If you have analytic functions available then there are other approaches using those. I'm sure you can figure out how to get top 10.

i think you need below query.
Assuming that you are using mysql so i used Limitfunction as you want last 3 unique row
select distinct th.thread_name as Topic_name, m.message_text, p.person_nickname as User_name, m.message_date as Date from message m
inner join thread th on m.thread_id=th.thread_id
inner join persion p on p.persion_id=m.persion_id
order by message_date desc
Limit 3
But if the db is SQLSERVER Then use below query
select distinct TOP(3) th.thread_name as Topic_name, m.message_text, p.person_nickname as User_name, m.message_date as Date from message m
inner join thread th on m.thread_id=th.thread_id
inner join persion p on p.persion_id=m.persion_id
order by message_date desc

Related

SQL Query 1 have count Function and to get data from another SQL Query 2 where memberid is same

My First Query is
SELECT
memberid,
count(*) count
From
dbo.Transactions
group by
dbo.Transactions.MemberID
having
count(memberid) > 1
My query 2 is
SELECT
transactionlog.id,
transactionlog.transactionid,
transactionlog.transactionamount,
transactionlog.transactiondate,
transactions.MemberID,
GymMember.FirstName,
from
dbo.GymMember
inner join Transactions on
GymMember.MemberID = Transactions.MemberId
inner join TransactionLog on
Transactions.Id = TransactionLog.TransactionId
Results of Query 2 are givne in below image
Now i want to have data where query 1 member id and query 2 member id are same
Do you mean find data where the MemberID from the second query exists in the first query? If so please see query below.
SELECT
transactionlog.id,
transactionlog.transactionid,
transactionlog.transactionamount,
transactionlog.transactiondate,
transactions.MemberID,
GymMember.FirstName,
from
dbo.GymMember
inner join Transactions on
GymMember.MemberID = Transactions.MemberId
inner join TransactionLog on
Transactions.Id = TransactionLog.TransactionId
WHERE
Transactions.MemberId IN
(SELECT
memberid
FROM
dbo.Transactions
group by
dbo.Transactions.MemberID
having
count(memberid) > 1))
I was working on it from more than 24 hours and after try and trial i found the solution but Senior can recommend a more proper way to do this My Solution is
SELECT* FROM( SELECT* FROM
(select transactionlog.id, transactionlog.transactionid, transactionlog.transactionamount, transactionlog.transactiondate, transactions.MemberID, GymMember.FirstName, GymMember.CellNumber from dbo.GymMember
inner join Transactions on GymMember.MemberID = Transactions.MemberId
inner join TransactionLog on Transactions.Id = TransactionLog.TransactionId) as MYTABLE where Exists
(select dbo.transactions.memberid,count(dbo.transactions.memberid) From dbo.Transactions Where mytable.MemberID = dbo.Transactions.MemberID group by dbo.Transactions.MemberID having count(dbo.Transactions.MemberID) > 1)) AS mynewtable where convert(datetime,TransactionDate,103) between '2022-09-30 00:00:00' and '2022-10-01 00:00:00'

Select newest TOPIC for each SUBJECT in SQL Server 2008

I have a project about programming a forum.
I have 2 tables in the database:
SUBJECT (idSUB, titleSUB);
TOPIC (idTOP, titleTOP, contentTOP, idSUB, idUser [user create topic], Time);
All I want is:
+ select COUNT(*) from TOPIC as numTOPIC group by idSUB--> as Table A
+select TOP 1 titleTOP order by Time desc-> as newestTOP group by idSUB---> as Table B
+ Then JOIN 3 table A,B,SUBJECT--> C(idSUB,titleSUB,numTOPIC,newestTOP, idUser (who created the newest topic))
I've found the way to LEFT JOIN A,SUBJECT-> C(idSUB,titleSUB,numTOPIC) but I really don't know the right syntax to JOIN 3 Tables above.
SELECT
a.idSUB, a.titleSUB,
COUNT(b.idSUB) numTOPIC
FROM
SUBJECT a
LEFT JOIN
TOPIC b ON a.idSUB = b.idSUB
GROUP BY
a.idSUB, a.titleSUB
I just want do this in only one query. Help!
UPDATE:
By the code of #John Bingham below, the output table cannot display the SUBJECT which doesn't have any TOPIC. I want all the TOPIC can be display.
SELECT
s.idSUB, s.titleSUB, a.numTOPIC,
isnull(b.newestTOP, '') as [Newest Topic],
isnull(b.idUser, '')
FROM
Subject s
INNER JOIN
(SELECT
IDSub, Count(*) as NumTopic
FROM
Topic
GROUP BY IDSub) a ON s.IDSub = a.IDSub
LEFT JOIN
(SELECT
t.IDSub, t.titleTop as newestTop, t.idUser as [idUser]
FROM
Topic t
INNER JOIN
(SELECT IDSub, Max([Time]) as tm
FROM Topic
GROUP BY IDSub) x ON t.IDSub = x.IDSub
WHERE t.[Time] = x.tm) b ON s.IDSub = b.IDSub
It's the right query but I want more exactly, help!
My inclination is to convert each of the requirements (a), (b) & (c) into subqueries which deliver the virtual tables to your query, rather than attempting to combine the base tables to deliver the requirements in a singe hit. So -
SELECT s.idSUB, s.titleSUB, a.numTOPIC, isnull(b.newestTOP, '') as [Newest Topic],
isnull(b.idUser, '')
FROM Subject s
INNER JOIN (SELECT IDSub, Count(*) as NumTopic FROM Topic GROUP BY IDSub) a
ON s.IDSub = a.IDSub
LEFT JOIN (
SELECT t.IDSub, t.titleTop as newestTop, t.idUser as [idUser]
FROM Topic t
INNER JOIN (
SELECT IDSub, Max([Time]) as tm FROM Topic GROUP BY IDSub
) x ON t.IDSub = x.IDSub
WHERE t.[Time] = x.tm
) b ON s.IDSub = b.IDSub
You want to display idSub,titleSub,numTopic,newestTOP,idUser where numTopic is number of topics in any subject i.e idSub and newestTOP is latest topic for the same subject.
I am using MySQL and tested the following query and it works fine.
SELECT S.idSub, S.titleSUB, TOPIC_COUNT_TABLE.NUMTOPIC, NEWESTTOPIC_TABLE.NEWESTTOPIC,
NEWESTTOPIC_TABLE.IDUSER
FROM SUBJECT S,
(SELECT IDSUB, COUNT(*) AS NUMTOPIC FROM TOPIC
GROUP BY TOPIC.IDSUB) AS TOPIC_COUNT_TABLE,
(SELECT T.IDSUB,T.titleTOP AS NEWESTTOPIC, T.IDUSER
FROM TOPIC T,(SELECT IDTOP,IDSUB,MAX(TIME) AS MAXTIME FROM TOPIC
GROUP BY IDSUB ) AS MAXTIME_TABLE
WHERE T.TIME = MAXTIME_TABLE.MAXTIME) AS NEWESTTOPIC_TABLE
WHERE S.IDSUB = NEWESTTOPIC_TABLE.IDSUB AND S.IDSUB = TOPIC_COUNT_TABLE.IDSUB;

select multiple tables in single sql query

The other threads about this didn't seem to help me. I want to select all the information from one table, but order them by a value in another table.
SELECT message,
DATE,
ip,
name,
website,
id
FROM guestbook_message
WHERE deleted = 0
AND DATE > Date_sub(Now(), interval 1 day)
ORDER BY DATE DESC
Except I need to ORDER BY 'votes' DESC; which is in another table called m_votes.
Is it possible to do this? I have read on another website that this query is impossible.
$query="SELECT g.message,
g.DATE,
g.ip,
g.name,
g.website,
g.id
FROM guestbook_message AS g
join m_votes AS v
ON g.id = v.vid
WHERE g.deleted = 0
AND v.messageid = $mid
AND g.DATE > Date_sub(Now(), interval 1 day)
ORDER BY SUM(v.votes) DESC;"
^^This doesn't work
You need a join:
SELECT
g.message,
g.date,
g.ip,
g.name,
g.website,
g.id
FROM guestbook_message AS g
LEFT JOIN m_votes AS v
ON g.id = v.message_id
WHERE g.deleted = 0
AND g.date > NOW() - INTERVAL 1 DAY
GROUP BY g.id
ORDER BY COUNT(v.message_id) DESC
I'm a bit of a beginner and to me this is a very hard query as it needs to find the SUM of 'votes' in m_votes and order by that. As well as get the information from the other query.
This is the query that gets the information about the message:
"SELECT message,
`date`,
ip,
name,
website,
id
FROM `guestbook_message`
WHERE deleted = 0
AND date > DATE_SUB(NOW(), INTERVAL 1 DAY)
ORDER BY `date` DESC";
And this is the query that gets the information about the votes:
"SELECT SUM(votes) as votes FROM m_votes WHERE messageid = $mid"
But I have no idea who I would put them into one query that will gather all the information from the first query, then ORDER them by votes.
You have to join the data, that is, you need to have the votes for each guestbook message.
Let's suppose for simplicity you have the following tables:
Message
----
id INT
messsageText VARCHAR(5000)
and
MessageVotes
------------
messageId INT (references the `id` column in table Message)
voteValue INT (suppose it can be +1 or -1, whatever)
votingIp VARCHAR(100)
Then you could do something like
SELECT
m.id,
m.messageText,
SUM(mv.voteValue) AS votes
FROM
Message AS m,
MessageVotes AS mv
WHERE
mv.messageId = m.id
GROUP BY
m.id, m.messageText /* here you need to place every field you `select` from Message */
ORDER BY
SUM(mv.voteValue) DESC
or even better:
SELECT
m.id,
m.messageText,
SUM(mv.voteValue) AS votes
FROM
Message AS m
LEFT JOIN MessageVotes AS mv ON mv.messageId = m.id
GROUP BY
m.id, m.messageText
ORDER BY
SUM(mv.voteValue) DESC
See:
mysql joins,
mysql left join
mysql group by - aggregate functions
Join Syntax
Please try below query, you missed group by clause.
SELECT g.message,
g.date,
g.ip,
g.name,
g.website,
g.id
FROM guestbook_message AS g
JOIN m_votes AS v ON g.id = v.vid
WHERE g.deleted = 0
AND v.messageid = $mid
AND g.date > DATE_SUB(NOW(), INTERVAL 1 DAY)
GROUP BY g.message,
g.date,
g.ip,
g.name,
g.website,
g.id
ORDER BY SUM(v.votes) DESC;

SQL JOIN Statement

Lets say I have a table e.g
Request No. Type Status
---------------------------
1 New Renewed
and then another table
Action ID Request No LastUpdated
------------------------------------
1 1 06-10-2010
2 1 07-14-2010
3 1 09-30-2010
How can I join the second table with the first table but only get the latest record from the second table(e.g Last Updated DESC)
SELECT T1.RequestNo ,
T1.Type ,
T1.Status,
T2.ActionId ,
T2.LastUpdated
FROM TABLE1 T1
JOIN TABLE2 T2
ON T1.RequestNo = T2.RequestNo
WHERE NOT EXISTS
(SELECT *
FROM TABLE2 T2B
WHERE T2B.RequestNo = T2.RequestNo
AND T2B.LastUpdated > T2.LastUpdated
)
Using aggregates:
SELECT r.*, re.*
FROM REQUESTS r
JOIN REQUEST_EVENTS re ON re.request_no = r.request_no
JOIN (SELECT t.request_no,
MAX(t.lastupdated) AS latest
FROM REQUEST_EVENTS t
GROUP BY t.request_no) x ON x.request_no = re.request_no
AND x.latest = re.lastupdated
Using LEFT JOIN & NOT EXISTS:
SELECT r.*, re.*
FROM REQUESTS r
JOIN REQUEST_EVENTS re ON re.request_no = r.request_no
WHERE NOT EXISTS(SELECT NULL
FROM REQUEST_EVENTS re2
WHERE re2.request_no = r2.request_no
AND re2.LastUpdated > re.LastUpdated)
SELECT *
FROM REQUEST, ACTION
WHERE REQUEST.REQUESTNO = ACTION.REQUESTNO --Joining here
AND ACTION.LastUpdated = (SELECT MAX(LastUpdated) FROM ACTION WHERE REQUEST.REQUESTNO = ACTION.REQUESTNO);
A sub-query is used to get the last updated record's date and matches against itself to prevent the other records being joined.
Granted, depending on how precise the LastUpdated field is, it can have problems with two records being updated on the same date, but that is a problem encountered in any other implementation, so the precision would have to be increased or some other logic would have to be in place or another distinguishing characteristic to prevent multiple rows being returned.
SELECT r.RequestNo, r.Type, r.Status, a.ActionID, MAX(a.LastUpdated)
FROM Request r
INNER JOIN Action a ON r.RequestNo = a.RequestNo
GROUP BY r.RequestNo, r.Type, r.Status, a.ActionID
We can use the operation Top 1 with ORDER BY clause. For instance, if your tables are RequestTable(ID,Type,Status) and ActionTable(ActionID,RequestID,LastUpdated), the query will be like this:
Select Top 1 rq.ID, rq.Status, at.ActionID
From RequestTable as rq
JOIN ActionTable as at ON rq.ID = at.RequestID
Order by at.LastUpdated DESC

Multiple MAX values select using inner join

I have query that work for me only when values in the StakeValue don't repeat.
Basically, I need to select maximum values from SI_STAKES table with their relations from two other tables grouped by internal type.
SELECT a.StakeValue, b.[StakeName], c.[ProviderName]
FROM SI_STAKES AS a
INNER JOIN SI_STAKESTYPES AS b ON a.[StakeTypeID] = b.[ID]
INNER JOIN SI_PROVIDERS AS c ON a.[ProviderID] = c.[ID] WHERE a.[EventID]=6
AND a.[StakeGroupTypeID]=1
AND a.StakeValue IN
(SELECT MAX(d.StakeValue) FROM SI_STAKES AS d
WHERE d.[EventID]=a.[EventID] AND d.[StakeGroupTypeID]=a.[StakeGroupTypeID]
GROUP BY d.[StakeTypeID])
ORDER BY b.[StakeName], a.[StakeValue] DESC
Results for example must be:
[ID] [MaxValue] [StakeTypeID] [ProviderName]
1 1,5 6 provider1
2 3,75 7 provider2
3 7,6 8 provider3
Thank you for your help
There are two problems to solve here.
1) Finding the max values per type. This will get the Max value per StakeType and make sure that we do the exercise only for the wanted events and group type.
SELECT StakeGroupTypeID, EventID, StakeTypeID, MAX(StakeValue) AS MaxStakeValue
FROM SI_STAKES
WHERE Stake.[EventID]=6
AND Stake.[StakeGroupTypeID]=1
GROUP BY StakeGroupTypeID, EventID, StakeTypeID
2) Then we need to get only one return back for that value since it may be present more then once.
Using the Max Value, we must find a unique row for each I usually do this by getting the Max ID is has the added advantage of getting me the most recent entry.
SELECT MAX(SMaxID.ID) AS ID
FROM SI_STAKES AS SMaxID
INNER JOIN (
SELECT StakeGroupTypeID, EventID, StakeTypeID, MAX(StakeValue) AS MaxStakeValue
FROM SI_STAKES
WHERE Stake.[EventID]=6
AND Stake.[StakeGroupTypeID]=1
GROUP BY StakeGroupTypeID, EventID, StakeTypeID
) AS SMaxVal ON SMaxID.StakeTypeID = SMaxVal.StakeTypeID
AND SMaxID.StakeValue = SMaxVal.MaxStakeValue
AND SMaxID.EventID = SMaxVal.EventID
AND SMaxID.StakeGroupTypeID = SMaxVal.StakeGroupTypeID
3) Now that we have the ID's of the rows that we want, we can just get that information.
SELECT Stakes.ID, Stakes.StakeValue, SType.StakeName, SProv.ProviderName
FROM SI_STAKES AS Stakes
INNER JOIN SI_STAKESTYPES AS SType ON Stake.[StakeTypeID] = SType.[ID]
INNER JOIN SI_PROVIDERS AS SProv ON Stake.[ProviderID] = SProv.[ID]
WHERE Stake.ID IN (
SELECT MAX(SMaxID.ID) AS ID
FROM SI_STAKES AS SMaxID
INNER JOIN (
SELECT StakeGroupTypeID, EventID, StakeTypeID, MAX(StakeValue) AS MaxStakeValue
FROM SI_STAKES
WHERE Stake.[EventID]=6
AND Stake.[StakeGroupTypeID]=1
GROUP BY StakeGroupTypeID, EventID, StakeTypeID
) AS SMaxVal ON SMaxID.StakeTypeID = SMaxVal.StakeTypeID
AND SMaxID.StakeValue = SMaxVal.MaxStakeValue
AND SMaxID.EventID = SMaxVal.EventID
AND SMaxID.StakeGroupTypeID = SMaxVal.StakeGroupTypeID
)
You can use the over clause since you're using T-SQL (hopefully 2005+):
select distinct
a.stakevalue,
max(a.stakevalue) over (partition by a.staketypeid) as maxvalue,
b.staketypeid,
c.providername
from
si_stakes a
inner join si_stakestypes b on
a.staketypeid = b.id
inner join si_providers c on
a.providerid = c.id
where
a.eventid = 6
and a.stakegrouptypeid = 1
Essentially, this will find the max a.stakevalue for each a.staketypeid. Using a distinct will return one and only one row. Now, if you wanted to include the min a.id along with it, you could use row_number to accomplish this:
select
s.id,
s.maxvalue,
s.staketypeid,
s.providername
from (
select
row_number() over (order by a.stakevalue desc
partition by a.staketypeid) as rownum,
a.id,
a.stakevalue as maxvalue,
b.staketypeid,
c.providername
from
si_stakes a
inner join si_stakestypes b on
a.staketypeid = b.id
inner join si_providers c on
a.providerid = c.id
where
a.eventid = 6
and a.stakegrouptypeid = 1
) s
where
s.rownum = 1