The query that I'm using is below. I need a 4th column in my result called letter_count, which counts how many sub_categories begin with A, how many begin with B, etc all the way to Z - it would be preferable if this could be done dynamically rather than adding a line for each letter.
An example of the table/result that I'm looking for is displayed at the bottom of this question. I can't work out how to amend the query to get this 4th column.
SELECT
headings.heading AS sub_category,
LEFT( headings.heading, 1 ) AS first_letter,
headings.url_code as url_code
FROM TOWN_TABLE a
INNER JOIN headings ON a.Heading=headings.heading
WHERE Category = 'Classified'
GROUP BY sub_category
ORDER BY sub_category ASC
Result:
+-------------------------+--------------+-------------------------+--+
| sub_category | first_letter | url_code | letter_count |
+-------------------------+--------------+-------------------------+--+
| Accountants | A | accountants | 6 |
| Adult Education | A | adult education | 6 |
| Aerials | A | aerials | 6 |
| Alarms | A | alarms | 6 |
| Architectural Services | A | architectural services | 6 |
| Art & Craft | A | art and craft | 6 |
| Bathrooms | B | bathrooms | 8 |
| Beauty Salons & Therapy | B | beauty salons & therapy | 8 |
| Bed & Breakfast | B | bed and breakfast | 8 |
| Bedrooms | B | bedrooms | 8 |
| Boiler Maintenance | B | boiler maintenance | 8 |
| Bookkeeping Services | B | bookkeeping services | 8 |
| Builders | B | builders | 8 |
| Builders Merchants | B | builders merchants | 8 |
+-------------------------+--------------+-------------------------+--+
You need to make a derived table that groups by the first letter to get your counts, then join that on to your original table. It's made messier because you have a couple of conditions on which headings
you want to look at. If this doesn't immediately work I suggest removing the WHERE and just getting it working without that, so you understand the structure, and then add the WHERE back in.
SELECT headings.heading AS sub_category,
LEFT( headings.heading, 1 ) AS first_letter,
headings.url_code as url_code ,
letter_counts.letter_count
FROM headings ON a.Heading=headings.heading
INNER JOIN (
-- make a derived table of each letter and how many
-- headings start with it. Only count ones that have
-- a TOWN_TABLE entry with category Classified.
select left(h_all.heading,1) as the_letter,
count(*) as letter_count
from headings h_all
WHERE EXISTS ( select * from TOWN_TABLE t
where t.heading = h_all.heading
AND Category = 'Classified')
group by left(h_all.heading,1)
) as letter_counts on left(heading.heading,1) = letter_counts.the_letter
WHERE EXISTS ( select * from TOWN_TABLE t
where t.heading = headings.heading
AND Category = 'Classified')
order by headings.heading
Alternatively in SQL Server you can use a CTE to make it slightly nicer to read. Not sure if CTEs work in mysql:
with sub_categories ( first_letter, sub_category )
as (
select left( h.heading, 1 )
, h.heading
from headings h
where exists( select * from TOWN_TABLE t
where t.heading = h_all.heading
and Category = 'Classified')
)
select sc.sub_category
, sc.first_letter
, sub_category_counts.the_count
from sub_categories sc
inner join (
select first_letter
, count(*) as the_count
from sub_categories
group by first_letter
) as sub_category_counts on sub_category_counts.first_letter = sc.first_letter
order by sc.sub_category
I think this should work:
SELECT
headings.heading AS sub_category,
LEFT( headings.heading, 1 ) AS first_letter,
headings.url_code as url_code , CNT as letter_count
FROM TOWN_TABLE a
INNER JOIN headings ON a.Heading=headings.heading
INNER JOIN (SELECT LEFT( headings.heading, 1 ) AS first_letter, COUNT(DISTINCT LEFT( headings.heading, 1 )) as CNT FROM headings) AS lettercounts
ON lettercounts.first_letter = LEFT( headings.heading, 1 )
WHERE Category = 'Classified'
GROUP BY sub_category
ORDER BY sub_category ASC;
You can add a joined field:
SELECT
...,
( SELECT COUNT(*) FROM headings AS lett
WHERE LEFT(lett.heading, 1)=first_letter)
AS letter_count
FROM ...
This should take first_letter
from the outer query and count how many headings start with that letter. If it doesn't work as such, because first_letter
is an alias, you need to state its value explicitly:
( SELECT COUNT(*) FROM headings AS lett
WHERE LEFT(lett.heading, 1)=LEFT(headings.heading, 1))
AS letter_count
You use headings
twice, once as itself to get the data you need, the second time to fetch the first letter.
This is a link to a SQL Fiddle for testing purposes :
SUB_CATEGORY FIRST_LETTER URL_CODE LETTER_COUNT
Accountants A /url/accountants 2
Art & Craft A /url/arts_crafts 2
Bathrooms B /url/bathrooms 1
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.