JPQL Group By - Limit ResultSet - group-by

I've a JPQL like this:
SELECT T0.id, T0.info, COUNT(T0.entry) AS count_entry FROM myObject AS T0 WHERE T0.someValue = 1 GROUP BY T0.id, T0.info
I want to get the first 100 results of this. The problem I have is, that if I declare maxResults-Parameter, the ROWNUM <= 100 is added to the where-clause. The where clause is evaluated before the grouping takes place - so I do not get 100 results in resultlist, I get less because of the grouping.
Any ideas to limit the result set AFTER grouping?

I found the solution. If you add an order-by clause, the problem is solved and the limitation of the number of results is in an extra query around the other query.
Query working as expected:
SELECT T0.id, T0.info, COUNT(T0.entry) AS count_entry FROM myObject AS T0 WHERE T0.someValue = 1 GROUP BY T0.id, T0.info ORDER BY T0.id

Related

Postgresql SUM calculated column

I am trying to create some sql to calculate the worth of a users inventory and have manage to get it to work up to the final step.
SELECT DISTINCT ON (pricing_cards.card_id)
(inventory_cards.nonfoil * pricing_cards.nonfoil) + (inventory_cards.foil * pricing_cards.foil) as x
FROM inventory_cards
INNER JOIN pricing_cards ON pricing_cards.card_id = inventory_cards.card_id
WHERE inventory_cards.user_id = 1
ORDER BY pricing_cards.card_id, pricing_cards.date DESC;
The code above bring back a single column that has the correct calculation for card. I now need to sum this column together but keep getting errors when I try to sum it.
Adding SUM((inventory_cards.nonfoil * pricing_cards.nonfoil) + (inventory_cards.foil * pricing_cards.foil)) throws the following error
ERROR: column "pricing_cards.card_id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 6: ORDER BY pricing_cards.card_id, pricing_cards.date DESC;
Adding GROUP BY pricing_cards.card_id, pricing_cards.date seems to fix the errors but is returning the same column of calculated values.
so:
SELECT DISTINCT ON (pricing_cards.card_id)
SUM((inventory_cards.nonfoil * pricing_cards.nonfoil) + (inventory_cards.foil * pricing_cards.foil)) as x
FROM inventory_cards
INNER JOIN pricing_cards ON pricing_cards.card_id = inventory_cards.card_id
WHERE inventory_cards.user_id = 1
GROUP BY pricing_cards.card_id, pricing_cards.date
ORDER BY pricing_cards.card_id, pricing_cards.date DESC;
Returns:
x
0.71
29.92
25.67
171.20
0.32
0.26
I suggest you use a subquery to get the latest pricing data, then join and sum:
SELECT
SUM(inventory_cards.nonfoil * latest_pricing.nonfoil + inventory_cards.foil * latest_pricing.foil)
FROM inventory_cards
INNER JOIN (
SELECT DISTINCT ON (card_id)
card_id, nonfoil, foild
FROM pricing_cards
ORDER BY pricing_cards.card_id, pricing_cards.date DESC
) AS latest_pricing USING (card_id)
WHERE inventory_cards.user_id = 1
For alternatives in the subquery, see also Select first row in each GROUP BY group? and Optimize GROUP BY query to retrieve latest row per user.

In Firebird, how to aggregate the first N rows?

I would like to do something like this:
CNT=2;
//[edit]
select avg(price) from (
select first :CNT p.Price
from Price p
order by p.Date desc
);
This does not work, Firebird does not allow :cnt as a parameter to FIRST. I need to average the first CNT newest prices. The number 2 changes so it can not be hard-coded.
This can be broken out into a FOR SELECT loop and break when a count is reached. Is that the best way though? Can this be done in a single SQL statement?
Creating the SQL as a string and running it is not the best fit either. It is important that the database compile my SQL statement.
You don't have to use CTE, you can do it directly:
select avg(price) from (
select first :cnt p.Price
from Price p
order by p.Date desc
);
You can use a CTE (Common Table Expression) (see http://www.firebirdsql.org/refdocs/langrefupd21-select.html#langrefupd21-select-cte) to select data before calculate average.
See example below:
with query1 as (
select first 2 p.Price
from Price p
order by p.Date desc
)
select avg(price) from query1

How to use the AS name in a query WHERE clause?

given a query like so:
SELECT
id,
(SELECT COUNT(*)
FROM members
WHERE members.network_id = networks.id) AS mem_count
FROM
networks
WHERE mem_count > 2
With this query, the where clause breaks as it does not know what mem_count is... Why can't I use the as var in the where clause?
Thanks
While bernie suggested correct answer to the question, your query can be simplified to:
SELECT
network_id as id,
count(*)
FROM
members
GROUP BY
network_id
HAVING
count(*) > 2
Which, as an additional bonus, can be faster.
You've got the concept down. You just need the right syntax. You could re-write like this and have the added benefit of making your query ANSI-compliant:
SELECT
id,
m.mem_count
FROM
networks n
JOIN (
SELECT m.network_id,
COUNT(*) AS mem_count
FROM members
GROUP BY m.network_id
) m
ON m.network_id = n.id
AND m.mem_count > 2;
Try:
SELECT
id,
(SELECT COUNT(*) as mem_count
FROM members
WHERE members.network_id = networks.id)
FROM
networks
WHERE mem_count > 2
One way would be.
Select * From (
SELECT
id,
(SELECT COUNT(*)
FROM members
WHERE members.network_id = networks.id) AS mem_count
FROM
networks)) mem_counts
WHERE mem_count > 2
A join as suggested by Bernie would be better though. Basically you confused the parser. You get the same sort of issue with group by or order by when you use AS to alias a column name.

What's the best T-SQL syntax to filter for an ID that has a count of X or at least X or at most X in a joined table?

What's the best way to do something like this in T-SQL?
SELECT DISTINCT ID
FROM Members,
INNER JOIN Comments ON Members.MemberId = Comments.MemberId
WHERE COUNT(Comments.CommentId) > 100
Trying to get the members who have commented more than 100 times. This is obviously invalid code but what's the best way to write this?
This should get you what you're after. I'm not saying this is the absolutely best way of doing it, but it's unlikely you'll find anything better.
SELECT ID
FROM Members
INNER JOIN Comments
ON Members.MemberId = Comments.MemberId
GROUP BY ID
HAVING COUNT(*) > 100
I like using a subquery.
SELECT DISTINCT m.ID
FROM Members m
WHERE (SELECT COUNT(c.CommentID)
FROM Comments c
WHERE c.MemberID = m.MemberID) > 100
Try
SELECT ID
FROM Members
INNER JOIN (SELECT MemberID FROM Comments
GROUP BY MemberID HAVING COUNT(CommentId) > 100)
AS CommentCount ON Members.MemberID = CommentCount.CommentID

T-SQL Query not bringing back a count of 0

I have a feeling I am making some sort of foolish mistake here, however I am trying to do a query over two tables. One table contains the value I want to aggregate over, in this case I have called if the StoreCharge table. The other table contains the values I want to count.
SELECT StoreCharge.StoreId,
COUNT(DISTINCT(ISNULL(WholesalerInvoice.WholesalerId,0))) AS Invoices
FROM StoreCharge
LEFT OUTER JOIN
WholesalerInvoice ON StoreCharge.StoreId = WholesalerInvoice.StoreId
WHERE StoreCharge.CompanyId = 2
AND WholesalerInvoice.StoreInvoiceId IS NULL
AND DATEDIFF(day,WholesalerInvoice.InvoiceDate,'20100627') > =0
AND DATEDIFF(day,dateadd(day,-7,'20100627'),WholesalerInvoice.InvoiceDate) > 0
GROUP BY StoreCharge.StoreId
My problem is that if there are rows in the counting table that match the WHERE clause, the query works ok. However When no rows match the criteria nothing is returned instead of a list of the values in StoreCharge with a count of 0.
WHERE is evaluated after the LEFT OUTER JOIN
Try moving your WHERE filter related to WholesalerInvoice into the OUTER JOIN
SELECT StoreCharge.StoreId,
COUNT(DISTINCT(ISNULL(WholesalerInvoice.WholesalerId,0))) AS Invoices
FROM StoreCharge
LEFT OUTER JOIN
WholesalerInvoice ON StoreCharge.StoreId = WholesalerInvoice.StoreId
AND DATEDIFF(day,WholesalerInvoice.InvoiceDate,'20100627') > =0
AND DATEDIFF(day,dateadd(day,-7,'20100627'),WholesalerInvoice.InvoiceDate) > 0
WHERE StoreCharge.CompanyId = 2
GROUP BY StoreCharge.StoreId
This will filter the required WholesalerInvoice records out and leave the StoreCharge table intact.
Based on the query in the example, you don't actually use what you join in. Unless there is more to the query a Subquery would produce the desired result.
SELECT StoreCharge.StoreId,
(SELECT COUNT(0) FROM WholesalerInvoice WHERE WholesalerInvoice.StoreId = StoreCharge.StoreId
AND DATEDIFF(day,WholesalerInvoice.InvoiceDate,'20100627') > =0
AND DATEDIFF(day,dateadd(day,-7,'20100627'),WholesalerInvoice.InvoiceDate) > 0) [Invoices]
FROM StoreCharge
WHERE StoreCharge.CompanyId = 2