This should work:
-- Query every name_changes where rownum <= per group limit (2)
select * from (
-- subquery for attaching rownumber counter for `name:city` groups
select `date`, name, city , old_mul, new_mul,
case when @lag != concat(name, ':', city) then @rownum:=1 else @rownum:=@rownum+1 end as rownum,
@lag:=concat(name, ':', city)
from name_changes,
-- init values
(select @rownum:=0) init_rownum,
(select @lag:=null) init_la
order by name, city, d desc
) numbered
where rownum <= 2;
I had a previous answer about mimicking window functions
in mysql: How do I write this query? where I explained this in more details.
Following what's already written at How to use GROUP_CONCAT in a CONCAT in mysql...
Let's assume you have a schema and sample data equivalent to:
CREATE TABLE properties
(
id integer PRIMARY KEY,
property varchar(255) NOT NULL
) ;
CREATE TABLE recommended_providers
(
id integer PRIMARY KEY,
recommended_provider_name varchar(255) NOT NULL
) ;
CREATE TABLE properties_recommended_providers
(
prop_id INTEGER NOT NULL REFERENCES properties(id),
recommended_provider_id INTEGER NOT NULL REFERENCES providers(id),
PRIMARY KEY (prop_id, recommended_provider_id)
) ;
INSERT INTO properties
VALUES (1, 'property 1'), (2, 'property 2') ;
INSERT INTO recommended_providers
VALUES (1, 'provider 1'), (2, 'provider 2'), (3, 'provider 3');
INSERT INTO properties_recommended_providers
VALUES (1, 1), (1, 2), (2, 3) ;
You can either have:
SELECT
p.id AS property_id, property,
GROUP_CONCAT(recommended_provider_name SEPARATOR ', ') AS provider_names
FROM
properties p
LEFT JOIN properties_recommended_providers pr ON pr.prop_id = p.id
LEFT JOIN recommended_providers rp ON rp.id = pr.recommended_provider_id
GROUP BY
property_id
ORDER BY
property_id ;
(Check it at SQL Fiddle)
or
SELECT
p.id AS property_id, property,
(SELECT
GROUP_CONCAT(recommended_provider_name SEPARATOR ', ')
FROM
properties_recommended_providers pr
LEFT JOIN recommended_providers rp ON rp.id =
pr.recommended_provider_id
WHERE
pr.prop_id = p.id
ORDER BY
/* You can easily order by in this case */
recommended_provider_name
) AS provider_names
FROM
properties p
ORDER BY
property_id ;
You can check the second one at SQL Fiddle
Best Answer
The elegance of the answer will vary with the DBMS of your choice. In it's simplest form:
I believe this should be supported by most DBMSes. If your DBMS supports lateral (cross apply in sqlserver?) you can do something like:
Edit: The T-SQL (SQL Server) syntax uses CROSS APPLY to perform the same task, i.e.:
CROSS APPLY
in SQL Server also often generates more effective execution plans than a bunch of union operators, so it's definitely worth a try.Edit: As @ypercube suggests it is not necessary to join, removing the name column and taking the cartesian product gives same result