what am I doing wrong this SQL query? - mysql

If I remove ORDER BY c.campaign_id ASC from below statement it work fine but now it throw me Sub query return more than 1 row.
SELECT SQL_CALC_FOUND_ROWS c.campaign_id,
c.title as campaign_title,
IFNULL((SELECT meta_value
FROM campaign_meta as cm
WHERE cm.campaign_id = c.campaign_id
AND cm.meta_key = 'total_viewed'), 0) AS total_viewed,
c.campaign_identifier,
c.added_datetime,
l.label_id,
l.title AS label_title,
l.color,
u.username
FROM campaigns AS c
LEFT JOIN users AS u ON u.user_id = c.author
LEFT JOIN campaign_relation AS cr ON c.campaign_id = cr.campaign_id
LEFT JOIN labels AS l ON l.label_id = cr.label_id
ORDER BY c.campaign_id ASC
LIMIT 0, 10

your sub query returns more that one row as result
(SELECT meta_value FROM campaign_meta as cm WHERE cm.campaign_id = c.campaign_id AND
cm.meta_key = 'total_viewed')
Where we need to change your query to use sytax:
SELECT ... LIMIT 1
Update it for MySQL
(SELECT meta_value FROM campaign_meta as cm WHERE cm.campaign_id = c.campaign_id AND
cm.meta_key = 'total_viewed' LIMIT 1)
or rewrite the query
out of interest to MS SQL syntax
(SELECT TOP 1 meta_value FROM campaign_meta as cm WHERE cm.campaign_id = c.campaign_id AND
cm.meta_key = 'total_viewed')

Related

How to run this complex mysql query as raw query in laravel

I have a mysql query and is working totally fine when I run this query in phpmyadmin. The raw sql query is
SELECT IF(COUNT(u.id) > 1
, GROUP_CONCAT(CONCAT(a.amenity_name, '_' ,a.id)), a.amenity_name) as m_concat
, u.id as unit_id
, u.building_id
, (uav.id) as uav_id
, a.*
FROM amenities a
JOIN amenity_values av
ON a.id = av.amenity_id
JOIN units_amenities_values uav
ON av.id = uav.amenity_value_id
JOIN units u ON u.id = uav.unit_id
where a.category_id = 370
AND a.property_id = 82
AND u.building_id = 1265
group
by u.id
order
by u.id asc
But, when I try to run the exact query as raw query in laravel it is throwing error. I am trying to run it as:
$statement = DB::select(DB::raw("SELECT IF(COUNT(u.id) > 1, GROUP_CONCAT(CONCAT(a.amenity_name, '_' ,a.id)), a.amenity_name) as m_concat, u.id as unit_id, u.building_id, (uav.id) as uav_id, a.* FROM amenities a INNER JOIN amenity_values av ON a.id = av.amenity_id INNER JOIN units_amenities_values uav ON av.id = uav.amenity_value_id INNER JOIN units u ON u.id = uav.unit_id where a.category_id = '370' AND a.property_id = '82' AND u.building_id = '1265' group by u.id order by u.id asc"));
While running the exact above statement, it throws following errors:
SQLSTATE[42000]: Syntax error or access violation: 1055 Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'amenity_db_prod.a.amenity_name' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by (SQL: SELECT IF(COUNT(u.id) > 1, GROUP_CONCAT(CONCAT(a.amenity_name, '_' ,a.id)), a.amenity_name) as m_concat, u.id as unit_id, u.building_id, (uav.id) as uav_id, a.* FROM amenities a INNER JOIN amenity_values av ON a.id = av.amenity_id INNER JOIN units_amenities_values uav ON av.id = uav.amenity_value_id INNER JOIN units u ON u.id = uav.unit_id where a.category_id = '370' AND a.property_id = '82' AND u.building_id = '1265' group by u.id order by u.id asc)

Error with ORDER BY clause using UNION in MySQL

I have the following query in MySQL:
(SELECT ue.id, ue.userid, ue.status, ue.timestart, ue.timeend, e.courseid,
e.id AS enrolid, ra.roleid
FROM user_enrolments ue
JOIN enrol e ON e.id = ue.enrolid
JOIN course c ON c.id = e.courseid
JOIN user u ON u.id = ue.userid
JOIN context ct ON ct.instanceid = c.id
LEFT JOIN role_assignments ra ON ra.userid = u.id AND
ra.contextid = ct.id AND
ra.itemid = e.id
WHERE e.customint1 = 1 AND u.deleted = 0 AND
ct.contextlevel = 50 AND (ue.status = 0 OR ue.status = 1))
UNION
(SELECT de.enrolid AS id, de.userid, de.status, de.date_ini, de.date_fin,
de.courseid, de.enrolid, de.roleid
FROM deleted_enrols de
JOIN user u ON u.id = de.userid
WHERE userid = ANY (SELECT userid FROM local_users WHERE clientid = 1))
ORDER BY u.firstname, u.lastname, c.fullname LIMIT 0, 100
If I delete ORBER BY and LIMIT, this query works fine... but the ORDER BY clause gives an error:
Table 'u' from one of the SELECTs cannot be used in global ORDER clause
If I delete the parentheses of both SELECT querys, the error is different:
Table 'u' from one of the SELECTs cannot be used in field list
I have also tried with UNION ALL, but it does not work either.
Any suggestion or clue? Thanks in advance for your time...
The results of your UNION do not include any fields from table 'u', so those results cannot be sorted by table 'u' fields.
You could perhaps perform the UNION and then re-join the results to table 'u', and then use that to sort the results by table 'u' fields. A similar issue exists for sorting on
course.fullname, so that would need to be joined back in, too.
SELECT x.id, x.userid, x.status, x.timestart, x.timeend, x.courseid, x.enrolid, x.roleid
FROM ((SELECT ue.id, ue.userid, ue.status, ue.timestart, ue.timeend, e.courseid,
e.id AS enrolid, ra.roleid
FROM user_enrolments ue
JOIN enrol e ON e.id = ue.enrolid
JOIN course c ON c.id = e.courseid
JOIN user u ON u.id = ue.userid
JOIN context ct ON ct.instanceid = c.id
LEFT JOIN role_assignments ra ON ra.userid = u.id
AND ra.contextid = ct.id
AND ra.itemid = e.id
WHERE e.customint1 = 1 AND u.deleted = 0
AND ct.contextlevel = 50 AND (ue.status = 0 OR ue.status = 1))
UNION
(SELECT de.enrolid AS id, de.userid, de.status, de.date_ini, de.date_fin,
de.courseid, de.enrolid, de.roleid
FROM deleted_enrols de
JOIN user u ON u.id = de.userid
WHERE userid = ANY (SELECT userid FROM local_users WHERE clientid = 1))
) x
JOIN user z ON z.id = x.userid
JOIN course d ON d.id = x.courseid
ORDER BY z.firstname, z.lastname, d.fullname LIMIT 0, 100
Assuming you want to sort the whole lot, try parentheses round the whole query with the ORDER BY done afterwards:
select id, userid, status, timestart, timeend, courseid, enrolid, roleid from
((SELECT ue.id, ue.userid, ue.status, ue.timestart, ue.timeend, e.courseid,
e.id AS enrolid, ra.roleid, u.firstname, u.lastname, c.fullname
FROM user_enrolments ue
JOIN enrol e ON e.id = ue.enrolid
JOIN course c ON c.id = e.courseid
JOIN user u ON u.id = ue.userid
JOIN context ct ON ct.instanceid = c.id
LEFT JOIN role_assignments ra ON ra.userid = u.id AND
ra.contextid = ct.id AND
ra.itemid = e.id
WHERE e.customint1 = 1 AND u.deleted = 0 AND
ct.contextlevel = 50 AND (ue.status = 0 OR ue.status = 1))
UNION
(SELECT de.enrolid AS id, de.userid, de.status, de.date_ini, de.date_fin,
de.courseid, de.enrolid, de.roleid, u.firstname, u.lastname, ' ' as fullname
FROM deleted_enrols de
JOIN user u ON u.id = de.userid
WHERE userid = ANY (SELECT userid FROM local_users WHERE clientid = 1))) s1
ORDER BY firstname, lastname, fullname LIMIT 0, 100
(obviously fullname in the second SELECT statement would be populated however seems sensible)
You need to include the data to be ordered by in the selects of the unioned queries; an ORDER BY following a UNION is handled as if it were SELECT * FROM (unions) ORDER BY ... so anything not coming out of the union cannot be used for ordering.
Ironically, a query similar to that is the key to getting what you want though, with something like
SELECT x, y, z
FROM (
SELECT x, y, z, somethingIdontactuallywant
FROM blah
UNION
SELECT a, b, c, somethingIdontactuallywant
FROM blah2
) AS u
ORDER BY u.somethingIdontactuallywant
As mysql documentation on union says:
This kind of ORDER BY cannot use column references that include a
table name (that is, names in tbl_name.col_name format). Instead,
provide a column alias in the first SELECT statement and refer to the
alias in the ORDER BY. (Alternatively, refer to the column in the
ORDER BY using its column position. However, use of column positions
is deprecated.)
Also, if a column to be sorted is aliased, the ORDER BY clause must
refer to the alias, not the column name.
So, do not refer to any table names and use columns that are actually in the resultset of the union.

mysql whats wrong with these this query trying to join to Select statements

Here is the query trying to join to select statements! What am i doing wrong?
​SELECT u.user_id,c.c_id,u.username,u.email, u.user_pic_path,c.time, G.file_name
FROM conversation c, users u
LEFT OUTER JOIN gallery G
ON U.user_pic_path = G.img_id
WHERE CASE
WHEN c.user_one =1
THEN c.user_two = u.user_id
WHEN c.user_two = 1
THEN c.user_one= u.user_id
END
AND (c.user_one =1 OR c.user_two = 1)
JOIN(SELECT R.time
FROM conversation_reply R
ORDER BY R.time DESC LIMIT 1)
ON R.c_id_fk = c.c_id
First query where I Join 2 tables.
SELECT u.user_id,c.c_id,u.username,u.email, u.user_pic_path,c.time, G.file_name
FROM conversation c, users u
LEFT OUTER JOIN gallery G
ON U.user_pic_path = G.img_id
WHERE CASE
WHEN c.user_one = '$user_one'
THEN c.user_two = u.user_id
WHEN c.user_two = '$user_one'
THEN c.user_one= u.user_id
END
AND (c.user_one ='$user_one' OR c.user_two ='$user_one')
Order by UNIX_TIMESTAMP(C.time) DESC Limit 20";
Finally the secound simple query.
SELECT R.cr_id,R.time,R.reply
FROM conversation_reply R
WHERE R.c_id_fk = ?
ORDER BY R.cr_id DESC LIMIT 1"
Here is what i ended up with.
$sql = "SELECT u.user_id,c.c_id,u.username,u.email, u.user_pic_path,G.file_name,
MAX(r.time) last_reply_time,r.reply
FROM conversation c
JOIN users u ON
CASE
WHEN c.user_one = 1
THEN c.user_two = u.user_id
WHEN c.user_two = 1
THEN c.user_one= u.user_id
END
JOIN conversation_reply r ON c.c_id = r.c_id_fk
LEFT OUTER JOIN gallery G ON U.user_pic_path = G.img_id
WHERE (c.user_one = 1 OR c.user_two = 1)
GROUP BY c.c_id ORDER BY last_reply_time DESC";
The only thing is I get the very first conversation reply from the conversation not the latest.
When you join with a subquery, the alias has to go after the subquery, not after the table name inside the subquery.
JOIN(SELECT time, c_id_fk
FROM conversation_reply
ORDER BY R.time DESC LIMIT 1) R
ON R.c_id_fk = c.c_id
But I'm not sure this will do what you want. This subquery finds the most recent reply across all conversations, not just conversations between the two users. If it's not a conversation by one of the two users, you'll get no results.
If you want to get the time of the most recent reply in that conversation, just do an ordinary JOIN with the conversation_reply and select MAX(time).
SELECT u.user_id,c.c_id,u.username,u.email, u.user_pic_path,c.time, G.file_name,
MAX(r.time) last_reply_time
FROM conversation c
JOIN users u ON
CASE
WHEN c.user_one =1
THEN c.user_two = u.user_id
WHEN c.user_two = 1
THEN c.user_one= u.user_id
END
JOIN conversation_reply r ON c.id = r.c_id_fk
LEFT OUTER JOIN gallery G ON U.user_pic_path = G.img_id
WHERE (c.user_one =1 OR c.user_two = 1)

MySQL SELECT in a UNION statement is not able to refer to the parent table

I'm trying to execute the following MySQL SELECT statement, to get the date of the last activity done against a every parent opportunity id.
The list of activities will be retrieved from 4 tables: calls, meetings, tasks, emails.
I'm getting a syntax error when I add the the condition "XXXXX.parent_id = opportunities.id" (in the inner 4 sub-SELECTS).
If I delete "XXXXX.parent_id = opportunities.id", the statements gets executed (but, of course, results are irrelevant to what I want).
Here is the code I'm tried:
SELECT
opportunities.id,
opportunities.name,
(
SELECT MAX(`last_activity_date`) FROM
(
SELECT c.date_end AS `last_activity_date`
FROM calls AS c
WHERE c.parent_type = 'Opportunities'
AND c.parent_id = opportunities.id
AND c.status IN ('Held')
AND c.deleted = '0'
UNION
SELECT m.date_end
FROM meetings AS m
WHERE m.parent_type = 'Opportunities'
AND m.parent_id = opportunities.id
AND m.status IN ('Held')
AND m.deleted = '0'
UNION
SELECT t.date_due
FROM tasks AS t
WHERE t.parent_type = 'Opportunities'
AND t.parent_id = opportunities.id
AND t.status IN ('Completed')
AND t.deleted = '0'
UNION
SELECT e.date_sent
FROM emails AS e
WHERE e.parent_type = 'Opportunities'
AND e.parent_id = opportunities.id
AND e.status IN ('sent', 'archived')
AND e.deleted = '0'
) AS `activities`
) AS "opportunities_activities"
FROM opportunities
WHERE opportunities.deleted = '0'
ORDER BY opportunities.id ASC
You can not use outer query fields inside the inner nested query as each inner query must be independent of any outer query.
Try query below for desired result.
SELECT
opportunities.id,
opportunities.name,
(
SELECT MAX(`last_activity_date`) FROM
(
SELECT c.date_end AS `last_activity_date`
FROM calls AS c
join opportunities o on c.parent_id = o.id
WHERE c.parent_type = 'Opportunities'
AND c.status IN ('Held')
AND c.deleted = '0'
UNION
SELECT m.date_end
FROM meetings AS m
join opportunities o on m.parent_id = o.id
WHERE m.parent_type = 'Opportunities'
AND m.status IN ('Held')
AND m.deleted = '0'
UNION
SELECT t.date_due
FROM tasks AS t
join opportunities o on t.parent_id = o.id
WHERE t.parent_type = 'Opportunities'
AND t.status IN ('Completed')
AND t.deleted = '0'
UNION
SELECT e.date_sent
FROM emails AS e
join opportunities o on e.parent_id = o.id
WHERE e.parent_type = 'Opportunities'
AND e.status IN ('sent', 'archived')
AND e.deleted = '0'
) AS `activities`
) AS "opportunities_activities"
FROM opportunities
WHERE opportunities.deleted = '0'
ORDER BY opportunities.id ASC

How to access outer table in a LEFT OUTER JOIN

In the query below, I am trying to use the first table in a left outer join. However I am getting an error.
SELECT
products.id,
products_cstm.oem_c,
products.mfr_part_num,
products.description,
products.cost,
products.assigned_user_id,
customfields_oo.ans
FROM products
LEFT OUTER JOIN (SELECT COUNT( q.id ) AS ans
, pq.product_id
FROM products_quotes pq
LEFT JOIN quotes q
ON pq.quote_id = q.id
WHERE q.deleted = 0
AND pq.deleted = 0
AND q.stage <> 4
AND (pq.qty_shipped < pq.product_qty)
AND pq.product_id = products.id
GROUP BY pq.product_id
) AS customfields_oo
ON customfields_oo.product_id = products.id
LEFT JOIN products_cstm
ON products.id = products_cstm.id_c
WHERE products.deleted = 0
ORDER BY ans DESC
When I run the query it gives me the following error:
Error Code : 1054
Unknown column 'products.id' in 'where clause'
It is not allowing first "products" table in left outer join query.
The issue is that customfields_oo is a derived table not a correlated subquery. Thus, you cannot reference the outer table from within the definition of the derived table. In this case, you cannot refer to the outer products table from within the customfields_oo definition. Instead, you must do that filter in the On clause outside the dervied table definition.
Select products.id,
products_cstm.oem_c,
products.mfr_part_num,
products.description,
products.cost,
products.assigned_user_id,
customfields_oo.ans
FROM products
Left Join (
Select pq1.product_id
, Count( q1.id ) As ans
From products_quotes As pq1
Left Join quotes As q1
On pq1.quote_id = q1.id
Where q1.deleted = 0
And pq1.deleted = 0
And q1.stage <> 4
And pq1.qty_shipped < pq1.product_qty
Group By pq1.product_id
) As customfields_oo
On customfields_oo.product_id = products.id
Left Join products_cstm
On products.id = products_cstm.id_c
Where products.deleted = 0
Order By customfields_oo.ans Desc
Now, you have stated in comments that this is too slow because, say products where deleted <> 0 might be evaluated in the derived table. If that is the case, then simply expand the derived table to include the filters on the outer products table.
Select products.id,
products_cstm.oem_c,
products.mfr_part_num,
products.description,
products.cost,
products.assigned_user_id,
customfields_oo.ans
FROM products
Left Join (
Select pq1.product_id
, Count( q1.id ) As ans
From products_quotes As pq1
Join products As p1
On p1.products.id = pq1.product_id
Left Join quotes As q1
On pq1.quote_id = q1.id
Where q1.deleted = 0
And pq1.deleted = 0
And q1.stage <> 4
And pq1.qty_shipped < pq1.product_qty
And p1.deleted = 0
Group By pq1.product_id
) As customfields_oo
On customfields_oo.product_id = products.id
Left Join products_cstm
On products.id = products_cstm.id_c
Where products.deleted = 0
Order By customfields_oo.ans Desc
You do not need to have AND pq.product_id = products.id in the where statement. Because you are LEFT JOINing on that. So I think something like this will work:
AND (pq.qty_shipped < pq.product_qty)
GROUP BY pq.product_id) AS customfields_oo
ON customfields_oo.product_id = products.id
LEFT JOIN products_cstm
ON products.id = products_cstm.id_c
WHERE products.deleted = 0
ORDER BY openorder DESC
EDIT
You do not need to LEFT JOIN on the table you are COUNTing on. You can also do ot like this:
SELECT
.....
(
SELECT
COUNT( q.id )
FROM products_quotes pq
LEFT JOIN quotes q
ON pq.quote_id = q.id
WHERE q.deleted = 0
AND pq.deleted = 0
AND q.stage <> 4
AND (pq.qty_shipped < pq.product_qty)
AND pq.product_id = products.id
) AS ans
FROM products
.....