Problem:
I know it's documented in MYSQL DOCUMENTS That in where clause "alias" cannot be used since where clause is not populated yet. But i have to get the data matched from other table values in where clause (IN condition).
I have also read some similar kind of post but this one is quite different & big complex one. I couldn't make it working with my efforts of last 3 days.
It's showing error (excepted as per documentation)
UNKNOWN COLUMN "Ind_ID" in WHERE CLAUSE
I have to match similarly for FA_ID & PREFERRED_LOCATION_ID field
Select a.job_id, a.Employer_ID, a.Sub_user_id,
Date_format(a.creation_on,'%d-%m-%Y') as Created_date, a.Job_type,
a.Designation, a.Open_Positions, a.Job_Description, a.Min_age,
a.Max_age, a.min_exp, a.max_exp, a.Hide_Salary, a.company_name,
a.About_Company, a.Contact_person_name, a.Contact_No, a.Refresh_type,
a.Response_type,
(Select GROUP_CONCAT(DISTINCT g.Education ORDER BY pjedu.Education_ID
SEPARATOR ', ') user_education
from e_pj_edu pjedu
INNER JOIN education g ON FIND_IN_SET(g.Edu_ID, pjedu.Education_ID)
where a.job_id = pjedu.Job_ID
) as Education_ID,
(Select GROUP_CONCAT(DISTINCT h.FA_description ORDER BY uf.FA_ID
SEPARATOR ', ') FA
from e_pj_fa uf
INNER JOIN functional_area h ON FIND_IN_SET(h.FA_ID, uf.FA_ID)
where a.Job_ID = uf.Job_ID
) as FA_ID,
(Select GROUP_CONCAT(DISTINCT i.Industry_description ORDER BY
ui.Industry_ID SEPARATOR ', ') Industry_ID
from e_pj_industry ui
INNER JOIN industry i ON FIND_IN_SET(i.Industry_ID, ui.Industry_ID)
where a.Job_ID = ui.Job_ID
) as Ind_ID,
(Select GROUP_CONCAT(DISTINCT j.location_name ORDER BY
upl.Location_ID SEPARATOR ', ') Location_ID
from e_pj_locations upl
INNER JOIN locations j ON FIND_IN_SET(j.location_id, upl.Location_ID)
where a.Job_ID = upl.Job_ID
) as Preferred_Location_ID,
(Select GROUP_CONCAT(DISTINCT uk.Keyword_Name ORDER BY uk.Keyword_ID
SEPARATOR ', ') keyskills
from e_pj_keywords uk
where a.Job_ID = uk.Job_ID
) as Keyword_Name,
GROUP_CONCAT(DISTINCT cc.salary_description ORDER BY cc.salary_ID
SEPARATOR ', ') Min_salary,
GROUP_CONCAT(DISTINCT dd.salary_description ORDER BY dd.salary_ID
SEPARATOR ', ') Max_salary
from post_jobs a
INNER JOIN user_salary cc ON FIND_IN_SET(cc.salary_ID, a.Min_salary)
INNER JOIN user_salary dd ON FIND_IN_SET(dd.salary_ID, a.Max_salary)
WHERE a.Designation LIKE '%MIS%' or a.company_name LIKE '%MIS%'
And a.max_exp <= 9
And a.Max_salary<=110
And Ind_ID IN (10001,10002,10004)
And FA_ID IN(1001)
group by a.job_id
First thing that comes in my mind is just move your aliased where conditions to outer query, i.e.:
select * from (
Select a.job_id ....
WHERE a.Designation LIKE '%MIS%' or a.company_name LIKE '%MIS%'
And a.max_exp <= 9
And a.Max_salary<=110
group by a.job_id
) inner
where
Ind_ID IN (10001,10002,10004)
And FA_ID IN(1001)
GL!
Posting revised query which worked. May be this helps someone from wasting 3 days like me :-)
select * from (
Select a.job_id, a.Employer_ID, a.Sub_user_id, Date_format(a.creation_on,'%d-%m-%Y') as Created_date, a.Job_type, a.Designation, a.
Open_Positions, a.Job_Description, a.Min_age, a.Max_age, a.min_exp, a.max_exp, a.Hide_Salary, a.company_name, a.About_Company, a.Contact_person_name,
a.Contact_No, a.Refresh_type, a.Response_type,
(Select GROUP_CONCAT(DISTINCT g.Education ORDER BY pjedu.Education_ID SEPARATOR ', ') user_education
from e_pj_edu pjedu
INNER JOIN education g ON FIND_IN_SET(g.Edu_ID, pjedu.Education_ID)
where a.job_id = pjedu.Job_ID
) as Education_ID,
(Select GROUP_CONCAT(DISTINCT h.FA_description ORDER BY uf.FA_ID SEPARATOR ', ') FA
from e_pj_fa uf
INNER JOIN functional_area h ON FIND_IN_SET(h.FA_ID, uf.FA_ID)
where a.Job_ID = uf.Job_ID
) as FA_ID,
(Select GROUP_CONCAT(DISTINCT i.Industry_description ORDER BY ui.Industry_ID SEPARATOR ', ') Industry_ID
from e_pj_industry ui
INNER JOIN industry i ON FIND_IN_SET(i.Industry_ID, ui.Industry_ID)
where a.Job_ID = ui.Job_ID
) as Ind_ID,
(Select GROUP_CONCAT(DISTINCT j.location_name ORDER BY upl.Location_ID SEPARATOR ', ') Location_ID
from e_pj_locations upl
INNER JOIN locations j ON FIND_IN_SET(j.location_id, upl.Location_ID)
where a.Job_ID = upl.Job_ID
) as Preferred_Location_ID,
(Select GROUP_CONCAT(DISTINCT uk.Keyword_Name ORDER BY uk.Keyword_ID SEPARATOR ', ') keyskills
from e_pj_keywords uk
where a.Job_ID = uk.Job_ID
) as Keyword_Name,
GROUP_CONCAT(DISTINCT cc.salary_description ORDER BY cc.salary_ID SEPARATOR ', ') Min_salary,
GROUP_CONCAT(DISTINCT dd.salary_description ORDER BY dd.salary_ID SEPARATOR ', ') Max_salary
from post_jobs a
INNER JOIN user_salary cc ON FIND_IN_SET(cc.salary_ID, a.Min_salary)
INNER JOIN user_salary dd ON FIND_IN_SET(dd.salary_ID, a.Max_salary)
group by a.Job_id
) aa
WHERE Designation LIKE '%op%' or company_name LIKE '%op%'
And max_exp <= 15
And Max_salary<=120
and Ind_ID IN (10001,10002,10004,10003)
And FA_ID IN(1001,1002,1003)
group by Job_id
Related
hi I want to put an alias in my join statement.
my code is:
SELECT distinct id_no, '' as picture, concat(lastname, IF(LENGTH(firstname) > 0 OR LENGTH(middlename) > 0, ', ', ''), concat(IF(p.degree = 5, 'Dr. ', IF(p.degree = 6, 'Dr. ', IF(p.degree = 28, 'Dr. ', '')))), firstname, IF(LENGTH(middlename) > 0, CONCAT(' ', middlename), '')) as name, tp.profession, '' as cv, e.entry_date, e.termination_date
FROM (bims_people as p)
LEFT JOIN bims_people_education as bpe ON bpe.people_id = p.id_no
LEFT JOIN tcms_profession as tp ON tp.profession_id = bpe.profession
LEFT JOIN (select * from bims_people_employment_contract_data order by termination_date DESC) e ON e.people_id = p.id_no
WHERE p.marked = 0 AND p.id_no > 1 GROUP BY p.id_no ORDER BY lastname ASC LIMIT 100, 50 ;
and I want it this way:
SELECT distinct id_no, '' as picture, concat(lastname, IF(LENGTH(firstname) > 0 OR LENGTH(middlename) > 0, ', ', ''), concat(IF(p.degree = 5, 'Dr. ', IF(p.degree = 6, 'Dr. ', IF(p.degree = 28, 'Dr. ', '')))), firstname, IF(LENGTH(middlename) > 0, CONCAT(' ', middlename), '')) as name, tp.profession, '' as cv, e.entry_date, e.termination_date
FROM (bims_people as p)
LEFT JOIN bims_people_education as bpe ON bpe.people_id = p.id_no
LEFT JOIN tcms_profession as tp ON tp.profession_id = bpe.profession
LEFT JOIN (select * from bims_people_employment_contract_data **where people_id = p.id_no** order by termination_date DESC limit 1) e ON e.people_id = p.id_no
WHERE p.marked = 0 AND p.id_no > 1 GROUP BY p.id_no ORDER BY lastname ASC LIMIT 100, 50 ;
i keeps telling me that p.id_no is unknown;
LEFT JOIN (select * from bims_people_employment_contract_data
where people_id = p.id_no
order by termination_date DESC limit 1) e
ON e.people_id = p.id_no
You cannot use a table's alias (correlation name) to define another table to JOIN to it. After you have given two tables & aliases to JOIN, ON or WHERE can use the alias in conditions.
From MySQL 5.7 Reference Manual 14.2.10.8 Subqueries in the FROM Clause
:
Subqueries in the FROM clause cannot be correlated subqueries, unless used within the ON clause of a JOIN operation.
(What do you expect the quoted OUTER JOIN to do? Since p.id_no doesn't appear in an ON or WHERE, there's no particular row of a table p that it could be the id_no value of.)
Maybe you want:
LEFT JOIN (SELECT * FROM bims_people_employment_contract_data
WHERE (people_id, termination_date) IN
(SELECT people_id, MAX(termination_date) AS termination_date
FROM bims_people_employment_contract_data
GROUP BY people_id)
) e
ON e.people_id = p.id_no
I have been trying to group by the mysql group by in normal column and mysql function aliases column where the mysql function aliases wont work group by
The query i tried and which should work according to the mysql documentation.
SELECT `project`.`project_name`, SUM(cost_allocated) AS cost_allocated,
count(task_id) as countTask,
GROUP_CONCAT(task_registration.members SEPARATOR ';') AS members,
GROUP_CONCAT(task_registration.indicators SEPARATOR ';') AS indicators,
GROUP_CONCAT(task_registration.percent_complete SEPARATOR ';') AS percent_complete,
GROUP_CONCAT(task_registration.status SEPARATOR ';') AS status,
DATE_FORMAT(`task_registration`.`created_at`, '%M') AS month
FROM (`project`)
INNER JOIN `task_registration` ON `task_registration`.`project` = `project`.`project_id`
GROUP BY `task_registration`.`project`,`month`
ORDER BY `project`.`project_id` desc
The result i get
Now after removing the normal column group by and just adding mysql function aliases column it works fine but i need both
SELECT `project`.`project_name`, SUM(cost_allocated) AS cost_allocated,
count(task_id) as countTask,
GROUP_CONCAT(task_registration.members SEPARATOR ';') AS members,
GROUP_CONCAT(task_registration.indicators SEPARATOR ';') AS indicators,
GROUP_CONCAT(task_registration.percent_complete SEPARATOR ';') AS percent_complete,
GROUP_CONCAT(task_registration.status SEPARATOR ';') AS status,
DATE_FORMAT(`task_registration`.`created_at`, '%M') AS month
FROM (`project`)
INNER JOIN `task_registration` ON `task_registration`.`project` = `project`.`project_id`
GROUP BY `month`
ORDER BY `project`.`project_id` desc
after removing task_registration`.`project from group by
GROUP BY `task_registration`.`project`,`month` Doesnt work in this case
http://sqlfiddle.com/#!2/18389/2 i have tried this so far
Very difficult to work out what you want without table declarations, sample input data and sample output data, but from your comment all I can suggest is using the 2nd query as a sub query and joining it to the results of the first query:-
SELECT project.project_name,
SUM(cost_allocated) AS cost_allocated,
count(task_id) as countTask,
GROUP_CONCAT(task_registration.members SEPARATOR ';') AS members,
GROUP_CONCAT(task_registration.indicators SEPARATOR ';') AS indicators,
GROUP_CONCAT(task_registration.percent_complete SEPARATOR ';') AS percent_complete,
GROUP_CONCAT(task_registration.status SEPARATOR ';') AS status,
DATE_FORMAT(task_registration.created_at, '%M') AS month,
sub0.cost_allocated AS months_cost_allocated,
sub0.countTask AS months_countTask,
sub0.members AS months_members,
sub0.indicators AS months_indicators,
sub0.percent_complete AS months_percent_complete,
sub0.status AS months_status
FROM (`project`)
INNER JOIN `task_registration` ON `task_registration`.`project` = `project`.`project_id`
INNER JOIN
(
SELECT DATE_FORMAT(task_registration.created_at, '%M') AS month,
SUM(cost_allocated) AS cost_allocated,
COUNT(task_id) as countTask,
GROUP_CONCAT(task_registration.members SEPARATOR ';') AS members,
GROUP_CONCAT(task_registration.indicators SEPARATOR ';') AS indicators,
GROUP_CONCAT(task_registration.percent_complete SEPARATOR ';') AS percent_complete,
GROUP_CONCAT(task_registration.status SEPARATOR ';') AS status
FROM (project)
INNER JOIN task_registration ON task_registration.project = project.project_id
GROUP BY `month`
) sub0
ON DATE_FORMAT(task_registration.created_at, '%M') = sub0.`month`
GROUP BY task_registration.project,
`month`,
months_cost_allocated,
sub0.countTask AS months_countTask,
sub0.members AS months_members,
sub0.indicators AS months_indicators,
sub0.percent_complete AS months_percent_complete,
sub0.status AS months_status
ORDER BY project.project_id desc
Thank you for the answer i did it on my own
SELECT COUNT( i.project_name ) AS completed_projects,i.month
FROM (
SELECT `project`.`project_name` , SUM( cost_allocated ) AS cost_allocated, COUNT( task_id ) AS countTask, GROUP_CONCAT( task_registration.members
SEPARATOR ';' ) AS members, GROUP_CONCAT( task_registration.indicators
SEPARATOR ';' ) AS indicators, GROUP_CONCAT( task_registration.percent_complete
SEPARATOR ';' ) AS percent_complete, GROUP_CONCAT( task_registration.status
SEPARATOR ';' ) AS
STATUS , DATE_FORMAT( task_registration.created_at, '%M' ) AS
MONTH FROM (
`project`
)
INNER JOIN `task_registration` ON `task_registration`.`project` = `project`.`project_id`
GROUP BY `task_registration`.`project`
ORDER BY `project`.`project_id` DESC
) AS i
GROUP BY i.month
http://sqlfiddle.com/#!2/18389/11
Product name supplier
A Su1
A Su1
A Su2
B Su1
C Su3
I want like this
A - su1, A-su2, B-su1, C-su3
Query:
SELECT
vtiger_salesorder.salesorder_no,
(Select
group_concat(DISTINCT concat(vtiger_products.productname, '-', vtiger_vendor.vendorname ) SEPARATOR ', ')
FROM
vtiger_salesorder
LEFT Join vtiger_inventoryproductrel ON vtiger_salesorder.salesorderid = vtiger_inventoryproductrel.id
inner Join vtiger_products ON vtiger_products.productid = vtiger_inventoryproductrel.productid
inner Join softMax_SalesOrderVendorInfo ON softMax_SalesOrderVendorInfo.salesorderid = vtiger_salesorder.salesorderid
LEFT JOIN vtiger_vendor ON softMax_SalesOrderVendorInfo.vendorid = vtiger_vendor.vendorid
where (vtiger_salesorder.salesorderid = vtiger_inventoryproductrel.id
AND vtiger_salesorder.salesorderid = vtiger_crmentity.crmid
and (softMax_SalesOrderVendorInfo.status = '0') )Group by vtiger_salesorder.salesorderid Limit 0,1) As SuName1
FROM
vtiger_salesorder
INNER JOIN vtiger_inventoryproductrel ON vtiger_salesorder.salesorderid = vtiger_inventoryproductrel.id
Inner Join vtiger_crmentity ON vtiger_salesorder.salesorderid = vtiger_crmentity.crmid
Order by vtiger_salesorder.salesorder_no
Given your original data, you can simply do this with something like:
select distinct group_concat(ProductName, '-', Supplier separator ', ')
from table t;
I have no idea what the query has to do with the question, because you already seem to have the data in the appropriate format.
I use view has subquery and concat in mysql. Normally, query works rapidly, but if query has subquery works very slowly.
This code is running quickly (approximate 1 seconds)
CREATE OR REPLACE VIEW ilceler AS (
SELECT I.id, I.modulid, I.id as icerikidsi,
MAX(IF(D.alanid=2,D.textkisa,NULL)) AS ilceadi,
MAX(IF(D.alanid=2,D.id,NULL)) AS ilceadi_i,
I.seo_description,
I.seo_h1,
I.seo_h2,
I.seo_h3,
I.seo_h4,
I.seo_imgalt,
I.seo_imgtitle,
I.seo_keywords,
I.seo_pagetitle,
I.seo_url,
I.seo_urltitle
FROM datalar as D LEFT JOIN icerikler as I ON D.icerikid=I.id WHERE D.modulid='3' GROUP BY D.icerikid ORDER BY sehiradi asc )
But this code is working very very slowly (approximate 20 seconds)
CREATE OR REPLACE VIEW ilceler AS (
SELECT I.id, I.modulid, I.id as icerikidsi,
MAX(IF(D.alanid=2,D.textkisa,NULL)) AS ilceadi,
MAX(IF(D.alanid=2,D.id,NULL)) AS ilceadi_i,
( SELECT CONVERT ( GROUP_CONCAT(D2.id SEPARATOR ' ₋ ' ) USING UTF8 )FROM datalar as D1
LEFT JOIN datalar as D2 ON D1.iliskialanid=D2.id WHERE D1.modulid='3' AND D1.alanid='3' AND D1.icerikid=icerikidsi ) as sehiradi_a ,
( SELECT GROUP_CONCAT(iliskiid SEPARATOR ' ₋ ') FROM datalar WHERE alanid='3' AND modulid='3' AND icerikid=icerikidsi ) as sehiradi_i,
( SELECT GROUP_CONCAT(D2.textkisa SEPARATOR ' ₋ ' ) FROM datalar as D1 LEFT JOIN datalar as D2 ON D1.iliskialanid=D2.id
WHERE D1.modulid='3' AND D1.alanid='3' AND D1.icerikid=icerikidsi ) as sehiradi ,
I.seo_description,
I.seo_h1,
I.seo_h2,
I.seo_h3,
I.seo_h4,
I.seo_imgalt,
I.seo_imgtitle,
I.seo_keywords,
I.seo_pagetitle,
I.seo_url,
I.seo_urltitle
FROM datalar as D LEFT JOIN icerikler as I ON D.icerikid=I.id WHERE D.modulid='3' GROUP BY D.icerikid ORDER BY sehiradi asc )
Why? Where do I make mistake?
I am waiting for your help.
Your sub queries rely on the values of the select, hence each of those 3 sub queries needs to be performed for each returned row. With a small number of rows this isn't an issue but with lots of rows this can rapidly add up.
Normal solution is to join against the sub query (hence it is done once for all rows and you just join the results).
For example:-
SELECT I.id,
I.modulid,
I.id as icerikidsi,
MAX(IF(D.alanid=2,D.textkisa,NULL)) AS ilceadi,
MAX(IF(D.alanid=2,D.id,NULL)) AS ilceadi_i,
sub1.sehiradi_a ,
sub2.sehiradi_i,
sub1.sehiradi ,
I.seo_description,
I.seo_h1,
I.seo_h2,
I.seo_h3,
I.seo_h4,
I.seo_imgalt,
I.seo_imgtitle,
I.seo_keywords,
I.seo_pagetitle,
I.seo_url,
I.seo_urltitle
FROM datalar as D
LEFT JOIN icerikler as I ON D.icerikid=I.id
LEFT OUTER JOIN
(
SELECT D1.icerikid, CONVERT ( GROUP_CONCAT(D2.id SEPARATOR ' ₋ ' ) USING UTF8 ) AS sehiradi_a, GROUP_CONCAT(D2.textkisa SEPARATOR ' ₋ ' ) AS sehiradi
FROM datalar as D1
LEFT JOIN datalar as D2 ON D1.iliskialanid=D2.id
WHERE D1.modulid='3'
AND D1.alanid='3'
GROUP BY D1.icerikid
) sub1
ON sub1.icerikid = I.id
LEFT OUTER JOIN
(
SELECT icerikid, GROUP_CONCAT(iliskiid SEPARATOR ' ₋ ') AS sehiradi_i
FROM datalar
WHERE alanid='3'
AND modulid='3'
GROUP BY icerikid
) sub2
ON sub2.icerikid = I.id
WHERE D.modulid='3'
GROUP BY D.icerikid
ORDER BY sehiradi asc
Or depending on your actual database design you might be able to simplify it to
SELECT I.id,
I.modulid,
I.id as icerikidsi,
MAX(IF(D.alanid=2,D.textkisa,NULL)) AS ilceadi,
MAX(IF(D.alanid=2,D.id,NULL)) AS ilceadi_i,
sub1.sehiradi_a ,
sub1.sehiradi_i,
sub1.sehiradi ,
I.seo_description,
I.seo_h1,
I.seo_h2,
I.seo_h3,
I.seo_h4,
I.seo_imgalt,
I.seo_imgtitle,
I.seo_keywords,
I.seo_pagetitle,
I.seo_url,
I.seo_urltitle
FROM datalar as D
LEFT JOIN icerikler as I ON D.icerikid=I.id
LEFT OUTER JOIN
(
SELECT D1.icerikid,
CONVERT ( GROUP_CONCAT(D2.id SEPARATOR ' ₋ ' ) USING UTF8 ) AS sehiradi_a,
GROUP_CONCAT(D2.textkisa SEPARATOR ' ₋ ' ) AS sehiradi,
GROUP_CONCAT(DISTINCT D1.iliskiid SEPARATOR ' ₋ ') AS sehiradi_i
FROM datalar as D1
LEFT JOIN datalar as D2 ON D1.iliskialanid=D2.id
WHERE D1.modulid='3'
AND D1.alanid='3'
GROUP BY D1.icerikid
) sub1
ON sub1.icerikid = I.id
WHERE D.modulid='3'
GROUP BY D.icerikid
ORDER BY sehiradi asc
However there is a minor issue here. In MySQL a view cannot contain a FROM that takes data from a sub query. As such to use this syntax in your view you would need to split the sub queries off into their own views. Then you could join against the view rather than the sub query.
I'm trying to show the boroughs and postcodes a particular town in is.
My database is fairly well structured, with a table such as town, postcode and borough. There are also tables for each of the relationships town_postcode & town_borough.
Ideally I want the data returned as:
"Abbey Wood", "SE2", "Bexley, Greenwich"
"Barbican", "EC1, EC2", "City of London"
I've tried a few different approaches and I'm close but not there yet.
Any help would be appreciated... :)
So far I've tried
SELECT DISTINCT t.town,
GROUP_CONCAT( DISTINCT p.postcode SEPARATOR ', ' ) AS 'postcode',
GROUP_CONCAT( DISTINCT b.borough SEPARATOR ', ' ) AS 'borough'
FROM coverage_towns AS t,
coverage_boroughs AS b,
coverage_postcodes AS p,
coverage_towns_boroughs AS tb,
coverage_towns_postcodes AS tp
WHERE t.id = tp.town_id
AND p.id = tp.postcode_id
AND b.id = tb.borough_id
GROUP BY t.town
ORDER BY t.town ASC
Which returns
"Abbey Wood", "SE2", "Southwark, Hammersmith and Fulham, Tower Hamlets, Wandsworth, Enfield, Newham, LOTS MORE HERE"
"Barbican", "EC1, EC2", "Brent, Greenwich, Kensington and Chelsea, Westminster, Camden, LOTS MORE HERE"
I've also tried
SELECT DISTINCT t.town, (
SELECT SQL_CACHE DISTINCT GROUP_CONCAT( p1.postcode
SEPARATOR ', ' )
FROM coverage_postcodes AS p1
WHERE p1.id = tp.postcode_id
) AS 'postcode', (
SELECT SQL_CACHE DISTINCT GROUP_CONCAT( b1.borough
SEPARATOR ', ' )
FROM coverage_boroughs AS b1
WHERE b1.id = tb.borough_id
) AS 'borough'
FROM coverage_towns AS t, coverage_boroughs AS b, coverage_postcodes AS p, coverage_towns_boroughs AS tb, coverage_towns_postcodes AS tp
WHERE t.id = tp.town_id
AND p.id = tp.postcode_id
AND b.id = tb.borough_id
GROUP BY t.town
ORDER BY t.town ASC
Which returns
"Abbey Wood", "SE2", "Greenwich"
"Acton", "W3", "Greenwich"
"Aldersbrook", "E12", "Greenwich"
First query looks good, just add distinct inside the group_concat, like:
SELECT t.town
, GROUP_CONCAT(DISTINCT p.postcode SEPARATOR ', ' ) AS 'postcode'
, GROUP_CONCAT(DISTINCT b.borough SEPARATOR ', ' ) AS 'borough'
<more code here>
GROUP BY
t.town
SOLUTION
I came back to the question after a good coffee and the answer presented itself.
SELECT DISTINCT t.town,
GROUP_CONCAT( DISTINCT p.postcode SEPARATOR ', ' ) AS 'postcode',
GROUP_CONCAT( DISTINCT b.borough SEPARATOR ', ' ) AS 'borough'
FROM towns AS t, boroughs AS b, postcodes AS p, towns_boroughs AS tb, towns_postcodes AS tp
WHERE (t.id = tp.town_id AND t.id = tb.town_id)
AND (p.id = tp.postcode_id AND b.id = tb.borough_id)
GROUP BY t.town
ORDER BY t.town ASC