Sort by SQL Count Used in WHERE Clause in ActiveRecord Scope - sql

I'm trying to get a calculated column used during a scope declaration "where" clause passed on so that it is then useable in the returned set. I've tried this many different ways, and none work. Ultimately, what I am trying to accomplish is to ORDER the returned set by that count. Here is my scope so far:
scope :used_in_past, ->(days_ago) {
where('(SELECT count(*) as total_tasks FROM grouptask WHERE creatorstudentid = sid AND creationdate > ?) > 0', Date.today-days_ago)
}
I'd like to "ORDER BY" total_tasks, and also hopefully pass it on to be used in a view. Whenever I try to use that named column it just says it doesn't exist, though.

Maybe in the SQL sentence you could do that, with Alias or Function
SELECT COUNT(sid) AS total_tasks
FROM grouptask
WHERE creatorstudentid = sid AND creationdate>0
GROUP BY sid
ORDER BY COUNT(sid);
I didn't see in your statement the GROUP BY section if you are using Aggregation Function Maybe you required
I hope this answer could help you
Regards

Related

Ecto Fragment interpolating var in group_by

I am trying to the following:
query =
from s in State,
group_by:
fragment("date_part(?, ?)", ^group, s.timestamp_start),
select:
{fragment("date_part(?, ?)", ^group, s.timestamp_start), count(s.id)}
Repo.all(query)
Where group might be one of ['minute', 'hour', 'day'].
However, I get the following error:
ERROR 42803 (grouping_error) column "s0.timestamp_start" must appear in the GROUP BY clause or be used in an aggregate function
But if I add s.timestamp_start to group_by clause, I don't get the expected result, since dates are grouped by timestamp_start and not by the part defined.
How can I do this without having to specify a query to each group possibility (passing the literal value inside fragment) ?
Found the answer here.
You can use as in fragments to reference eachother:
from(m in Message,,
group_by: fragment("timestamp"),
select: fragment("date_trunc(?, ?) as timestamp", ^timeseries, m.inserted_at)
)
When you do group by, everything you select has to be related to the group by, or use one of the aggregation functions. Since you're grouping by year, month, etc, the DB wouldn't know which timestamp_start to show in that row. If you want to show all of the timestamps for that particular row, you can use a fragment that builds out what would end up being string_agg(s.timestamp_start, ',')

SQLite alias (AS) not working in the same query

I'm stuck in an (apparently) extremely trivial task that I can't make work , and I really feel no chance than to ask for advice.
I used to deal with PHP/MySQL more than 10 years ago and I might be quite rusty now that I'm dealing with an SQLite DB using Qt5.
Basically I'm selecting some records while wanting to make some math operations on the fetched columns. I recall (and re-read some documentation and examples) that the keyword "AS" is going to conveniently rename (alias) a value.
So for example I have this query, where "X" is an integer number that I render into this big Qt string before executing it with a QSqlQuery. This query lets me select all the electronic components used in a Project and calculate how many of them to order (rounding to the nearest multiple of 5) and the total price per component.
SELECT Inventory.id, UsedItems.pid, UsedItems.RefDes, Inventory.name, Inventory.category,
Inventory.type, Inventory.package, Inventory.value, Inventory.manufacturer,
Inventory.price, UsedItems.qty_used as used_qty,
UsedItems.qty_used*X AS To_Order,
ROUND((UsedItems.qty_used*X/5)+0.5)*5*CAST((X > 0) AS INT) AS Nearest5,
Inventory.price*Nearest5 AS TotPrice
FROM Inventory
LEFT JOIN UsedItems ON Inventory.id=UsedItems.cid
WHERE UsedItems.pid='1'
ORDER BY RefDes, value ASC
So, for example, I aliased UsedItems.qty_used as used_qty. At first I tried to use it in the next field, multiplying it by X, writing "used_qty*X AS To_Order" ... Query failed. Well, no worries, I had just put the original tab.field name and it worked.
Going further, I have a complex calculation and I want to use its result on the next field, but the same issue popped out: if I alias "ROUND(...)" AS Nearest5, and then try to use this value by multiplying it in the next field, the query will fail.
Please note: the query WORKS, but ONLY if I don't use aliases in the following fields, namely if I don't use the alias Nearest5 in the TotPrice field. I just want to avoid re-writing the whole ROUND(...) thing for the TotPrice field.
What am I missing/doing wrong? Either SQLite does not support aliases on the same query or I am using a wrong syntax and I am just too stuck/confused to see the mistake (which I'm sure it has to be really stupid).
Column aliases defined in a SELECT cannot be used:
For other expressions in the same SELECT.
For filtering in the WHERE.
For conditions in the FROM clause.
Many databases also restrict their use in GROUP BY and HAVING.
All databases support them in ORDER BY.
This is how SQL works. The issue is two things:
The logic order of processing clauses in the query (i.e. how they are compiled). This affects the scoping of parameters.
The order of processing expressions in the SELECT. This is indeterminate. There is no requirement for the ordering of parameters.
For a simple example, what should x refer to in this example?
select x as a, y as x
from t
where x = 2;
By not allowing duplicates, SQL engines do not have to make a choice. The value is always t.x.
You can try with nested queries.
A SELECT query can be nested in another SELECT query within the FROM clause;
multiple queries can be nested, for example by following the following pattern:
SELECT *,[your last Expression] AS LastExp From (SELECT *,[your Middle Expression] AS MidExp FROM (SELECT *,[your first Expression] AS FirstExp FROM yourTables));
Obviously, respecting the order that the expressions of the innermost select query can be used by subsequent select queries:
the first expressions can be used by all other queries, but the other intermediate expressions can only be used by queries that are further upstream.
For your case, your query may be:
SELECT *, PRC*Nearest5 AS TotPrice FROM (SELECT *, ROUND((UsedItems.qty_used*X/5)+0.5)*5*CAST((X > 0) AS INT) AS Nearest5 FROM (SELECT Inventory.id, UsedItems.pid, UsedItems.RefDes, Inventory.name, Inventory.category, Inventory.type, Inventory.package, Inventory.value, Inventory.manufacturer, Inventory.price AS PRC, UsedItems.qty_used*X AS To_Order FROM Inventory LEFT JOIN UsedItems ON Inventory.id=UsedItems.cid WHERE UsedItems.pid='1' ORDER BY RefDes, value ASC))

Query to update values in a table with averages from the same table

I'm looking for a bit of support regarding using a value from a separate query in an update query. The background is that i have a query calle qry_AvgOfXCoeff which calculates the average of tbl_ConvertToDouble.XCoeff. What i would like to do is replace any Xcoeff value that is greater than 0 with the avg calculated in the first query. At present i cannot use the qry directly in an Update query as i received the dreaded 'Must use a updateable query' error.
qry_AvgOfXCoeff:
SELECT Avg(tbl_ConvertToDouble.XCoeff) AS [Avg]
FROM tbl_ConvertToDouble;
Now i've been informed that i should be able to do this by using an IN condition in the update query, but im really stumped with this one and cannot seem to find any examples of how i would implement this. I've had a play with some code as per below, but please can someone help with this. It seems such a simple thing.
UPDATE qry_AvgOfXCoeff, tbl_ConvertToDouble SET tbl_ConvertToDouble.[Xcoeff]
WHERE (( ( tbl_ConvertToDouble.[xcoeff] ) IN (SELECT [qry_AvgOfCoeff].[Avg]
FROM [qry_AvgOfCoeff] AS Tmp
Where [tbl_ConvertToDouble].[Xcoeff] > 0) ))
ORDER BY tbl_calcreg.[xcoeff];
Thank you kindly in advance.
Donna
Access offers Domain Aggregate Functions that can be helpful in avoiding the "Operation must use an updateable query" issue. In this case, you can use the DAvg() function
UPDATE tbl_ConvertToDouble
SET XCoeff = DAvg("XCoeff", "tbl_ConvertToDouble")
WHERE XCoeff>0

NHibernate: row/result counting: Projection.RowCount() VS. Projection.Count()

What is the exact difference between NHibernates
Projection.RowCount()
and
Projection.Count()
when we are looking for number of rows/results?
Projection.Count expects you to pass a property that you want a count on i.e
Projection.Count("propertyName")
which transalates to the following in SQL
select Count(this.whateverNhibernateConvention) from table as this
where as for Projection.RowCount you dont need to pass anything which translates to
select Count(1) from table as this
I think I expect the above to be the case

Group by SQL statement

So I got this statement, which works fine:
SELECT MAX(patient_history_date_bio) AS med_date, medication_name
FROM biological
WHERE patient_id = 12)
GROUP BY medication_name
But, I would like to have the corresponding medication_dose also. So I type this up
SELECT MAX(patient_history_date_bio) AS med_date, medication_name, medication_dose
FROM biological
WHERE (patient_id = 12)
GROUP BY medication_name
But, it gives me an error saying:
"coumn 'biological.medication_dose' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.".
So I try adding medication_dose to the GROUP BY clause, but then it gives me extra rows that I don't want.
I would like to get the latest row for each medication in my table. (The latest row is determined by the max function, getting the latest date).
How do I fix this problem?
Use:
SELECT b.medication_name,
b.patient_history_date_bio AS med_date,
b.medication_dose
FROM BIOLOGICAL b
JOIN (SELECT y.medication_name,
MAX(y.patient_history_date_bio) AS max_date
FROM BIOLOGICAL y
GROUP BY y.medication_name) x ON x.medication_name = b.medication_name
AND x.max_date = b.patient_history_date_bio
WHERE b.patient_id = ?
If you really have to, as one quick workaround, you can apply an aggregate function to your medication_dose such as MAX(medication_dose).
However note that this is normally an indication that you are either building the query incorrectly, or that you need to refactor/normalize your database schema. In your case, it looks like you are tackling the query incorrectly. The correct approach should the one suggested by OMG Poinies in another answer.
You may be interested in checking out the following interesting article which describes the reasons behind this error:
But WHY Must That Column Be Contained in an Aggregate Function or the GROUP BY clause?
You need to put max(medication_dose) in your select. Group by returns a result set that contains distinct values for fields in your group by clause, so apparently you have multiple records that have the same medication_name, but different doses, so you are getting two results.
By putting in max(medication_dose) it will return the maximum dose value for each medication_name. You can use any aggregate function on dose (max, min, avg, sum, etc.)