I'm running into some trouble with SQL:
Basically I'm trying to get a result set back that contains a sum of ALL questions asked to employees (grouped by company) and also add the "onetime_items" which are manually added items in a different table.
I currently have this SQL statement (I'm using MySQL):
SELECT
CONCAT_WS(
', ', count(DISTINCT CONCAT(emailaddress, '_', a.id)),
(
SELECT GROUP_CONCAT(items SEPARATOR '; ') as OneTimeItems
FROM (
SELECT CONCAT_WS(
': ', oi.item_name, SUM(oi.item_amount)
) items
FROM onetime_item oi
WHERE oi.company_id = e.company_id
AND oi.date BETWEEN '2015-12-01'
AND LAST_DAY('2015-12-01')
GROUP BY oi.item_name
) resulta
)
) as AllItems,
e.id,
LEFT(e.firstname, 1) as voorletter,
e.lastname
FROM question q
LEFT JOIN employee e ON q.employee_id = e.id
WHERE 1=1
AND YEAR(created_at) = '2015'
AND MONTH(created_at) = '12'
GROUP BY e.company_id
Now I get the following error:
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[42S22]: Column not found: 1054 Unknown column 'e.company_id' in 'where clause'
The dates used are dummy dates.
This column DOES exist in the table employee and the left join works ( I tried entering an id manually instead of using the column reference and it worked, I got the right result back)
Any idea as to why the reference to e.company_id fails?
Thanks to dba.stackexchange.com
link: https://dba.stackexchange.com/questions/126339/subquery-cant-find-column-from-superquerys-join
Answer by ypersillycubeᵀᴹ
Here's the answer that was posted there, hopefully someone else will profit as well from this!
The cause of the problem was identified by #Phil in the comments: in the comments:
Probably because it's nested too deep
You have 2 layers of nesting and the reference of table e cannot "see" through these 2 layers in MySQL.
Correlated inline subquery can usually be converted to derived tables and then LEFT joined to the other tables in the FROM clause but they have to be turned into uncorrelated (in MySQL. In other DBMS, you could use a LATERAL join or the similar OUTER APPLY.
A first rewrite to get the job done:
SELECT
CONCAT_WS(
', ', count(DISTINCT CONCAT(q.emailaddress, '_', e.id)),
dv.OneTimeItems
) as AllItems,
e.id,
LEFT(e.firstname, 1) as voorletter,
e.lastname
FROM question q
LEFT JOIN employee e ON q.employee_id = e.id
LEFT JOIN
(
SELECT company_id,
GROUP_CONCAT(items SEPARATOR '; ') AS OneTimeItems
FROM (
SELECT oi.company_id,
CONCAT_WS(
': ', oi.item_name, SUM(oi.item_amount)
) items
FROM onetime_item oi
WHERE oi.date BETWEEN '2015-12-01'
AND LAST_DAY('2015-12-01')
GROUP BY oi.company_id, oi.item_name
) resulta
GROUP BY company_id
) AS dv
ON dv.company_id = e.company_id
WHERE 1=1
AND YEAR(q.created_at) = '2015'
AND MONTH(q.created_at) = '12'
GROUP BY e.company_id ;
Test in SQLfiddle.
Unrelated to the issue comments:
There is GROUP BY e.company_id while the select list has e.id, LEFT(e.firstname, 1), e.lastname. All these will give arbitrary result from a (more or less random) employee for each company - or even in extremely rare cases arbitrary results from 2 or 3 different employees! MySQL allowed (before 5.7) such bad use of group by that could cause erroneous results. It has been fixed in 5.7 and the default settings would reject this query.
The condition:
YEAR(created_at) = '2015' AND MONTH(created_at) = '12'
cannot make use of indexes. It's better to rewrite with either BETWEEN if the column is of DATE type of with an inclusive-exclusive range condition, which works flawlessly with any datetime type (DATE, DATETIME, TIMESTAMP) of any precision:
-- use only when the type is DATE only
date BETWEEN '2015-12-01' AND LAST_DAY('2015-12-01')
or:
-- use when the type is DATE, DATETIME or TIMESTAMP
created_at >= '2015-12-01' AND created_at < '2016-01-01'
Related
I am trying to produce a result that shows duplicates in a table. One method I found for getting duplicates and showing them is to run the select statement again through an inner join. However, one of my columns needs to be the result of a function, and the only thing I can think to do is use an alias, however I can't use the alias twice in a SELECT statement.
I am not sure what the best way to run this code for getting the duplicates I need.
My code below
SELECT EXTRACT(YEAR_MONTH FROM date) as 'ndate', a.transponderID
FROM dispondo_prod_disposition.event a
inner JOIN (SELECT EXTRACT(YEAR_MONTH FROM date) as ???,
transponderID, COUNT(*)
FROM dispondo_prod_disposition.event
GROUP BY mdate, transponderID
HAVING count(*) > 1 ) b
ON ndate = ???
AND a.transponderID = b.transponderID
ORDER BY b.transponderID
SELECT b.ndate, transponderID
FROM dispondo_prod_disposition.event a
INNER JOIN ( SELECT EXTRACT(YEAR_MONTH FROM date) as ndate,
transponderID
FROM dispondo_prod_disposition.event
GROUP BY 1, 2
HAVING COUNT(*) > 1 ) b USING (transponderID)
WHERE b.ndate = ??? -- for example, WHERE b.ndate = 202201
ORDER BY transponderID
can somebody help me solving and explaining how i can get the following done? :
In my MySQL query i want to select all entries, where the forwarded_to_cordroom value is 0, and in the next row i want to have all where the value is 1, basically i could create 2 identical queries, where the only difference would be the WHERE clause (where forwarded_to_cordroom = 1 , where forwarded_to_cordroom = 0) , and i thought about doing this in one query, but getting the following error with what ive tried:
SELECT
COUNT(DISTINCT o.order_id) as count,
(SELECT o.forwarded_to_cordroom WHERE o.forwarded_to_cordroom = 1)
FROM
`orders_articles` o
LEFT JOIN orders oo ON
o.order_id = oo.order_id
WHERE
(
oo.finished_order_date IS NULL OR oo.finished_order_date >= '2021-09-27'
) AND oo.order_date <= '2021-09-27'
Results in :
#1140 - In aggregated query without GROUP BY, expression #2 of SELECT list contains nonaggregated column 'o.forwarded_to_cordroom'; this is
incompatible with sql_mode=only_full_group_by
I have also tried changing the subselect in various ways (with and without joins etc.) but without success, always the same error.
I'd prefer not turning this mode off, I think that would not be the purpose and that I can fix my query with some help.
Best Regards
Use conditional aggregation:
SELECT COUNT(DISTINCT o.order_id) AS count,
COUNT(CASE WHEN o.forwarded_to_cordroom = 1 THEN 1 END) AS count_1,
COUNT(CASE WHEN o.forwarded_to_cordroom = 0 THEN 1 END) AS count_0
FROM orders_articles AS o
LEFT JOIN orders AS oo ON o.order_id = oo.order_id
WHERE ...
I need to select records for review based a nutty set of factors primarily from two tables, supplementing additional data from a third. here are the factors:
is it annual, and not overridden? (stays annual)
OR it is NOT annual, BUT IS overridden? (WAS biennial, but now is annual)
OR does the searchYear match the even/oddness of the recordYear?
(this handles biennial cases that would qualify for the searchYear)
AND finally does it match the searchQtr? (because this is a quarterly summary)
so based on that, here's my query that i've assembled (and is throwing an error):
select ar.id as eNum, ar.quarter as qtr, dd.description as device, ar.building_name AS bldgName, ir.inspectorName
from (select * from asset_roster) ar
join device_descriptions dd on ar.descriptionID = dd.id
left join inspector_roster ir on ar.inspectorID = ir.id
where ar.id not in ( select eNumber from safety_report )
and ( ( (dd.annual = '1' and ar.override = '0') or
(dd.annual = '0' and ar.override = '1') ) or
( (select mod( left(ar.quarter,2))) = '1') )
and ( right(ar.quarter,2) = 'Q2' )
group by bldgName asc;
so this query fails with this message:
Error in query (1064): Syntax error near ')) = '1') ) and ( right(ar.quarter,2) = 'Q2' ) group by bldgName asc' at line 8
some things to note: the query up to the first and works on it's own. and the last and, above the group by... works as well. so I've narrowed it to the group of nested ands. sadly, I'm unable to unravel exactly what the issue is here. which is why this post now exists.
I am trying to create a summary output to show a totals based on values in sub queries and then group the output by a label
Query looks like:
select c.name,
(select sum(duration) from dates d
inner join time t1 on d.time_id=t1.id
where d.employee=t.employee
and d.date >= now() - INTERVAL 12 MONTH) as ad,
(select sum(cost) from dates d
inner join time t1 on d.time_id=t1.id
where d.employee=t.employee
and d.date >= now() - INTERVAL 12 MONTH) as ac
FROM time t
inner join employees ee on t.employee=ee.employee
inner join centres c on ee.centre=c.id
where
ee.centre in (4792,4804,4834) group by c.centre
I want this to show me the ad and ac for each centre but instead it only shows values for ac for the last centre in the list and the rest show as zero
If I remove the group by then I get a list of all the entries but then it is not summarised in any way and I need that rollup view
A SQL statement that is returning a result that is unexpected is not a whole lot to go on.
Without a specification, helpfully illustrated with sample data and expected output, we're just guessing at the result that the query is supposed to achieve.
I think the crux of the problem is the value of t.employee returned for the GROUP BY, multiple detail rows with a variety of values for t.employee are getting collapsed into a single row for each value of c.centre, and the value of t.employee is from "some row" in the set. (A MySQL-specific non-standard extension allows the query to run without throwing an error, where other RDBMS would throw an error. We can get MySQL behavior more inline with the standard by including ONLY_FULL_GROUP_BY in `sql_mode. But that would just cause the SQL in the question to throw an error.)
Suggested fix (just a guess) is to derived ac and ad for each employee, before doing the GROUP BY, and then aggregating.
(I'm still suspicious of the joins to centre, not being included in the subqueries. Is employee the primary key or a unique key in employees? Is centre functionally dependent on employee? So many questions, too many assumptions.
My guess is that we are after the result returned by a query something like this:
SELECT c.name
, SUM(v.ad) AS `ad`
, SUM(v.ac) AS `ac`
FROM ( -- derive `ad` and `ac` in an inline view before we collapse rows
SELECT ee.employee
, ee.centre
, ( -- derived for each employee
SELECT SUM(d1.duration)
FROM time t1
JOIN dates d1
ON d1.time_id = t1.id
AND d1.date >= NOW() + INTERVAL -12 MONTH
WHERE d1.employee = t.employee
) AS `ad`
, ( -- derived for each employee
SELECT SUM(d2.cost)
FROM time t2
JOIN dates d2
ON d2.time_id = t2.id
AND d2.date >= NOW() + INTERVAL -12 MONTH
WHERE d2.employee = t.employee
) AS `ac`
FROM time t
JOIN employees ee
ON ee.employee = t.employee
WHERE ee.centre in (4792,4804,4834)
GROUP
BY ee.employee
, ee.centre
) v
LEFT
JOIN centres c
ON c.id = v.centre
GROUP
BY v.centre
, c.name
I have to select a counted column, grouped by dates from two sources. I'm joining the resultset as a subquery. However, the result is bogus. As I see the problem is related to the JOIN .. ON clause. This query works fine:
SELECT id
FROM pu a
LEFT JOIN (
SELECT
COUNT(pd.id) AS c_id1,
NULL AS c_id2,
LEFT(pd.start_date, 10) AS date,
pd.pid
FROM
p_d pd
**WHERE pd.pid = 111**
GROUP BY date
UNION
SELECT
NULL AS c_id1,
COUNT(pd.id) AS c_id2,
LEFT(pd.inactivation_date, 10) AS date,
pd.pid
FROM
p_d pd
**WHERE pd.pid = 111**
GROUP BY date
) x
ON x.pid = a.id;
But this one (without the WHERE clause) returns a bad result set:
SELECT id
FROM pu a
LEFT JOIN (
SELECT
COUNT(pd.id) AS c_id1,
NULL AS c_id2,
LEFT(pd.start_date, 10) AS date,
pd.pid
FROM
p_d pd
GROUP BY date
UNION
SELECT
NULL AS c_id1,
COUNT(pd.id) AS c_id2,
LEFT(pd.inactivation_date, 10) AS date,
pd.pid
FROM
p_d pd
GROUP BY date
) x
ON x.pid = a.id;
It is possible to use a.id in the joined subquery somehow? It's "unknown column" now.
In your subquery you are using columns like pd.pid for SELECT that are not part of the GROUP BY and are not aggregated. Such columns are called hidden and in standard SQL this would give syntax error, but mysql permits it, though it is free to choose value from any row in every group.
If you restrict your set with WHERE pd.pid = 111 all the values of pd.pid in the group will be the same so it doesn't matter which row will be used to get it, however without WHERE value of pd.pid will be undefined (mysql will probably choose the one that can fetch you fastest). You also use that undefined pid for the JOIN so you are bound to get wrong results.
http://dev.mysql.com/doc/refman/5.6/en/group-by-hidden-columns.html
It's hard to say however how you should rewrite your query as you don't provide enough info about table schema, what are you trying to achieve and what is the meaning of your table/column names.