Group by only for "limit and offset" in MySQL - mysql

Whilst trying to do pagination I've run into this problem.
My table-
ID CarBrand Car Model
---------------------------
1 Alfa Romeo Guilietta
2 Alfa Romeo Mito
3 Audi A3
4 Audi R8
5 Audi TT
6 Fiat Punto
7 Fiat Panda
8 Ford Mondeo
9 Ford Mustang
10 Nissan Almera
11 Nissan Note
12 Nissan Qashqai
13 Toyota Aygo
14 Toyota Prius
15 Volkswagen Beetle
16 Volkswagen Golf
17 Volkswagen Polo
18 Volkswagen Up
I have the data displayed like so, in groups of two:
-Fiat - Punto
Panda
-Ford - Mondeo
Mustang
So there are 2 brands but 4 database results.
Is it possible to have a query limit and offset my results to two brands while showing all the models for the brand?
Sorry if I'm not clear!

It is clear. Try this:
select * from t t1
join (
select distinct carBrand from t
limit 2
) s on t1.carBrand = s.carBrand
Before the limit 2 apply the ordering you want.

To get a limit, without using the limit keyword, you can impose a count.
For example, given the table definition
create table cars (id int,
carBrand char(10),
carModel char(10));
this will give you all the Car Models for the top 2 Car Brands
select cars.carBrand, cars.carModel
from cars
where ((select count(*) from
(select distinct carBrand from cars) as carBrands
where carBrands.carBrand < cars.carBrand) < 2)
order by cars.carBrand, cars.carModel;
This creates an inline table just listing the carBrands and then joins this back to cars to get the list of all cars that are in the top 2 brands. The count(*) .... < 2 enforces the limit. Consider 'Ford', for example, in your above data. In 'Ford''s case, there are 3 brands that are < 'Ford' alphabetically, so the count(*) above = 3. Since 3 is not less than 2, no 'Ford' cars appear in the output.
The output on your test data would be:
CARBRAND CARMODEL
Alfa Romeo Guilietta
Alfa Romeo Mito
Audi A3
Audi R8
Audi TT
Now, you didn't say how you wanted to pick the 2 brands -- you just listed Ford and Fiat in your example -- I don't know how you happened to pick those. If you want something other than alphabetical criteria for ordering, that's doable, but harder.
SQL Fiddle and results for all this: http://sqlfiddle.com/#!2/33a8f/3

It's a matter of database design. Maybe you should split your data into two tables model (model names) and brand (brand names). Then you can write a query like this:
SELECT m.name, b.name
FROM model m
INNER JOIN brand b
WHERE b.id IN (
SELECT id
FROM brand
ORDER BY name ASC
LIMIT 2 OFFSET 0
)
I did not test the code. No need for GROUP BY in my opinion.

Related

sql query results depend on attributes of other table

Cars:
id name
1 Mercedes
2 Audi
CarAttributes:
id car_id attribute
1 1 fast
2 1 modern
3 1 fancy
4 1 green
5 2 fast
6 2 quiet
7 2 blue
8 2 old
How would the sql query look if the returns depend on the attributes of the car like following:
[fast OR modern] AND [fancy OR old] = would return both cars
[fast OR modern] AND [old OR blue] = would only return the audi car
You can use aggregation with a having clause:
select car_id
from carattributes
group by car_id
having sum( attribute in ('fast', 'modern')) > 0 and
sum( attribute in ('fancy', old')) > 0

Find count of value A that does not have value B

ROW - NAME - BRAND
____________________
1 - John - Ford
2 - John - BMW
3 - John - Merc
4 - Mary - Ford
5 - Mary - VW
6 - James - Ford
7 - James - Jeep
8 - James - Lexus
9 - Susan - Jeep
10 - Susan - Lexus
How do I find the values in Column A that does not have a particular value in Column B.
Column A, let's say Name, is not unique, there are multiple rows with the same value in A (as the same person can have multiple cars)
Column B, let's say Car Brand, shows the brand of car that the person has in A. There are only a total of 5 brands possible and ideally everyone should have one of the brands - Ford.
How do I find out all the unique Names for people who have other car types, but are missing the Ford? In the above example I'm looking to find Susan.
You can use aggregation:
select name
from t
group by name
having sum(brand = 'Ford') = 0;
The having clause counts the number of rows that match Ford. The = 0 says there are no such rows.
I hope you are talking about this.
SELECT DISTINCT name
FROM tablename
WHERE brand <> 'FORD';
If you need names with all 4 other cars but with no Ford:
SELECT DISTINCT name FROM t
WHERE (SELECT COUNT(DISTINCT car) FROM t AS t2 WHERE t2.name=t.name)=4
AND (SELECT COUNT(*) FROM t AS t2 WHERE t2.name=t.name AND t2.car="Ford")=0
There are a lot of ways, but one answer would be:
SELECT DISTINCT A
FROM T
WHERE A NOT IN (
SELECT A
FROM T
WHERE B = 'Ford'
);

how can combine two columns in the same table and count its unique occurrences

I have been struggling and would really appreciate some assistance:
I have two tables cars and rides
cars
car_id car_manuf car_model
1 Honda CRV
2 Honda Accord
3 Toyota Corolla
4 Toyota Camry
5 Ford Fusion
rides
ride_id car_id ride_destination
1 3 Boston
2 5 New York
3 5 Washington DC
4 1 California
5 2 Dallas
6 5 Canada
I would like to count the number of rides by each car type which will have the combination of car_manuf and car_model and should be sorted from most to fewest number of rides.
Output should be:
CarType-NumberofRides
Honda_CRV-1
Honda_Accord-1
Toyota_Corolla-1
Toyota_Camry-0
Ford_Fusion-3
Sorted output with most-few rides
CarType-NumberofRides
Toyota_Camry-0
Honda_Accord-1
Toyota_Corolla-1
Honda_CRV-1
Ford_Fusion-3
mycode:
select
c.car_manuf + '_' + c.car_model AS 'Car Type',
(select count(*) from rides r where r.car_id = c.car_id) AS 'Number of Rides'
from cars c;
I am kinda stuck here and not sure which direction I should go in regards to getting the correct output.
You have to use GROUP BY and an ORDER BY when COUNTing the occurences. I use CONCAT to concatenate the strings instead of a + sign. Makes clearer what is going on, and is not mistaken as an arithmetic operation.
SELECT CONCAT(c.car_manuf, '_', c.car_model) AS CarType, COUNT(r.car_id) AS NumberOfRides
FROM rides r
LEFT JOIN cars c ON (r.car_id = c.car_id)
GROUP BY CarType
ORDER BY NumberOfRides ASC
However this omits the 0 occurences.
If you want to see the 0s as well swap the table order to:
SELECT CONCAT(c.car_manuf, '_', c.car_model) AS CarType, COUNT(r.car_id) AS NumberOfRides
FROM cars c
LEFT JOIN rides r ON (r.car_id = c.car_id)
GROUP BY CarType
ORDER BY NumberOfRides ASC

Order by on a group sum criteria

Is it possible to order return rows with a criteria on a sum group ?
For example, my data are :
Id Price Product Category
1 12 Book1 Car
2 1 Book2 Art
3 8 Book3 Car
4 7 Book4 Art
5 11 Book5 Car
6 24 Book6 Bridge
As the sum of Car books is 31, the sum of Art books is 8 and the sum of Bridge books is 24, I would like to have the following result (Car first, then Bridge and then Art):
Id Price Product Category
1 12 Book1 Car
3 8 Book3 Car
5 11 Book5 Car
6 24 Book6 Bridge
2 1 Book2 Art
4 7 Book4 Art
On the other hand, I would like to add other Order by criteria (in the example, "Product" criteria).
I have tried many things using ORDER BY and GROUP BY but it always aggregate my results.
Thanks for help !
You could do something like this:
select
l.* from table l
inner join (
select category, sum(price) as total from table group by category
) r
on l.category = r.category
order by r.total, <some_other_column>
This is the procedure I followed:
find the subtotals
join the original table to the subtotals
order the original table by those subtotals

Tricky "grouped" ordering in SQL

Been having trouble with this for some time.
I have a database sort of like this:
Car_ID Car_Brand Car_Model Car_Price
1 Ford Fiesta 4000
2 Ford Mustang 29000
3 Ford Focus 12000
4 Honda Civic 15000
6 Honda Jazz 5000
7 Toyota Prius 14000
I want to perform a search that finds the cheapest car then orders the rest of the cars of the same brand by price ascending.
I want my output to be this:
Car_ID Car_Brand Car_Model Car_Price
1 Ford Fiesta 4000
3 Ford Focus 12000
2 Ford Mustang 29000
6 Honda Jazz 5000
4 Honda Civic 15000
7 Toyota Prius 14000
The cheapest car is the Ford Fiesta so that and the rest of the Ford models follow it directly ordered by price. Honda then has the second cheapest model so the Jazz and the rest of the Hondas follow and so on.
Is this possible?
What you need to do is create a transient data set that contains car_brand and the lowest price for that brand (which I'll call brand_price), then JOIN that data back to your original cars table. This will give you the additional piece of information (brand_price) that you need to sort the data:
SELECT car_id, car_brand, car_model, price FROM cars C1
JOIN (select car_brand, MIN(price) AS brand_price FROM cars GROUP BY car_brand) C2
ON C1.car_brand = C2.car_brand
ORDER BY C2.brand_price, C1.car_brand, C1.price
Something like this should work:
SELECT a.*
FROM Cars a
LEFT JOIN (
SELECT Car_Brand, MIN(Car_Price) AS MinPrice
FROM Cars
GROUP BY Car_Brand
) b ON a.Car_Brand = b.Car_Brand
ORDER BY b.MinPrice, a.Car_Price
I would do a min grouped by Car_Brand order by the min price and then do a join ordered by the sorted car_brand and price. I will see if I can get the query done for this.
I think you will be able to do that with the following query
SELECT Car_ID, Car_Brand, Car_Model, Car_Price
FROM tblcars
ORDER BY Car_Price, Car_Brand
unless I missed something
select * from cars order by Car_Price, Car_Brand ASC