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

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)

Related

MYSQL - Subquery returns more than 1 row - how to duplicate row with same userId?

Here is my subQuery, I cannot understand the error : 1242 - Subquery returns more than 1 row
SELECT DISTINCT u.id as userId,
(
SELECT a10.description
FROM Export exp
INNER JOIN Account a10 ON (a10.id = exp.accountId)
WHERE exp.isActive = 1
AND exp.platformId = 14
) as structur
FROM User u
LEFT JOIN AccountUser au ON au.userId = u.id and au.isDefault = 1
LEFT JOIN Account a ON a.id = au.accountId
WHERE u.id > 0
ORDER BY u.id ASC
LIMIT 10
ERROR : 1242 - Subquery returns more than 1 row
SELECT DISTINCT u.id as userId,
(
SELECT a10.description
FROM Export exp
Thank you for your help
Your subquery return more than a row but a row cell accept just one value so if you really need this subquery then you should limit the result
SELECT DISTINCT u.id as userId,
(
SELECT a10.description
FROM Export exp
INNER JOIN Account a10 ON (a10.id = exp.accountId)
WHERE exp.isActive = 1
AND exp.platformId = 14
LIMIT 1
) as structur
FROM User u
LEFT JOIN AccountUser au ON au.userId = u.id and au.isDefault = 1
LEFT JOIN Account a ON a.id = au.accountId
WHERE u.id > 0
ORDER BY u.id ASC
LIMIT 10
but looking to your code you could also avoid the subquery adding the join at the main query
SELECT DISTINCT u.id as userId, Account.description structur
FROM User u
LEFT JOIN AccountUser au ON au.userId = u.id and au.isDefault = 1
LEFT JOIN Account a ON a.id = au.accountId
LEFT JOIN exp ON ON Account.id = exp.accountId
AND exp.isActive = 1
AND exp.platformId = 14
WHERE u.id > 0
ORDER BY u.id ASC
LIMIT 10

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.

Cannot execute GROUP_CONCAT

I'm trying to return as GROUP_CONCAT 5 matches associated to the joined records, I tried to setup the query in the following way:
$sql = $this->db->prepare("SELECT l.*,
t.name as team_name,
r.name AS rank_name,
r.color AS rank_color,
GROUP_CONCAT(DISTINCT m.* LIMIT 5, ORDER BY m.id) AS last_five_matches,
FROM league_ranking l
LEFT JOIN team t ON l.team_id = t.id
LEFT JOIN competition_ranks r ON l.rank = r.id
LEFT JOIN `match` m ON m.home_team_id = l.team_id OR m.away_team_id = l.team_id
WHERE l.round_id = :round_id AND m.status = 5");
as you can see I want return 5 matches which have the status = 5.
The problem's that I get:
SQLSTATE[42000]: Syntax error or access violation: 1064 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 '* LIMIT 5, ORDER BY m.id) AS last_five_matches,
FROM league_ranking l
I don't understand where is the problem on the GROUP_CONCAT, notice that if I remove GROUP_CONCAT the query working, any help?
UPDATE
this is the query edited:
"SELECT l.*,
t.name as team_name,
r.name AS rank_name,
r.color AS rank_color,
GROUP_CONCAT(DISTINCT m.id ORDER BY m.id) AS last_five_matches
FROM league_ranking l
LEFT JOIN team t ON l.team_id = t.id
LEFT JOIN competition_ranks r ON l.rank = r.id
LEFT JOIN `match` m ON m.home_team_id = l.team_id OR m.away_team_id = l.team_id
WHERE l.round_id = :round_id AND m.status = 5
GROUP BY team_name"
and I get:
Syntax error or access violation: 1055 Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'swp.l.position' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
I believe you want:
SELECT t.name as team_name, r.name AS rank_name, r.color AS rank_color,
SUBSTRING_INDEX(GROUP_CONCAT(DISTINCT m.id ORDER BY m.id), ',', 5) AS last_five_matches
FROM team t LEFT JOIN
league_ranking l
ON l.team_id = t.id LEFT JOIN
competition_ranks r
ON l.rank = r.id LEFT JOIN
`match` m
ON m.home_team_id = l.team_id OR m.away_team_id = l.team_id
WHERE l.round_id = :round_id AND m.status = 5
GROUP BY t.name, r.name, r.color;
Notes:
The GROUP BY keys exactly match the unaggregated columns in the SELECT.
I removed the l.*. It doesn't make sense in the GROUP BY query.
GROUP_CONCAT() doesn't support LIMIT. Sounds like a good idea, but it doesn't exist. Instead, form the list then take the first 5 elements.
I change the JOIN order to start with team. You seem to want one row per team, so that should be the first table in the FROM.
GROUP_CONTACT is an Aggregation Operation which you need to have a GROUP BY clause describe under which values you are aggregating the records
SELECT l.*,
t.name as team_name,
r.name AS rank_name,
r.color AS rank_color,
GROUP_CONCAT(DISTINCT m.<column_name> LIMIT 5, ORDER BY m.id) AS last_five_matches,
FROM league_ranking l
LEFT JOIN team t ON l.team_id = t.id
LEFT JOIN competition_ranks r ON l.rank = r.id
LEFT JOIN `match` m ON m.home_team_id = l.team_id OR m.away_team_id = l.team_id
WHERE l.round_id = :round_id AND m.status = 5
GROUP BY team_name, rank_name, rank_color
According to the mysql documentation you can't use LIMIT statement with GROUP_CONCAT(). Try this one :
.. GROUP_CONCAT(DISTINCT m.id, ORDER BY m.id) AS last_five_matches ..

MySQL - #1066 - Not unique table/alias: 'components' with multiple inner joins

I have this query and I am getting error #1066 - Not unique table/alias: 'components'. What seems to be the issue?
SELECT COUNT(*) FROM `products`, `components`, `tradeNames`
INNER JOIN `componentsMap` ON componentsMap.product_id = product.id
INNER JOIN `components` ON componentsMap.component_id = components.id
INNER JOIN `tradeNamesMap` ON .tradeNamesMap.product_id = products.id
INNER JOIN `tradeNames` ON tradeNamesMap.tradeName_id = tradeNames.id
WHERE (((((LOWER(inci) LIKE '%abies%')
OR (trade_name.LOWER(name) LIKE '%abies%'))
OR (components.LOWER(no_cas)='abies'))
OR (components.LOWER(no_einecs)='abies'))
OR (components.LOWER(name)='abies'))
AND (`published`=1)
ORDER BY `trade_name`.`name` DESC
You don't need to list the tables before the INNER JOINs. In fact, simply don't ever use commas in the FROM clause. So:
SELECT COUNT(*)
FROM `products`
INNER JOIN `componentsMap` ON componentsMap.product_id = product.id
INNER JOIN `components` ON componentsMap.component_id = components.id
INNER JOIN `tradeNamesMap` ON tradeNamesMap.product_id = products.id
INNER JOIN `tradeNames` ON tradeNamesMap.tradeName_id = tradeNames.id
WHERE (((((LOWER(inci) LIKE '%abies%')
OR (trade_name.LOWER(name) LIKE '%abies%'))
OR (components.LOWER(no_cas)='abies'))
OR (components.LOWER(no_einecs)='abies'))
OR (components.LOWER(name)='abies'))
AND (`published`=1)
ORDER BY `trade_name`.`name` DESC;
The above query only returns one row because of the COUNT(). The order by suggests that you actually want this information for each trade_name.name. If so, you need a GROUP BY:
SELECT tn.name, COUNT(*)
FROM `products` p INNER JOIN
`componentsMap cm
ON cm.product_id = p.id INNER JOIN
`components` c
ON cm.component_id = c.id INNER JOIN
`tradeNamesMap` tnm
ON tnm.product_id = p.id INNER JOIN
`tradeNames` tn
ON tnm.tradeName_id = tn.id
WHERE ((LOWER(inci) LIKE '%abies%') OR
(tn.LOWER(name) LIKE '%abies%') OR
(c.LOWER(no_cas)='abies') OR
(c.LOWER(no_einecs)='abies') OR
(c.LOWER(name)='abies')
) AND
(`published` = 1)
GROUP BY tn.name
ORDER BY tn.`name` DESC
INNER JOIN `[components]` ON componentsMap.component_id = components.id
AND
SELECT COUNT(*) FROM `products`, [`components`], `tradeNames`
Two components are there.
Just guessing, and untested, but I suspect that something like this would do what you're after...
SELECT n.name
, COUNT(*)
FROM products p
JOIN componentsMap pc
ON pc.product_id = p.id
JOIN components c
ON c.id = pc.component_id
JOIN tradeNamesMap pn
ON pn.product_id = p.id
JOIN tradeNames n
ON n.id = pn.tradeName_id
WHERE
( inci LIKE '%abies%'
OR n.name LIKE '%abies%'
OR 'abies' IN (c.no_cas,c.no_einecs,c.name)
)
AND published = 1
GROUP
BY n.name
ORDER
BY n.name DESC

what am I doing wrong this SQL query?

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