Transforming Raw Sql to Laravel equolent - sql

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');

Related

Typo3 9.5 - Custom flexform ordering, wrong backquotes in sql

i have an custom extension, where you can select the different entries at the backend, to show them at the list view. I have a custom sorting at my backend, but the system always sort them Descending.
I implemented an "orderBy" function, which doesnt work, because the system uses wrong backspaces.
My code looks like this:
I call the sort function in my "findByUid($uid)" function like this:
$query->setOrderings($this->orderByKey('uid', $uidArray));
protected function orderByKey($key, $uidlist) {
$order = array();
foreach ($uidlist as $uid) {
//$order["$key=$uid"] = \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_DESCENDING;
$order["$key=$uid"] = "ASC";
\TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump($order);
}
return $order;
}
The result at the sql query is:
ORDER BY `tx_MYEXTENSION_domain_model_FIELD`.`uid=3` DESC
But it must be:
ORDER BY `tx_MYEXTENSION_domain_model_FIELD`.`uid` = 3 DESC
Is there a way to change this?
After a lot of search, I found this solution on an stackoverflow entry:
$ids = explode(',',$this->settings['entries'])
foreach($ids as $key => $id){
$entries[$id] = $this->entriesRepository->findByUid($id);
}
This code snippet has to be intergrated at the controller.
For me its working.

codeigniter change complex query into active record

I have a codeigniter app.
My active record syntax works perfectly and is:
function get_as_09($q){
$this->db->select('m3');
$this->db->where('ProductCode', $q);
$query = $this->db->get('ProductList');
if($query->num_rows > 0){
foreach ($query->result_array() as $row){
$row_set[] = htmlentities(stripslashes($row['m3'])); //build an array
}
return $row_set;
}
}
This is effectively
select 'm3' from 'ProductList' where ProductCode='$1'
What I need to do is convert the below query into an active record type query and return it to the controller as per above active record syntax:
select length from
(SELECT
[Length]
,CONCAT(([width]*1000),([thickness]*1000),REPLACE([ProductCode],concat(([width]*1000),([thickness]*1000),REPLACE((convert(varchar,convert(decimal(8,1),length))),'.','')),'')) as options
FROM [dbo].[dbo].[ProductList]) as p
where options='25100cr' order by length
I picture something like below but this does not work.
$this->db->select(length);
$this->db->from(SELECT [Length],CONCAT(([width]*1000),([thickness]*1000),REPLACE[ProductCode],concat(([width]*1000),([thickness]*1000),REPLACE((convert(varchar,convert(decimal(8,1),length))),'.','')),'')) as options
FROM [dbo].[dbo].[ProductList]);
$this->db->where(options, $q);
$this->db->order(length, desc);
Help appreciated as always. Thanks again.
You can use sub query way of codeigniter to do this for this purpose you will have to hack codeigniter. like this
Go to system/database/DB_active_rec.php Remove public or protected keyword from these functions
public function _compile_select($select_override = FALSE)
public function _reset_select()
Now subquery writing in available And now here is your query with active record
$select = array(
'Length'
'CONCAT(([width]*1000)',
'thickness * 1000',
'REPLACE(ProductCode, concat((width*1000),(thickness*1000),REPLACE((convert(varchar,convert(decimal(8,1),length))),'.','')),'')) as options'
);
$this->db->select($select);
$this->db->from('ProductList');
$Subquery = $this->db->_compile_select();
$this->db->_reset_select();
$this->db->select('length');
$this->db->from("($Subquery)");
$this->db->where('options','25100cr');
$this->db->order_by('length');
And the thing is done. Cheers!!!
Note : While using sub queries you must use
$this->db->from('myTable')
instead of
$this->db->get('myTable')
which runs the query.
Source

Symfony2 + Doctrine - Filtering

I've got a OneToMany relationship where one football team has many players. I want to list all football teams and display the name of the captain for each team.
Each player entity has a foreign key (team_id) and a field 'captain' which is set to 0 or 1. I'm currently running the following query:
$teams = $this
->getDoctrine()
->getRepository('FootballWebsiteBundle:Team')
->createQueryBuilder('t')
->setFirstResult(($pageNumber * $resultPerPage) - $resultPerPage)
->setMaxResults($resultPerPage)
->add('where','t.deleted = 0')
->add('orderBy', 't.name DESC')
->getQuery()->getResult();
Then when I loop through each team in twig I run team.getTeamCaptain().getName() which is a filter within my Team entity:
public function getTeamCaptain() {
$them = $this->players->filter(function($p) {
return $p->getCaptain() == 1;
});
return $them->first();
}
Is there a better way to run this query?
First of all, you may want to fetch-join the players of each retrieved team to avoid having them lazy loaded during rendering of the template. Here's the DQL:
SELECT
t, p
FROM
FootballWebsiteBundle:Team t
LEFT JOIN
t.players p
WHERE
t.deleted = 0
ORDER BY
t.name DESC
Which can be built with following query builder API calls:
$teamsQuery = $this
->getDoctrine()
->getRepository('FootballWebsiteBundle:Team')
->createQueryBuilder('t')
->addSelect('p')
->leftJoin('t.players', 'p')
->add('where','t.deleted = 0')
->add('orderBy', 't.name DESC')
->getQuery()
Then you wrap this query into a Paginator object (since setMaxResults and setFirstResult cannot be trusted when fetch-joining):
$paginator = new \Doctrine\ORM\Tools\Pagination\Paginator($teamsQuery, true);
$teamsQuery
->setFirstResult(($pageNumber * $resultPerPage) - $resultPerPage)
->setMaxResults($resultPerPage)
In your view you can then iterate on the teams like following pseudo-code:
foreach ($paginator as $team) {
echo $team->getTeamCaptain() . "\n";
}
You can also gain some extra performance in your getTeamCaptain method by using the Selectable API:
public function getTeamCaptain() {
$criteria = new \Doctrine\Common\Collections\Criteria();
$criteria->andWhere($criteria->expr()->eq('captain', 1));
return $this->players->matching($criteria)->first();
}
The advantage here is mainly relevant when the association players is not yet initialized, since this will avoid loading it entirely. This is not the case, but I consider it a good practice (instead of re-inventing collection filtering logic).

How to get the result of the join operations?

Whenever I tried to execute this sql query in a function module in drupal I am not able to get the results but when I try to execute this in MySQL I can view the result. My code looks like this :
function _get_subject_sub_category() {
$options = array();
$sql = "SELECT father.Subject_Code, child.Subject_Category
FROM {subjects} as child
INNER JOIN {subjects} as father ON (child.Parent_Category = father.Subject_Code
AND child.Level =2 )";
$result = db_query($sql);
foreach ($result as $row) {
$options[$row->father.Subject_Code] = $row->child.Subject_Category;
}
return $options;
}
The error I encountered is in the line $options[$row->father.Subject_Code] = $row->child.Subject_Category;`.
Any help will be highly appreciated.
Try changing this line:
$options[$row->father.Subject_Code] = $row->child.Subject_Category;
To this:
$options[$row->Subject_Code] = $row->Subject_Category;
The name of the table is not in the result. If you need to avoid confusion, you can use alias in your SQL query.
I don't know drupal and don't use php, but I would say :
remove
father. in $row->father.Subject_Code
and
child. in $row->child.Subject_Category
as father and child are just db aliases.

Criteria API - Using UPPER in a ElementCollection

I have a class
#Entity
public class Person{
...
#ElementCollection
private Set<String> tags;
...
}
I want to use the JPA 2.0 Criteria API to search over these tags - but in a case insensitive way. Thus I want to both set the search parameter to UPPER and the column to UPPER (Pseudo-SQL: select p.* from Person p join Tags t on p.id=t.pId where upper(t.name)=upper('searchParameter'); )
Here is my code without the UPPER on the tags:
CriteriaBuilder builder = this.em.getCriteriaBuilder();
CriteriaQuery<Person> query = builder.createQuery(Person.class);
Root<Person> root = query.from(Person.class);
return this.em.createQuery(query.select(root).where(
builder.isMember(builder.upper(builder.literal(searchTag)),
root.get(Person_.tags)))).getResultList();
where searchTag is the input parameter.
How can I assign the UPPER to the Person_.tags "Column"?
In other words I want to write this Query with Criteria API:
SELECT p FROM Person p JOIN p.tags t WHERE UPPER(t) = UPPER('searchString')
Thank you
Ok, I finally have the solution:
cQuery.where(
builder.equal(
builder.upper(cQuery.from(Relation.class).join(Relation_.aliase)
.as(String.class)),
builder.upper(builder.literal(alias))
)
);
One has to use the ".as(..)" method.
suburbCriteria = criteriaBuilder.equal(
criteriaBuilder.upper(root.get(Property_.suburb)),
criteriaBuilder.upper(criteriaBuilder.literal(searchBean.getSuburb())));
You need to call upper and literal property name on joined Tags from Person.
CriteriaBuilder builder = this.em.getCriteriaBuilder();
CriteriaQuery<Person> query = builder.createQuery(Person.class);
Root<Person> root = query.from(Person.class);
Join<Person, Tag> tags = root.join(Person_.tags);
query.where(builder.isMember(
builder.upper(builder.literal(searchTag)),
builder.upper(builder.literal(tags.get(Tag_.name)))
));
return this.em.createQuery(query).getResultList();
I omitted query.select(root), not sure if it is required.
Tou can also omit builder.literal() on Tag_.name since is String.
If I am wrong somewhere, please edit my answer for further users.
Hope this helps.