I've inherited the need to convert a production MySQL DB over to Postgres. This has mostly been handled without issue using simple SQL statements for table/function creation (using Navicat to generate semi-automated conversion), but now I am hitting a problem with converting a somewhat complex view.
Research suggests this might be due to differences in how the two DBs handle sub-queries (the WHERE statements), and perhaps it's just a syntax difference. The business logic here is unknown as the code-base has been inherited from another developer.
Running the following (using Laravel migrations / PHP script):
SELECT
parent.is_owner AS is_owner,
parent.brand AS first_name,
parent.id AS id,
(SELECT count(c.id)
FROM campaigns c
WHERE((
(c.user_id = parent.id)
OR
(c.user_id = child.id)
)
AND
(c.campaign_status_id = 4)
))
AS current_campaigns,
(SELECT count(c.id)
FROM campaigns c
WHERE
((
(c.user_id = parent.id)
OR (c.user_id = child.id)
)
AND (c.campaign_status_id = 5)
))
AS past_campaigns,
(SELECT count(c.id)
FROM campaigns c
WHERE
((
(c.user_id = parent.id)
OR (c.user_id = child.id))
AND (c.campaign_status_id = 2)
))
AS pending_campaigns,
(SELECT count(c.id)
FROM campaigns c
WHERE ((
(c.user_id = parent.id)
OR (c.user_id = child.id)
)
AND (c.invoice_status = '1')
))
AS past_invoices
FROM ((users parent LEFT JOIN campaigns mc ON
((parent.id = mc.user_id)))
LEFT JOIN users child ON ((child.parent_owner = parent.id)
))
WHERE
(
(parent.is_owner = 1)
OR (child.is_retailer = 1)
)
GROUP BY parent.id
ORDER BY parent.brand
... triggers the error
SQLSTATE[42803]: Grouping error: 7 ERROR: subquery uses ungrouped column "child.id" from outer query
LINE 1: ...c where (((c.user_id = parent.id) or (c.user_id = child.id)) ...
Can anyone suggest how to format this so Postgres runs the sub-queries?
BTW, the PHP code used here in a Laravel migration script is:
...
DB::unprepared("CREATE VIEW client AS
select parent.is_owner AS is_owner,parent.brand AS first_name,parent.id AS id
,(select count(c.id) from campaigns c where (((c.user_id = parent.id) or (c.user_id = child.id)) and (c.campaign_status_id = 4))) AS current_campaigns
,(select count(c.id) from campaigns c where (((c.user_id = parent.id) or (c.user_id = child.id)) and (c.campaign_status_id = 5))) AS past_campaigns
,(select count(c.id) from campaigns c where (((c.user_id = parent.id) or (c.user_id = child.id)) and (c.campaign_status_id = 2))) AS pending_campaigns
,(select count(c.id) from campaigns c where (((c.user_id = parent.id) or (c.user_id = child.id)) and (c.invoice_status = '1'))) AS past_invoices
from ((users parent
left join campaigns mc on((parent.id = mc.user_id)))
left join users child on((child.parent_owner = parent.id)))
where ((parent.is_owner = 1) or (child.is_retailer = 1))
group by parent.id
order by parent.brand;");
UPDATE, FIXED:
Brilliant. Very good input here from all.
The solutions from @patrick and @ErwinBrandstetter both work. I will favour Patrick's here as my role in this is to convert the system "as-is". There may be scope to refactor in the future, but at this stage I feel it risky to mess with (or improve) someone else's duct tape solution (i.e the code-base seems overly complex in places, with no sign of documentation, and I'm reluctant to poke around or attempt core improvement without more background info on business logic). I suspect parts of the model may need to be overhauled anyway, so [sic]-fix favoured here.
I suspected some click-jiggery might have generated the original query... trying to give the original dev the benefit of the doubt and assume there was some business pressure that called for a quick (i.e mousy) turn-around. Complex SQL is not my strong suit but I'm glad my instinct was correct, the query being unnecessary complex to begin with. Perhaps the view was an unplanned bolt-on -not designed in the first place. Wise or not, I'd probably have tried to hit the problem with an ORM based approach.
I'm on this project last minute, running cleanup for a re-launch (original dev was "let go"), so am working with a mostly undocumented code-base full of unknown functionality. Running paratrooper as it were. Thankfully, this view issue appears to the last piece of the puzzle. Thank you :-)