HAVING CLAUSE LIMITATION - sql

I'm working on a SQL code for my work, so I will make the question general.
When I use a count function, in my having clause, I've set the condition as
COUNT(ED.TRANSACTION_KEY) > QP.MIN_OCCURRENCES.
I've passed both ED and QP tables. It seems if I change the condition to COUNT(ED.TRANSACTION_KEY) > 3, the code works. However, once I set the conditions based on two parameters, the system shows "not a GROUP BY expression". Please advice.

You need to either use an aggregation function:
HAVING COUNT(ED.TRANSACTION_KEY) > MIN(QP.MIN_OCCURRENCES)
or move QP.MIN_OCCURRENCES to the GROUP BY clause.

Related

Django ORM filter multiple fields using 'IN' statement

So I have the following model in Django:
class MemberLoyalty(models.Model):
date_time = models.DateField(primary_key=True)
member = models.ForeignKey(Member, models.DO_NOTHING)
loyalty_value = models.IntegerField()
My goal is to have all the tuples grouped by the member with the most recent date. There are many ways to do it, one of them is using a subquery that groups by the member with max date_time and filtering member_loyalty with its results. The working sql for this solution is as follows:
SELECT
*
FROM
member_loyalty
WHERE
(date_time , member_id) IN (SELECT
max(date_time), member_id
FROM
member_loyalty
GROUP BY member_id);
Another way to do this would be by joining with the subquery.
How could i translate this on a django query? I could not find a way to filter with two fields using IN, nor a way to join with a subquery using a specific ON statement.
I've tried:
cls.objects.values('member_id', 'loyalty_value').annotate(latest_date=Max('date_time'))
But it starts grouping by the loyalty_value.
Also tried building the subquery, but cant find how to join it or use it on a filter:
subquery = cls.objects.values('member_id').annotate(max_date=Max('date_time'))
Also, I am using Mysql so I can not make use of the .distinct('param') method.
This is a typical greatest-per-group query. Stack-overflow even has a tag for it.
I believe the most efficient way to do it with the recent versions of Django is via a window query. Something along the lines should do the trick.
MemberLoyalty.objects.all().annotate(my_max=Window(
expression=Max('date_time'),
partition_by=F('member')
)).filter(my_max=F('date_time'))
Update: This actually won't work, because Window annotations are not filterable. I think in order to filter on window annotation you need to wrap it inside a Subquery, but with Subquery you are actually not obligated to use a Window function, there is another way to do it, which is my next example.
If either MySQL or Django does not support window queries, then a Subquery comes into play.
MemberLoyalty.objects.filter(
date_time=Subquery(
(MemberLoyalty.objects
.filter(member=OuterRef('member'))
.values('member')
.annotate(max_date=Max('date_time'))
.values('max_date')[:1]
)
)
)
If event Subqueries are not available (pre Django 1.11) then this should also work:
MemberLoyalty.objects.annotate(
max_date=Max('member__memberloyalty_set__date_time')
).filter(max_date=F('date_time'))

Wrong SQL query executed in influxDB

I execute wrong query with clause Group By but it execute successfully.
As we know Group By clause used with an aggregate function or the GROUP BY clause and throw error.
SELECT * FROM "CSTable"."autogen"."sampleTable" GROUP BY "NAME" FILL(null)
So can anyone light on this query and why it is successfully executed in InfluxDB.
Well, technically it would be the same as if you didn't have the group by tag clause. Group by tag does not limit the number of datapoints that influxdb can return, hence it can just return all of them as they are. That is why you are probably not getting an error. Whether an error should be produced in this case is separate question.
If you however group by time() (instead of, or in addition to, a tag) then you would need to provide an aggregate function.

Decode not working

I can't seem to figure out why this won't work - can someone please help? This is part of a larger query, so I don't want to have to update the one that already exists - just wanna add to it -
SELECT INNERPART.*,
SUBSTR(status_remday, 1,1) AS COMPLETE,
**--this line shows if it is completed or not**
DECODE(SUBSTR(status_remday, 1,1),'Y','Complete','N','Incomplete', null) AS qualCompleted,
**--need this to show if the curriculum is complete or not, in it's own row. will eventually have about 10 or more qual_ids**
decode(INNERPART.qualID,'ENG_CURR_SAFETY CERT', qualCompleted) as SAFETY
FROM (Innerpart)
The problem is that the SQL syntax (the Oracle dialect, anyway) doesn't allow you to define an alias in a SELECT clause and then reference the same alias in the same SELECT clause (even if it's later in the clause).
You define qualCompleted as a DECODE, and then you reference qualCompleted in the second DECODE. That won't work.
If you don't want to define qualCompleted at one level and then wrap everything within an outer SELECT where you can reference that name, your other option is to use the first DECODE, as is (not by alias) in the second DECODE.
This:
decode(INNERPART.qualID,'ENG_CURR_SAFETY CERT', qualCompleted) as SAFETY
should instead be written as
decode(INNERPART.qualID,'ENG_CURR_SAFETY CERT',
DECODE(SUBSTR(status_remday, 1,1),'Y','Complete','N','Incomplete', null) )
as SAFETY
One more thing: by default, DECODE returns null if the first parameter is not matched in DECODE. So you don't actually need to give the last parameter (null) in your definition of qualCompleted.
EDIT: here is what the Oracle documentation says about column aliases.
Link: https://docs.oracle.com/database/121/SQLRF/statements_10002.htm#i2080424
c_alias Specify an alias for the column expression. Oracle Database will use this alias in the column heading of the result set.
The AS keyword is optional. The alias effectively renames the select
list item for the duration of the query. The alias can be used in
the order_by_clause but not other clauses in the query.
This means a few things. An alias like the qualCompleted you created cannot be used in the same query in the WHERE clause, GROUP BY, etc. - and not even in the SELECT clause where it was created. It can ONLY be used in the ORDER BY clause of the same query. Any other use must be in a surrounding, "outer" query. It also does mean, though, that you can use it in ORDER BY, if needed.
In your case, if you ONLY created qualCompleted so that you can reference it in another DECODE, and had no other use for it, then you don't even need to define it at all (since it doesn't help anyway); just define SAFETY directly as a nested call to DECODE.

LookupRecord in SQL statement with WHERE clause does not work

Background
I am creating a database to tracks lab samples. I wish to put a restriction in place that prevents a technician from reporting multiple results for the same sample.
Current strategy
My query called qselReport lists all samples being reported.
SELECT tblResult.strSampleName, tblResult.ysnReport FROM tblResult WHERE (((tblResult.ysnReport)=True));
When a technician wishes to report a result for a given sample, I use a Before Change Event to check for that sample in qselReport (the code block below is my event macro N.B. it is not VBA).
If Updated("ysnReport") And Old.[ysnReport]=False Then
Look Up A Record In qselReport
Where Condition = [strSampleName]=[tblResult].[strSampleName]
Alias
RaiseError
Error Number 1
Error Description This sample is already being reported.
End If
That all works fine and dandy. The error message pops up if a second result is selected to report for a sample.
The problem
I like to keep things as sleek as possible, so I don't want qselReport unless it's absolutely necessary. So I made a slight adjustment to the LookupRecord block so that it operates on a SQL statement rather than on the query. Here's what that looks like (again N.B. not VBA, just a macro):
If Updated("ysnReport") And Old.[ysnReport]=False Then
Look Up A Record In SELECT tblResult.strSampleName, tblResult.ysnReport FROM tblResult WHERE [tblResult].[ysnReport]=True;
Where Condition = [strSampleName]=[tblResult].[strSampleName]
Alias
RaiseError
Error Number 1
Error Description This sample is already being reported.
End If
Now I get the error message every time that a result is reported, even if it's the first instance for that sample. From what I can tell, the issue is that the SQL statement WHERE clause does not filter the records to only those where ysnReport=True.
Can anyone explain why I can do LookupRecord in a query but not LookupRecord in an identical SQL statement? Thanks for the input.
If you want things as sleek as possible, at least performance-wise, a stored query should, in principle, outperform dynamic SQL.
Syntax-wise, I'm not familiar with the macro constructs, but I'd consider enclosing the select statement in parentheses if it accepts them and also adding an explicit alias. I suspect that alias would in turn need to be referenced in your WHERE condition:
Where Condition = MySelect.[strSampleName]=[tblResult].[strSampleName]
Alias MySelect
I found the solution to my problem. The SQL statement where clause needed to be moved to the LookupRecord data block Where condition. This works:
If Updated("ysnReport") And Old.[ysnReport]=False Then
Look Up A Record In SELECT tblResult.strSampleName, tblResult.ysnReport FROM tblResult;
Where Condition = [ysnReport]=True And [strSampleName]=[tblResult].[strSampleName]
Alias
RaiseError
Error Number 1
Error Description This sample is already being reported.
End If

Active Record embed Table.where('x').count inside of select statement

I'm setting up an AR query that is basically meant to find an average of a few values that span three different tables. I'm getting hung up on how to embed the result of a particular Count query inside of the Active Record select statement.
Just by itself, this query returns "3":
Order.where(user_id: 319).count => 3
My question is, can I embed this into a select statement as a SQL alias similar to below:
Table.xxxxxx.select("Order.where(user_id: 319).count AS count,user_id, SUM(quantity*current_price) AS revenue").xxxxx
It seems to be throwing an error and generally not recognizing what I'm trying to do when I declare that first count alias. Any ideas on the syntax?
Well, after examining a bit, I cleared my mind into the ActiveRecord select() syntax.
It's a method that can take a variable length of parameters. So, your failing :
Table.xxxxxx.select("Order.where(user_id: 319).count AS count,user_id, SUM(quantity*current_price) AS revenue").xxxxx
After replacing proper SQL for your misplaced ActiveRecord statement, should be more of like this [be careful, you can't use as count in most cases, count is reserved]:
Table.xxxxx.select("(SELECT count(id) from orders where user_id=319) as usercount", "user_id","SUM(quantity*current_price) AS revenue").xxxx
But I guess you should need more a per-user_id-table.
So, I'd skip Models and go to direct SQL, always being careful to avoid injections:
ActiveRecord::Base.connection.execute('SELECT COUNT(orders.id) as usercount, users.id from users, orders where users.id=orders.user_id group by users.id')
This is simplified of course, you can apply the rest of the data (which I currently do not know) accordingly. The above simplified, not full solution, could be written also as:
Order.joins(:user).select("count(orders.id) as usercount, users.id").group(:user_id)