Grails criteria groupby object - sql

Example grouping by name of the zones:
def result = User.createCriteria().list{
projections {
roles {
zones{
groupProperty("name")
}
}
}
}
but suppose I want to get the "id" or other attributes. the fact is that i want the object on the representing the group and not the string "name".
result.each{ println it.customFuncion() }
"zones" is a hasMany attribute and then i cant group by itself. What should be done, but doesnt works:
def result = User.createCriteria().list{
projections {
roles {
groupProperty("zones")
}
}
}
Is that possible? Thank you guys!

use hql for complex queries:
def result = User.executeQuery("select u.id, zone.name from User as u inner join u.roles as role inner join role.zones as zone group by u.id, zone.name")
Then you can access the result columns as follows:
result.each { row -> row[0] // u.id } // or access via defined column name
Imagine that i do not know your real hasMany collection names.

Related

Transforming Raw Sql to Laravel equolent

I have written this SQL code
SELECT drugs.*, COUNT(*) as 'views' from drugs INNER JOIN drug_seen on drugs.id = drug_seen.drug_id GROUP BY drugs.id order by views ASC
And now I am trying to write in in the Laravel equolent but I am facing some troubles.
This is what I have tried
$drugs = Drug::select(DB::raw('drugs.*,count(*) as views'))
->join('drug_seen', 'drugs.id', 'drug_seen.drug.id')
->groupBy('drug.id')->orderByRaw('views');
I am having errors like column not found i think the code is not written properly
Drug class
class Drug extends Model
{
use HasFactory;
use SoftDeletes;
...
...
...
public function drugVisits()
{
return $this->hasMany(DrugSeen::class);
}
Hop this will solve your problem.
$drugs = Drug::with('drugVisits')->get();
$drugs->count(); //for total records in drugs table.
You have typo error in join instead on drug_id you use drug.id
Try this:
$drugs = Drug::select(DB::raw('drugs.*,count(*) as views'))
->join('drug_seen', 'drugs.id', 'drug_seen.drug_id')
->groupBy('drugs.id')->orderByRaw('views');
}
As soon as you use join() you're leaving Eloquent and entering Query\Builder, losing the benefits of Model configurations in the process. And with() eager-loads aren't the answer, if you're looking to filter the results by both tables. What you want is whereHas().
Also, as far as your grouping and count manipulation there, I think you're looking more for Collection handling than SQL groups.
$drugModel = app(Drugs::class);
$results = $drugModel->whereHas('drugVisits')->with('drugVisits')->get();
$organizedResults = $results
->groupBy($drugModel->getKey())
->sortyBy(function (Drugs $drugRecord) {
return $drugRecord->drugVisits->count();
});
If you want to have a 'views' property that carries the count in the root-level element, it would look like this:
$drugModel = app(Drugs::class);
$results = $drugModel->whereHas('drugVisits')->with('drugVisits')->get();
$organizedResults = $results
->groupBy($drugModel->getKey())
->map(function (Drugs $drugRecord) {
$drugRecord->views = $drugRecord->drugVisits->count();
return $drugRecord;
});
->sortyBy('views');

Grails joinTable query issue

I have a User domain and a Role domain and a working joinTable coded on the User side as
static hasMany = [ roles: Role ]
...
static mapping = {
table 'user_data'
id column: 'employee_number', name: 'employeeNumber', generator: 'assigned', type: 'int'
version false
sort 'lastName'
roles joinTable: [ name: 'user_role' ]
}
I am trying to query the database to pull all users with a security officer role with
def roleInstance = Role.find { name == 'security_officer' }
def secList = User.findAll("from User as u where u.roles = :roleInstance", [roleInstance:roleInstance])
But I am getting the error
Class: com.microsoft.sqlserver.jdbc.SQLServerException
Message: The value is not set for the parameter number 1.
What am I doing wrong?
I figured it out with a bunch of guess and checking.
def roleInstance = Role.findByName("security_officer")
def query = User.where {
roles {
id == roleInstance.id
}
}
def securityOfficerList = query.list()
Roles is a hasMany relationship so I think following should work.
def secList = User.findAll("from User as u where u.roles in (:roleInstance)", [roleInstance:[roleInstance]])
User has many roles, so in query you can't use u.roles = roleInstance.Try to use in [list of roles] or you can try the following query:
def secList = User.findAll("from User as u where u.roles in (from Role r where r.name=:roleInstance)", [roleInstance:roleInstance])

What is the best way to go about referencing multiple tables using slick 2.0?

I have these tables: USERS, USER_ROLES, ROLES, PERMISSIONS, ROLE_PERMISSIONS
I am implementing the:
AssignedRoles (M): returns the set of roles assigned to a given user;
So, if I was going to write the query for this function it would like something like this:
SELECT role_id FROM USER_ROLES WHERE user_id = 'M'
where M is the given user id, then I would look up each role by their id and return the Role object, or I would use a join, but that is not relevant here.
so where is what my UserRole model looks like:
case class UserRole(id:Long, userID:Long, roleID:Long)
object UserRoles {
class UserRoles(tag: Tag) extends Table[UserRole](tag, "USER_ROLES") {
def id = column[Long]("ID", O.PrimaryKey, O.AutoInc)
def userID = column[Long]("USER_ID")
def roleID = column[Long]("ROLE_ID")
def user = foreignKey("USER_ID", userID, TableQuery[Users])(_.id)
def role = foreignKey("ROLE_ID", roleID, TableQuery[Roles])(_.id)
def * = (id, userID, roleID) <> (UserRole.tupled, UserRole.unapply)
}
def retrieveRoles(userID:Long) : List[Role] = {
DB.withSession { implicit session =>
userRoles.filter(_.userID === userID).list
}
}
As expected retrieveRoles returns a list of UserRoles, but I want a list of Roles, so I woulds have to write another query that will take UserRole.roleID and find it in the roles table for each of UserRole that is returned. That is a lot of queries and I feel like there is a way that will to do this in one query. Any help from the Slick experts?
userRoles.filter(_.userID === userID).flatMap(_.role)

Grails: HasMany Intersection Query

Given the following domain structure:
Book {
static hasMany = [tags: Tag]
}
Tag {
String name
}
I'm trying to find a way that given a Book I can find any other books containing any of this book's tags.
I've tried:
Book.findAllByTagsInList(myBook.tags)
But as expected the 'List in List' query isn't producing the required results.
You can use Criteria as
def books = Book.createCriteria().listDistinct{
tags{
'in'('id', myBook.tags*.id)
}
}
or use HQL as
def books = Book.executeQuery("select distinct b from Book as b \
inner join b.tags as tag \
where tag.id in (:tags)",
[tags: myBook.tags*.id])

LINQ getting Distinct values

I know there are several questions regarding this topic. However; I cannot find one that is directly related to my problem.
I have 3tables in a DB and the PK's from those 3 tables form a composite PK in a XRef table.
I need to be able to select Distinct items based on 2 of the keys just for display on a report.
public IEnumerable<AssemblyPrograms> GetProgramAssemblies()
{
var assembliesList = (from c in eModel.Assemblies.ToList()
join d in eModel.Programs_X_Assemblies_X_Builds
on c.AssemblyID equals d.AssemblyID
join p in eModel.Programs
on d.ProgramID equals p.ProgramID
join a in eModel.AssemblyTypes
on c.AssemblyTypeID equals a.AssemblyTypeID
select new AssemblyPrograms
{
AssemblyID = c.AssemblyID
,ProgramID = d.ProgramID
,AssemblyName = c.AssemblyName
,AssemblyPrefixName = c.AssemblyPrefixName
,ProgramName = p.ProgramName
,AssemblyTypeName = a.AssemblyTypeName
,AssemblyTypeID = a.AssemblyTypeID
});
return assembliesList;
}
This is my query and what I need to pull out of the tables
In my XRef table I have AssemblyID, ProgramID and BuildID as my composite PK.
There can be a many-many relationship from AssemblyID to ProgramID. The BuildID is the key that separates them.
I need to pull Distinct AssemblyID to ProgramID relationships for my report, the BuildID can be ignored.
I have tried .Distinct() in my query and a few other things to no avail.
I would appreciate any help anyone could give me.
Thanks
How about a Distinct overload that accepts a custom equality comparer? Something like this:
class AssemblyComparer : EqualityComparer<AssemblyPrograms> {
public override bool Equals(AssemblyPrograms x, AssemblyPrograms y) {
return x.ProgramID == y.ProgramID && x.AssemblyID == y.AssemblyID;
}
public override int GetHashCode(AssemblyPrograms obj) {
return obj.ProgramID.GetHashCode() ^ obj.AssemblyID.GetHashCode();
}
}