SQL query not sorting desc - sql

This sql command works fine in sqlitemanager
but in my android application this don't sort desc...
select t._id, u.name, c.commdate, c.message
from tickets t, users u, comments c
where c.userid = u._id and c.ticketid = t._id
and t.status = 5
group by t._id
having max(c.commdate)
order by c.commdate desc

I have a feeling the "having" part is a problem. Try (untested);
SELECT t._id, u.name, c.commdate, c.message
FROM tickets t
JOIN comments c ON (t._id = c.ticketid)
-- Find most decent comments on tickets, but handle lack of any comments
LEFT JOIN (
SELECT c2.ticketid, MAX(c2.commdate) as max_commdate
FROM comments c2
) AS latest ON (c.ticketid = latest.ticketid AND c.commdate = latest.max_commdate)
JOIN users u ON (c.userid = i._id)
WHERE t.status = 5
ORDER BY t._id DESC, c.commdate DESC

Related

converting subquery to join in postgresql

select p.postid postid,p.posttypeid posttypeid,
(select count(parentid) as no_of_answers from post
where parentid=p.postid), p.title title,
p.body body ,
p.creationdate creationdate,
p.modifieddate modifieddate,
p.modifieduserid modifieduserid,
p.score score,p.views no_of_views,
u.userid userid
from post
as p
left outer join user_quest as u on p.owneruserid = u.userid
where p.posttypeid = 1
Order by p.creationdate desc
LIMIT 10 OFFSET 0;
I need to convert his subquery to join, please help
You could use CTE:
WITH counts AS (
SELECT
count(parentid) AS no_of_answers,
parentid
FROM post
GROUP BY parentid
)
SELECT
p.postid,
p.posttypeid,
p.title,
COALESCE(c.no_of_answers, 0) AS no_of_answers,
p.body,
p.creationdate,
p.modifieddate,
p.modifieduserid,
p.score,
p.views AS no_of_views,
u.userid
FROM post AS p
LEFT JOIN counts c ON (c.parentid = p.postid)
LEFT JOIN user_quest AS u ON (p.owneruserid = u.userid)
WHERE p.posttypeid = 1
ORDER BY p.creationdate DESC
LIMIT 10 OFFSET 0;
or put yours subquery to JOIN:
SELECT
p.postid,
p.posttypeid,
p.title,
COALESCE(c.no_of_answers, 0) AS no_of_answers,
p.body,
p.creationdate,
p.modifieddate,
p.modifieduserid,
p.score,
p.views AS no_of_views,
u.userid
FROM post AS p
LEFT JOIN
(
SELECT
count(parentid) AS no_of_answers,
parentid
FROM post
GROUP BY parentid
) c ON (c.parentid = p.postid)
LEFT JOIN user_quest AS u ON (p.owneruserid = u.userid)
WHERE p.posttypeid = 1
ORDER BY p.creationdate DESC
LIMIT 10 OFFSET 0;
But I would prefer CTE. The performance of CTEs and subqueries should, in theory, be the same since both provide the same information to the query optimizer. One difference is that a CTE used more than once could be easily identified and calculated once. And it's look pretties because is easier to read, at least i thing so.

Selecting multiple fields from row with max value of column, per group

I'm quite certain I've painted myself into a corner and I can't figure my way out.
The Users table and OrderHistories tables both have 1+ million records:
SELECT
u.Id ,
u.Email AS EmailAddress ,
c.Address_Address1 AS "Address 1" ,
(
SELECT
COUNT(*)
FROM
dbo.OrderHistories oh
WHERE
oh.UserId = u.UserName
) AS NumberOfOrders ,
Carts.SubtotalAmount AS CartTotal ,
(
SELECT
MAX(oh.CreateDate)
FROM
dbo.OrderHistories AS oh
WHERE
oh.UserId = u.Id
) AS LastOrderDate ,
(
SELECT
LastOrders.SubtotalAmount AS LastOrderSubtotal
FROM
(
SELECT
UserId ,
CreateDate ,
SubtotalAmount ,
MAX(CreateDate) OVER ( PARTITION BY UserId ) MyLastOrderDate
FROM
Users u
INNER JOIN dbo.OrderHistories oh
ON u.Id = oh.UserId
) AS LastOrders
WHERE
LastOrders.MyLastOrderDate = LastOrders.CreateDate
AND LastOrders.UserId = u.Id
) AS LastOrderSubtotal
FROM
Users u
INNER JOIN Customers AS c
ON u.Id = c.Id
LEFT JOIN dbo.Carts
ON c.Id = Carts.CustomerId
This particular subquery is my current problem (EXTREMELY inefficient), but I'm not experienced enough to understand exactly why, or how I should be doing it instead (I can't get there from here!):
(
SELECT
LastOrders.SubtotalAmount AS LastOrderSubtotal
FROM
(
SELECT
UserId ,
CreateDate ,
SubtotalAmount ,
MAX(CreateDate) OVER ( PARTITION BY UserId ) MyLastOrderDate
FROM
Users u
INNER JOIN dbo.OrderHistories oh
ON u.Id = oh.UserId
) AS LastOrders
WHERE
LastOrders.MyLastOrderDate = LastOrders.CreateDate
AND LastOrders.UserId = u.Id
) AS LastOrderSubtotal
Anyone mind telling me how terrible I am and then segue right into a suggested improvement?
Just from looking at your query, you may be able to simplify it using cross apply() like so:
select
u.Id
, EmailAddress = u.Email
, [Address 1] = c.Address_Address1
, CartTotal = Carts.SubtotalAmount
, NumberOfOrders = oh.NumberOfOrders
, LastOrderDate = oh.CreateDate
, LastOrderSubtotal = oh.SubtotalAmount
from Users u
inner join Customers AS c
on u.Id = c.Id
left join dbo.Carts
on c.Id = Carts.CustomerId
cross apply (
select top 1
i.CreateDate
, i.SubtotalAmount
, NumberOfOrders = count(*) over (partition by i.UserId)
from dbo.OrderHistories i
where i.UserId = u.Id
order by i.CreateDate desc
) as oh
If you want rows that may not have an OrderHistory, switch to outer apply().
Reference:
apply() - msdn
The power of T-SQL's APPLY operator - Rob Farley
APPLY: It Slices! It Dices! It Does It All! - Brad Shulz

SQL with limit by result

I am making a simple chat, and need a way to get only 10 "messages" pr. conversation, but can't figure out how to do so.
This is what i already have tried.
my SQL:
SELECT c.* FROM chat c
INNER JOIN users su ON su.id = c.sender_user_id
INNER JOIN users ru ON ru.id = c.receiver_user_id
WHERE sender_user_id='1234' OR receiver_user_id='1234'
ORDER BY created ASC
Now i get ALL the messages for user ID 1234 ... BUT i only want 10 messages pr. conversation.
Hope it make sense
The standard SQL way is to use window/analytic functions:
SELECT t.*
FROM (SELECT c.*, su.name as sender_name, ru.name as receiver_name,
row_number() over (partition by c.conversation order by c.created desc) as seqnum
FROM chat c INNER JOIN
users su
ON su.id = c.sender_user_id INNER JOIN
users ru
ON ru.id = c.receiver_user_id
WHERE sender_user_id = '1234' OR receiver_user_id = '1234'
) t
WHERE seqnum <= 10
ORDER BY created ASC;
Note that you need to do a better job of selecting the columns you want in the subquery. Using * will result in duplicate column names.
EDIT:
In MySQL, you can do this using variables:
SELECT t.*
FROM (SELECT c.*, su.name as sender_name, ru.name as receiver_name,
(#rn := if(#c = c.conversation, #rn + 1,
if(#c := c.conversation, 1, 1)
)
) as seqnum
FROM chat c INNER JOIN
users su
ON su.id = c.sender_user_id INNER JOIN
users ru
ON ru.id = c.receiver_user_id CROSS JOIN
(SELECT #c := 0, #rn := 0) vars
WHERE sender_user_id = '1234' OR receiver_user_id = '1234'
ORDER BY c.conversation, c.created desc
) t
WHERE seqnum <= 10
ORDER BY created ASC;

sql syntax group by

Struggling with this as i'm not good with sql and designer wont work with the OVER use. Basically this is getting a list of topics if the user is following an associated tag.
I need to group by T.TopicId to stop duplicates. If a user is selecting more than one tag associated with a topic it will list the topic twice (once for each tag)
When I add a group by in sql I get multiple errors and i've tried rearranging things and cant get it to work, As said i'm useless with sql statements
#id int = null
AS
SELECT
*
FROM
(SELECT
ROW_NUMBER()
OVER
(ORDER BY TopicOrder desc
,
(CASE
WHEN M.MessageCreationDate > T.TopicCreationDate THEN M.MessageCreationDate
ELSE T.TopicCreationDate
END) desc)
AS RowNumber
,T.TopicId, T.TopicTitle, T.TopicShortName, T.TopicDescription, T.TopicCreationDate, T.TopicViews, T.TopicReplies, T.UserId, T.TopicTags, T.TopicIsClose,
T.TopicOrder, T.LastMessageId, T.UserName, M.MessageCreationDate, M.UserId AS MessageUserId, MU.UserName AS MessageUserName, U.UserGroupId,
U.UserPhoto, T.UserFullName
FROM Tags INNER JOIN
TopicsComplete AS T ON T.TopicId = Tags.TopicId LEFT OUTER JOIN
Messages AS M ON M.TopicId = T.TopicId AND M.MessageId = T.LastMessageId AND M.Active = 1 LEFT OUTER JOIN
Users AS MU ON MU.UserId = M.UserId LEFT OUTER JOIN
Users AS U ON U.UserId = T.UserId LEFT OUTER JOIN
tagfollows AS TF ON #id = TF.userid
WHERE (Tags.Tag = TF.tag)
)T
If anyone could help it would be much appreciated, thanks! :)
I think you only need to convert the join to tagfollows into an EXISTS subquery (and remove the redundant nesting):
SELECT
ROW_NUMBER()
OVER ( ORDER BY TopicOrder desc
, CASE WHEN M.MessageCreationDate > T.TopicCreationDate
THEN M.MessageCreationDate
ELSE T.TopicCreationDate
END desc )
AS RowNumber,
T.TopicId, T.TopicTitle, T.TopicShortName, T.TopicDescription,
T.TopicCreationDate, T.TopicViews, T.TopicReplies, T.UserId,
T.TopicTags, T.TopicIsClose, T.TopicOrder, T.LastMessageId,
T.UserName, M.MessageCreationDate,
M.UserId AS MessageUserId,
MU.UserName AS MessageUserName,
U.UserGroupId, U.UserPhoto, T.UserFullName
FROM
TopicsComplete AS T
LEFT OUTER JOIN
Messages AS M ON M.TopicId = T.TopicId
AND M.MessageId = T.LastMessageId
AND M.Active = 1
LEFT OUTER JOIN
Users AS MU ON MU.UserId = M.UserId
LEFT OUTER JOIN
Users AS U ON U.UserId = T.UserId
WHERE EXISTS
( SELECT *
FROM Tags
INNER JOIN tagfollows AS TF
ON Tags.Tag = TF.tag
WHERE T.TopicId = Tags.TopicId
AND #id = TF.userid
) ;
You say you want to show posts with tags in the set that the user is following, but you don't want the post to show up multiple times when it has multiple matching tags. That's a perfect use for an EXISTS subquery. Here's an example from that MSDN page.
SELECT a.FirstName, a.LastName
FROM Person.Person AS a
WHERE EXISTS
(SELECT *
FROM HumanResources.Employee AS b
WHERE a.BusinessEntityID = b.BusinessEntityID
AND a.LastName = 'Johnson');
You're really interested in the person table (like your posts table), but you want to show records that have at least one matching record in employee (like your tags table).

Grab only the last post from all topics in a category from phpbb

I want to only grab the last post of all topics in a category (Category->Forum->Topic->Post) from a phpbb database in a single query. Currently I have cooked up this, but it returns only the first post, not the last.
SELECT *, MAX(p.post_id)
FROM phpbb_forums f, phpbb_topics t, phpbb_posts p
WHERE f.parent_id IN (<categories>)
AND t.forum_id = f.forum_id
AND p.topic_id = t.topic_id
GROUP BY p.topic_id
Does anybody know how to correctly do this?
SELECT *
FROM phpbb_forums f
JOIN phpbb_topics t
ON t.forum_id = f.forum_id
JOIN phpbb_posts p
ON p.post_id =
(
SELECT pi.post_id
FROM phpbb_posts pi
WHERE pi.topic_id = t.topic_id
ORDER BY
pi.date DESC
LIMIT 1
)
WHERE f.parent_id IN (…)