Translate SQL query into codeigniter for joomla - php

I have written a SQL query which works fine and output provides all the data that I need:
Please see this screenshot:
This is the SQL code:
SELECT
P.name, C.project_id, C.choice_id, C.time_stamp, P.id,
P.description, T.type, P.activated
FROM
(SELECT P.*
FROM aqoru_pt_project P
JOIN
(SELECT id, MAX(creation_date) AS latestUpdate
FROM aqoru_pt_project
GROUP BY id) t ON t.id = P.id AND t.latestUpdate = P.creation_date) P
JOIN
(SELECT C.*
FROM aqoru_pt_project_choice C
JOIN
(SELECT project_id, MAX(time_stamp) AS latestDate
FROM aqoru_pt_project_choice
GROUP BY project_id) t ON t.project_id = C.project_id AND t.latestDate = C.time_stamp) C ON P.id = C.project_id
LEFT JOIN
aqoru_community_groups_members CGM ON P.group_id = CGM.groupid
INNER JOIN
aqoru_pt_project_type T ON P.type_id = T.id
WHERE
P.user_id = 569 OR CGM.memberid = 569
AND CGM.permissions = 1
AND P.deactivated != 1
GROUP BY
P.id
ORDER BY
P.id;
Now I need to push it into php format I was trying without great success as I am struggling mainly with the part where I try to put Join in select on the very beginning of the code. Definitely the part after ON P.id = C.project_id works fine. The problem occurs when I try to add max value from other table.
This is the code I wrote, but it does not work:
public function getProjects($userID)
{
$db = JFactory::getDbo();
$query = $db->getQuery(true);
$columns = array('P.id', 'P.name', 'P.description', 'T.type', 'P.activated');
$query
->select(array('P.id', 'P.name', 'P.description', 'T.type', 'P.activated', 'max(C.time_stamp) as max'))
->from($db->quoteName(
->SELECT ('P.*')
->FROM ($db->quoteName('aqoru_pt_project', 'P')
->JOIN($db->quoteName(
->SELECT ('id', 'MAX(creation_date) AS latestUpdate')
->FROM ($db->quoteName('aqoru_pt_project')
->group($db->quoteName('id')) 't' . ' ON t.id = P.id AND t.latestUpdate = P.creation_date') P
->JOIN(
->SELECT ('C.*')
->FROM ($db->quoteName('aqoru_pt_project_choice', 'C')
->JOIN($db->quoteName(
->SELECT ('project_id', 'MAX(time_stamp) AS latestDate')
->FROM ($db->quoteName('aqoru_pt_project_choice'))
->group($db->quoteName('id')) 't' . ' ON t.project_id = P.project_id AND t.latestUpdate = P.time_stamp') 'C' . 'ON P.id = C.project_id'
))
->leftjoin($db->quoteName('#__community_groups_members', 'CGM') . ' ON P.group_id = CGM.groupid')
->innerjoin($db->quoteName('#__pt_project_type', 'T') . ' ON P.type_id = T.id')
->where(
$db->quoteName('P.user_id') . ' = ' . $db->quote($userID),
)
->orwhere(array(
$db->quoteName('CGM.memberid') . ' = ' . $db->quote($userID),
$db->quoteName('CGM.permissions') . ' = 1'
))
->andwhere($db->quoteName('P.deactivated') . ' != 1')
->group($db->quoteName('P.id'))
->order('P.id DESC');
/*
* Note: for some reason the queries return duplicates on the production site not on my local site
* So we must group by projectID to avoid duplicates. I am not aware what is causing this duplication
*/
return $db->setQuery($query)->loadObjectList();
}

try this
$this->db->select('P.name,C.project_id,C.choice_id,C.time_stamp,P.id,P.description,T.type,P.activated')
->from('(SELECT P.*
FROM aqoru_pt_project P
JOIN
(SELECT id, MAX(creation_date) AS latestUpdate
FROM aqoru_pt_project
GROUP BY id) t ON t.id = P.id AND t.latestUpdate = P.creation_date) P')
->join('(SELECT C.*
FROM aqoru_pt_project_choice C
JOIN
(SELECT project_id, MAX(time_stamp) AS latestDate
FROM aqoru_pt_project_choice
GROUP BY project_id) t ON t.project_id = C.project_id AND t.latestDate = C.time_stamp) C', 'P.id = C.project_id')
->join('aqoru_community_groups_members CGM', 'P.group_id = CGM.groupid', 'LEFT')
->join('aqoru_pt_project_type T', 'P.type_id = T.id')
->where('P.user_id', 569)
->or_where('CGM.memberid', 569)
->where('CGM.permissions', 1)
->where('P.deactivated !=', 1)
->group_by('P.id')
->order_by('P.id ASC')
->get();

Related

Query working on localhost but not on live server

My database query works fine on localhost but showing error on a live server. Same code i'm using in another server and it works just fine. I'm using Mysql (localhost version 5.5.54-0ubuntu0.14.04.1) and live server (5.7.10-0ubuntu0.16.04.1).
This is the error i'm getting:
A Database Error Occurred
Error Number: 1055
Expression #10 of SELECT list is not in GROUP BY clause and contains
nonaggregated column 'imanage_asd.lut.log_text' which is not
functionally dependent on columns in GROUP BY clause; this is
incompatible with sql_mode=only_full_group_by
The code:
SELECT u.id, u.user, u.email, u.full_name, u.stat,
GROUP_CONCAT(distinct(ar.role)) as roles, GROUP_CONCAT(distinct(g.title)) as group_names,
count(lug.user_id) as login_times, MAX(lug.created_at) as last_login, lut.log_text,
lut.created_at as log_text_date, mobile FROM users as u LEFT JOIN
group_users as gu ON gu.user_id = u.id LEFT JOIN groups as g ON g.id = gu.group_id
LEFT JOIN user_roles as ur ON ur.user_id = u.id LEFT JOIN access_roles as ar ON
ar.id = ur.role_id LEFT JOIN log_user_login as lug ON lug.user_id = u.id LEFT JOIN
log_user_texts as lut ON lut.user_id = u.id AND lut.id = (SELECT l.id FROM log_user_texts l
WHERE u.id = l.user_id ORDER BY l.id DESC LIMIT 1) WHERE u.id > 1 GROUP BY u.id
Filename: modules/admin/models/Users_model.php
Line Number: 84
This is my Code:
<?php
$query = $this->db->select('u.id, u.user, u.email, u.full_name, u.stat, GROUP_CONCAT(distinct(ar.role)) as roles, '
. 'GROUP_CONCAT(distinct(g.title)) as group_names, count(lug.user_id) as login_times, MAX(lug.created_at) as last_login, '
. 'lut.log_text, lut.created_at as log_text_date, mobile')
->join(static::T_GROUP_USERS . ' as gu', 'gu.user_id = u.id', 'left')
->join(static::T_GROUPS . ' as g', 'g.id = gu.group_id', 'left')
->join(static::T_USER_ROLES . ' as ur', 'ur.user_id = u.id', 'left')
->join(static::T_ROLES . ' as ar', 'ar.id = ur.role_id', 'left')
->join(static::T_LOG_USER_LOGIN . ' as lug', 'lug.user_id = u.id', 'left')
->join(static::T_LOG_USER_TEXTS . ' as lut', 'lut.user_id = u.id AND '
. 'lut.id = (SELECT l.id FROM log_user_texts l WHERE u.id = l.user_id ORDER BY l.id DESC LIMIT 1)', 'LEFT')
->where('u.id > 1')->group_by('u.id')->get(static::T_USERS . ' as u');
I will appreciate any kind of help.
Thanks
I think that this is the key to your problem this is incompatible with sql_mode=only_full_group_by.
Take a look at this Disable ONLY_FULL_GROUP_BY.
It could be that your database on live server has this option enabled, but on your localhost is probably disabled.
A quick solution could be using the following statement before your select query to set sql_mode to none.
$this->db->query("SET sql_mode = ''");
$query = $this->db->select(...
...
Obviously, you should update the query by adjusting the joins in a convinient time.

MySQL Query for HTML table using filters, COUNT, GROUP BY / LIMIT / ORDER BY and sub-queries

I got a query that blows my head off for about 2 days, and I need some help. Pleeeaaze !
What I need to do is get data form described tables below and the output must display every message for each application using filters on customer.(name, codeX/Y/Z), application.(name, wave), migrationLabel.label, migrationMessage.(dates) using pagination (50 per pages).
Each application can display 0 to n messages and I have to make an HTML table using attribute "rowspan".
Here are the tables :
"# : PK"
"# : FK"
application(#id, label, #customerId)
customer(#id, name, codeX, codeY, codeZ)
erpApplication(#id, label, #customerId)
migrationMessage(#applicationId, creationTime, closureDate, previsionalDate, #labelId, #authorId)
migrationLabel(#id, label, ordering)
works(#employeeId, #applicationId, #roleId)
employee(#id, username)
Here is the current Query :
<?php
$query = 'SELECT
c.id AS customerId, c.name AS customerName, c.X3Code, c.mfgProCode, c.as400Code, c.jdeCode,
a.id AS appId, a.label AS appName, a.wave,
mm.closureDate, mm.previsionalDate, mm.content,
ml.id, ml.label,
q.msgCount
FROM (
SELECT a.id
FROM `application` a
JOIN `customer` c ON c.id = a.customerId
ORDER BY c.name
) l
JOIN application a ON a.id = l.id
JOIN `customer` c ON c.id = a.customerId
LEFT JOIN (
SELECT applicationId, COUNT(*) AS msgCount
FROM application a
JOIN migrationMessage mm ON mm.applicationId = a.id
JOIN migrationLabel ml ON ml.id = mm.labelId
JOIN customer c ON c.id = a.customerId
' . $where . '
GROUP BY applicationId
LIMIT ' . $limit . ' OFFSET ' . $offset . '
) q ON q.applicationId = a.id
LEFT JOIN `migrationMessage`mm ON mm.applicationId = q.applicationId
LEFT JOIN `migrationLabel` ml ON ml.id = mm.labelId
JOIN `works` w ON w.applicationId = a.id '
. ($user->isOperator() ? ' AND w.roleId = ' . Role::Rri : ' AND w.employeeId = ' . $user->id)
. ' JOIN employee e ON e.id = w.employeeId'
. ($user->isJustUser() ? ' AND e.siteId = ' . $user->siteId : '')
. $where
. ' ORDER BY c.name, a.label, ml.ordering'
. 'LIMIT ' . $limit . ' OFFSET ' . $offset;
Almost everything works using this query, the problem happens when I got an application with several messages which get itself on 2 pages...
For example, "rowspan" (msgCount in the query) is 5 but the 3 last messages are on a different page than the first 2 and then the HTML display is completely erroneous. See HTML result
I wrote my query from scratch and come with a result that completely fit my needs.
For those who wondered, the key is the RIGHT JOIN'ed query :
<?php
$query = 'SELECT
c.id AS customerId, c.name AS customerName, c.X3Code, c.mfgProCode, c.as400Code, c.jdeCode,
a.id AS appId, a.label AS appName, a.wave,
mm.closureDate, mm.previsionalDate, mm.content,
ml.id, ml.label,
q0.msgCount
FROM application a
JOIN customer c ON c.id = a.customerId
LEFT JOIN migrationMessage mm ON mm.applicationId = a.id
LEFT JOIN migrationLabel ml ON ml.id = mm.labelId
JOIN `works` w ON w.applicationId = a.id '
. ($user->isOperator() ? ' AND w.roleId = ' . Role::Rri : ' AND w.employeeId = ' . $user->id)
. ' JOIN employee e ON e.id = w.employeeId'
. ($user->isJustUser() ? ' AND e.siteId = ' . $user->siteId : '')
. ' LEFT JOIN (
SELECT applicationId, COUNT(*) AS msgCount
FROM application a
JOIN migrationMessage mm ON mm.applicationId = a.id
JOIN migrationLabel ml ON ml.id = mm.labelId
JOIN customer c ON c.id = a.customerId
GROUP BY applicationId
) q0 ON q0.applicationId = a.id
RIGHT JOIN (
SELECT a.id
FROM application a
JOIN customer c ON c.id = a.customerId
LEFT JOIN migrationMessage mm ON mm.applicationId = a.id
LEFT JOIN migrationLabel ml ON ml.id = mm.labelId
' . $where . '
GROUP BY a.id
ORDER BY c.name, a.label, ml.ordering
LIMIT ' . $limit . ' OFFSET ' . $offset . '
) q1 ON q1.id = a.id
ORDER BY c.name, a.label, ml.ordering'

Issue with an mySQL sentence including two temporary table creation

I have a mySQL sentence that works like a charm if I execute it in my phpMyAdmin:
CREATE TEMPORARY TABLE hash1
SELECT * FROM
(
(
SELECT DISTINCT feature_id AS fl, feature_value AS fv FROM gf_product_features WHERE feature_id = '1' AND feature_value = 'No frost total'
) UNION
(
SELECT DISTINCT feature_id AS fl, feature_value AS fv FROM gf_product_features WHERE feature_id = '3' AND feature_value = '43'
)) AS q;
CREATE TEMPORARY TABLE hash2
SELECT * FROM hash1;
SELECT
p.id AS id,
p.main_image AS main_image,
p.type AS taxonomy,
p.name AS model,
p.sku AS sku,
p.price AS price,
b.brand_name AS brand_name,
b.brand_image AS brand_logo,
pf.feature_value AS feature_value,
f.feature AS feature_label,
f.id AS feature_id
FROM
(
SELECT a.*
FROM gf_product AS a
INNER JOIN
(
SELECT product_id
FROM
(
SELECT a.product_id , count(*) AS commons
FROM gf_product_features AS a
INNER JOIN hash1 AS b
ON a.feature_id = b.fl
AND a.feature_value = b.fv
GROUP BY a.product_id
) AS features
WHERE commons = (SELECT count(*) AS count FROM hash2)
) b1 ON a.id = b1.product_id
) AS p
INNER JOIN gf_brands AS b
ON p.brand_id = b.id
INNER JOIN gf_product_features AS pf
ON pf.product_id = p.id
INNER JOIN gf_features AS f
ON pf.feature_id = f.id
ORDER BY price ASC,
feature_id ASC
I want to execute a php function through Ajax request, that constructs dinamically the sql sentence above, but I'm always getting this error in my browser's console:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CREATE TEMPORARY TABLE hash2
SELECT * FROM hash1;
SELECT
' at line 12
And thus, the following error too:
Warning: mysqli_fetch_assoc() expects parameter 1 to be mysqli_result, boolean given in /www/htdocs/example/inc/functions.php on line 538
Which corresponds to this line of my php code:
while ($row = mysqli_fetch_assoc($result))
Maybe clone hash2 table from hash1 table
CREATE TEMPORARY TABLE hash2
SELECT * FROM hash1;
sounds weird, but if I don't do this in that way, in my phpMyAdmin I get this error:
#1137 - Can't reopen table: 'b'
I can't realize why my sql sentence works fine in my phpMyadmin but, when I construct it on my php file it doesn't works. Can anybody help me, please?
For further information, this is my PHP code:
function getProductsFromFilteredQuery($connection, $filters, &$html)
{
$sql = '';
$m = count($filters); // $filters are an array of values like this: ['value1A, value2A', 'value1B, value2B', ...]
$sql = 'CREATE TEMPORARY TABLE hash1
SELECT * FROM
(';
for ($n = 0; $n < $m; $n++)
{
$string = explode(', ', $filters[$n]);
$feature_id = $string[0];
$feature_value = $string[1];
$sql .= "
(
SELECT DISTINCT feature_id AS fl, feature_value AS fv FROM gf_product_features WHERE feature_id = '" . $feature_id . "' AND feature_value = '" . $feature_value . "'
)";
if ($n < ($m - 1))
{
$sql .= ' UNION ';
}
}
$sql .= ') AS q;
CREATE TEMPORARY TABLE hash2 -- In this line I get an error
SELECT * FROM hash1;
SELECT
p.id AS id,
p.main_image AS main_image,
p.type AS taxonomy,
p.name AS model,
p.sku AS sku,
p.price AS price,
b.brand_name AS brand_name,
b.brand_image AS brand_logo,
pf.feature_value AS feature_value,
f.feature AS feature_label,
f.id AS feature_id
FROM
(
SELECT a.*
FROM gf_product AS a
INNER JOIN
(
SELECT product_id
FROM
(
SELECT a.product_id , count(*) AS commons
FROM gf_product_features AS a
INNER JOIN hash1 AS b
ON a.feature_id = b.fl
AND a.feature_value = b.fv
GROUP BY a.product_id
) AS features
WHERE commons = (SELECT count(*) AS count FROM hash2)
) b1 ON a.id = b1.product_id
) AS p
INNER JOIN gf_brands AS b
ON p.brand_id = b.id
INNER JOIN gf_product_features AS pf
ON pf.product_id = p.id
INNER JOIN gf_features AS f
ON pf.feature_id = f.id
ORDER BY price ASC,
feature_id ASC';
$result = mysqli_query($connection, $sql);
while ($row = mysqli_fetch_assoc($result)) // In this line I get an error too
{
// Do some stuff... and at last, return the resulting $html
}
};
I finally could find the error. In my phpMyAdmin it worked as well because someone can execute several queries in the SQL console. There is no problem with it.
However, when coding an mySQL query through PHP you only can run one mySQL sentence at once. Well, there is an exception: You can use mysqli_multi_query + mysqli_more_results, or something like these. But as I was coded it, you can't.
So there is two options: rewrite the PHP code like described in the pages of the two links above, or doing several mysqli_query within the PHP function.
I decided to do it through the second option, so the working code is the following (Notice the comments after each mysqli_query):
function getProductsFromFilteredQuery($mysqli, $filters, &$html) {
$sql = '';
$m = count($filters);
$sql = 'DROP TEMPORARY TABLE IF EXISTS hash1;';
$result = mysqli_query($mysqli, $sql); // A single query
$sql = 'DROP TEMPORARY TABLE IF EXISTS hash2;';
$result = mysqli_query($mysqli, $sql); // Another single query
$sql = 'CREATE TEMPORARY TABLE hash1
SELECT * FROM
(';
for ($n = 0; $n < $m; $n++)
{
$string = explode(', ', $filters[$n]);
$feature_id = $string[0];
$feature_value = $string[1];
$sql .= "
(SELECT DISTINCT feature_id AS fl, feature_value AS fv FROM gf_product_features WHERE feature_id = '" . $feature_id . "' AND feature_value = '" . $feature_value . "')";
if ($n < ($m - 1))
{
$sql .= ' UNION ';
}
}
$sql .= ') AS q1';
$result = mysqli_query($mysqli, $sql); // Another single query
$sql = 'CREATE TEMPORARY TABLE hash2
SELECT * FROM hash1;';
$result = mysqli_query($mysqli, $sql); // Another single query
$sql = 'SELECT
p.id AS id,
p.main_image AS main_image,
p.type AS taxonomy,
p.name AS model,
p.sku AS sku,
p.price AS price,
b.brand_name AS brand_name,
b.brand_image AS brand_logo,
pf.feature_value AS feature_value,
f.feature AS feature_label,
f.id AS feature_id
FROM
(
SELECT a.*
FROM gf_product AS a
INNER JOIN
(
SELECT product_id
FROM
(
SELECT a.product_id , count(*) AS commons
FROM gf_product_features AS a
INNER JOIN hash1 AS b
ON a.feature_id = b.fl
AND a.feature_value = b.fv
GROUP BY a.product_id
) AS features
WHERE commons = (SELECT count(*) AS count FROM hash2)
) b1 ON a.id = b1.product_id
) AS p
INNER JOIN gf_brands AS b
ON p.brand_id = b.id
INNER JOIN gf_product_features AS pf
ON pf.product_id = p.id
INNER JOIN gf_features AS f
ON pf.feature_id = f.id
ORDER BY price ASC,
feature_id ASC';
$result = mysqli_query($mysqli, $sql); // Another single query. The last one.
while ($row = mysqli_fetch_assoc($result))
{
// My stuff here...
}
}; // #END of function

Convert SQL to Doctrine

I want to convert this sql query for the entity manager of doctrine :
SELECT count(c.id)
FROM content c
WHERE c.id IN
(SELECT tdtc.content_id
FROM tdtheme_content tdtc
JOIN tdtheme tdt ON tdtc.tdtheme_id = tdt.id
JOIN td t ON tdt.td_id = t.id
JOIN matiere m ON t.matiere_id = m.id
WHERE m.id = 2)
OR c.id IN
(SELECT sc.content_id
FROM semaine_content sc
JOIN semaine s ON sc.semaine_id = s.id
JOIN cour cr ON s.cour_id = cr.id
JOIN matiere m ON cr.matiere_id = m.id
WHERE m.id = 2)
OR c.id IN
(SELECT ac.content_id
FROM annale_content ac
JOIN annale a ON ac.annale_id = a.id
JOIN matiere m ON a.matiere_id = m.id
WHERE m.id = 2)');
I have :
Matiere With Annale And Td And Cours
Annale With Contents
Td With Tdtheme With Contents
Cours With Semaines With Contents
And I want to get count of contents for one matiere
Any Idea ?
Thanks and sorry for my bad English ^^
Assuming your entity names are Content, TdTheme_Content, etc.
$repo = $em->getRepository('AppBundle:Content');
$query = $repo ->createQueryBuilder('c');
$subQuery1 = $query->createSubquery();
$subQuery1
->select('tdtc.contentId')
->from('TdTheme_Content tdtc')
->join('tdtc.tdTheme tdt') // Doctrine joins by property names, not column names
->join('tdt.td t')
->join('t.matiere m')
->where('m.id = ?', 2)
;
// Assume similar for $subQuery2 and $subQuery3
$query
->select('COUNT(c.id)')
->where('c.id IN(' . $subQuery1->getDql() ')')
->orWhere('c.id IN(' . $subQuery2->getDql() ')')
->orWhere('c.id IN(' . $subQuery3->getDql() ')')
;
NOTE: I did not debug this or attempt to execute it - this was just off the top of my head with some basic knowledge of the doctrine query-builder api.

Doctrine Select from Subquery

I am trying to run the following query via doctrine:
$sql = "SELECT league_id, sum(num_fans) AS total_fans FROM ("
."SELECT COUNT(*) as num_fans, t.id AS team_id, l.id AS league_id FROM fan_link fl "
."JOIN team t ON fl.team_id = t.id JOIN League l ON t.league_id = l.id GROUP BY fl.team_id"
.") a GROUP BY league_id LIMIT 0, 3";
$results = $this->em->createQuery($sql)->getScalarResult();
The query works fine in PHPMyAdmin, but when I try to run it in doctrine I get this error:
Doctrine\ORM\Query\QueryException [ 0 ]:
[Semantical Error] line 0, col 51 near '(SELECT COUNT(*)':
Error: Class '(' is not defined.
Is the parenthesis ( a reserved character in doctrine queries? I have subselects in where clauses elsewhere that work fine, but this one in the from clause doesn't want to work. What am I doing wrong?
Update:
I just tried using the query builder and got the same error. Code:
$qb = $this->em->createQueryBuilder();
$leagueQuery = $qb->select('league_id, sum(num_fans) AS total_fans')
->from("(SELECT count(*) as num_fans, t.id AS team_id, l.id AS league_id "
."FROM fan_link fl "
."JOIN team t ON fl.team_id = t.id "
."JOIN League l ON t.league_id = l.id GROUP BY fl.team_id)",
'a')
->groupBy("league_id")
->orderBy("total_fans", "DESC")
->setMaxResults(3)
->getQuery();
$results = $leagueQuery->getArrayResult();
Ended up using this:
$sql = "SELECT league_id, sum(num_fans) AS total_fans FROM "
."(SELECT COUNT(*) as num_fans, t.id AS team_id, l.id AS league_id FROM fan_link fl "
."JOIN team t ON fl.team_id = t.id JOIN League l ON t.league_id = l.id GROUP BY fl.team_id"
.") a GROUP BY league_id LIMIT 0, 3";
$q = $this->em->getConnection();
$league_results = $q->fetchAll($sql);
Spend many hours while got this working!
You could do that with createNativeQuery()
Here are working example:
$rsm = new ResultSetMapping();
$rsm->addScalarResult('c1', 'c1');
$rsm->addScalarResult('b1', 'b1');
$qb = $manager->createNativeQuery("
SELECT SUM(RESULTS.totalHours) AS c1, SUM(RESULTS.totalDuration) AS b1
FROM
(
SELECT S.totalHours, S.totalDuration
FROM S
INNER JOIN SV ON S.specificationId = SV.id
LEFT JOIN SToTagRel ST ON S.id = ST.specificationId
LEFT JOIN T ON ST.tagId = T.id
GROUP BY S.id
) AS RESULTS
", $rsm);
$qb->getSingleResult();

Categories