Refine Query Results from MySQL Database - mysql

I have the following query:
SELECT routes.route_date, time_slots.name, time_slots.openings, time_slots.appointments
FROM routes
INNER JOIN time_slots ON routes.route_id = time_slots.route_id
WHERE route_date
BETWEEN 20140109
AND 20140115
AND time_slots.openings > time_slots.appointments
ORDER BY route_date, name
This works just fine and will produce the following results:
What I want to do is only return one name per date. So the 9th, name = 1, would only have 1 result, rather than 2, as it currently does.

UPDATE: See the SQLFIDDLE for different type of solutions here: http://sqlfiddle.com/#!2/9ac65b/6
Will it solve your request if you use...
SELECT DISTINCT routes.route_date...your query... ?
It depends if you know that your rows always will have the same values, for same date/name.
Otherwise use group by...
(which I think suits your request best)
SELECT routes.route_date, time_slots.name, sum(time_slots.openings), sum(time_slots.appointments)
FROM routes
INNER JOIN time_slots ON routes.route_id = time_slots.route_id
WHERE route_date
BETWEEN 20140109
AND 20140115
AND time_slots.openings > time_slots.appointments
group by routes.route_date, time_slots.name
ORDER BY route_date, name
(i did a sum for the openings and appointments, you could do min, max, count, etc. Pick the one that fits your requirements best!)

You need to figure out which "name" you want when there are several for the same date.
Then you can group by date and select the right "name" by using an aggregate function like COUNT, MAX, etc.
I can't help you more if you don't explain your rule for picking one.

Related

Group By Largest revision string

I need to figure out a way to group these properly. I have a results set that returns Incident numbers which are actually datatype string, that have revisions done. I only need the grouping of the last revision number entered. Such as the below.
INC-101
INC-101
INC-101A1
INC-101A1
INC-101A2
INC-101A2
JNC-101
JNC-101
JNC-101S1
JNC-101S1
How could I only see the highest revision number such as the following:
INC-101A2
INC-101A2
JNC-101S1
JNC-101S1
You can use GROUP BY with SUBSTRING, e.g.:
SELECT MAX(incident_no)
FROM incidents
GROUP BY SUBSTRING(incident_no, 1, 7);
Here's the SQL Fiddle.
Update
If you want all the rows belonging to the latest revision number then you can use the above query as sub-query, e.g.:
SELECT *
FROM incidents
WHERE incident_no IN (
SELECT MAX(incident_no)
FROM incidents
GROUP BY SUBSTRING(incident_no, 1, 7)
);
You could use the max-function in conjunction with group by on the "base" of an incident numner. Not sure, if it works completely as you expect, since I do not know the number system used. But maybe with some adaptions you get the results you want rather easy:
select max(incnumber)
from incidents
group by left(incnumber,7)

Query max(date) with group by not working on SELECT ... IN?

Each page in my system has multiple page_objects.
I need to return the last_changed records of my page_objects per page.
To decrease DB-impact, I have a SELECT ... IN query to return each last-edited page_object per page:
SELECT object, f_page_id, page_object_id, last_change
FROM page_objects
WHERE f_page_id IN (page_id1, page_id2, page_id3, etc...) GROUP BY f_page_id
ORDER BY last_change ASC;
Of course this does not work, because GROUP BY is applied before ORDER BY, so I changed the query:
SELECT object, f_page_id, page_object_id, max(UNIX_TIMESTAMP(last_change))
FROM page_objects
WHERE f_page_id IN (page_id1, page_id2, page_id3, etc...) GROUP BY f_page_id
But this still does not return the last-edited page_object per page_id.
What am I doing wrong?
Your query does not specify to get the record for the latest last_change. Merely that it gets the latest value of last_change. The other non aggregate values (ie, not the result of an aggregate function like MAX or MIN) that are not mentioned in the GROUP BY clause can come from any row for the grouped values.
As such you use a sub query to get the latest value for each page, and then join that back against your main table to get the matching rows
Something like this:-
SELECT page_objects.object,
page_objects.f_page_id,
page_objects.page_object_id,
page_objects.last_change
FROM page_objects
INNER JOIN
(
SELECT f_page_id, MAX(last_change) AS latest_last_change
FROM page_objects
GROUP BY f_page_id
) sub0
ON page_objects.f_page_id = sub0.f_page_id
AND page_objects.last_change = sub0.latest_last_change
WHERE page_objects.f_page_id IN (page_id1, page_id2, page_id3, etc...)
ORDER BY last_change DESC
Note that MySQL is quite unusual at allowing you to have non aggregate columns that are not mentioned in the GROUP BY clause (as it is against SQL standards, except under very particular circumstances). Most flavours of SQL will issue an error if you try this, and MySQL has a configuration parameter which will similar cause it to reject such queries.

Using a COUNT value in an expression getting..does not include specified expression as part of an aggregate function

I am trying to display a warning if a bike station gets to over 90% full or less than 10% full. When i run this query I get "you are trying to execute query that does not include the iif statment... as part of an aggregate function.
Bike_locations table - Bicycle_id and Locations_ID
Locations table - Locations_ID, No_of_Spaces, Location_Address
SELECT Locations.Location_Address, Count(Bike_Locations.Bicycle_ID) AS CountOfBicycle_ID,
IIf(((([CountOfBicycle_ID]/[LOCATIONS]![No_Of_Spaces])*100)>90),"This Station is nearly full.
Need to move some bicycles out of here",IIf(((([CountOfBicycle_ID]/[LOCATIONS]![No_Of_Spaces])*100)
<10),"This station is nearly empty. Need to move some bicycles here","")) AS Warnings
FROM Locations INNER JOIN Bike_Locations ON Locations.[LOCATIONS_ID] = Bike_Locations.[LOCATIONS_ID]
GROUP BY Locations.Location_Address;
Anyone got a scooby
When you use a GROUP BY, you should have the exact same fields in both your SELECT and GROUP BY statements, except for the aggregate function that should only be specified in the SELECT
The aggregate function in your case is the COUNT(*)
The fields you aggregate on are:
in the SELECT : Location_Address and Warnings
in the GROUP BY : Location_Address only
The error message is telling you that you don't have the same in both statements.
2 solutions:
Remove the Warnings from the SELECT statement
Add the Warnings to the GROUP BY statement
Note that in MS Access SQL, you can't (unfortunately) use in the GROUP BY, the Aliases specified in the SELECT. So you have to copy over the whole field, which would be the long iif in your case
Edit: better solution proposal:
I would radically change your approach as you'll go no where with all those nested iff
Create the following Query and Name it (for instance) Stations_Occupation
SELECT L.Locations_ID AS ID,
L.Location_Address AS Addr,
L.No_of_Spaces AS TotSpace,
BL.cnt AS OccSpace,
ROUND((BL.cnt/L.No_of_Spaces*100),0) AS OccPourc
FROM Locations L
LEFT JOIN
(
SELECT Locations_ID, COUNT(*) AS cnt
FROM Bike_Locations
GROUP BY LOCATIONS_ID
) AS BL ON L.Locations_ID = BL.Locations_ID
This query will probably be a lot helpfull in many parts of your application, and not only here, as it calculates the occupation % of each station
Some examples:
Get all stations with >90% occupation:
SELECT Addr
FROM Stations_Occupation
WHERE OccPourc > 90
Get all stations with <10% occupation:
SELECT Addr
FROM Stations_Occupation
WHERE OccPourc < 10
Get Occupation level of a specific station:
SELECT OccPourc
FROM Stations_Occupation
WHERE ID=specific_station_ID
Get number of bikes and max on a specific station:
SELECT OccSpace & "/" & TotSpace
FROM Stations_Occupation
WHERE ID=specific_station_ID

MySQL Select within another select

I have a query as follows
select
Sum(If(departments.vat, If(weeklytransactions.weekendingdate Between
'2011-01-04' And '2099-12-31', weeklytransactions.takings / 1.2,
If(weeklytransactions.weekendingdate Between '2008-11-30' And '2010-01-01',
weeklytransactions.takings / 1.15, weeklytransactions.takings / 1.175)),
weeklytransactions.takings)) As Total,
weeklytransactions.weekendingdate,......
and another that returns a vat rate as follows
select format(Max(Distinct vat_rates.Vat_Rate),3) From vat_rates Where
vat_rates.Vat_From <= '2011-01-03'
I want to replace the hard coded if statement with the lower query, replacing the date in the lower query with weeklytransactions.weekendingdate.
After Kevin's comments, here is the full query I'm trying to get to work;
Select Max(vat_rates.vat_rate) As r,
If(departments.vat, weeklytransactions.takings / r, weeklytransactions.takings) As Total,
weeklytransactions.weekendingdate,
Week(weeklytransactions.weekendingdate),
round(datediff(weekendingdate, (if(month(weekendingdate)>5,concat(year(weekendingdate),'-06-01'),concat(year(weekendingdate)-1,'-06-01'))))/7,0)+1 as fyweek,
cast((Case When Month(weeklytransactions.weekendingdate) >5 Then Concat(Year(weeklytransactions.weekendingdate), '-',Year(weeklytransactions.weekendingdate) + 1) Else Concat(Year(weeklytransactions.weekendingdate) - 1, '-',Year(weeklytransactions.weekendingdate)) End) as char) As fy,
business_units.business_unit
From departments Inner Join (business_units Inner Join weeklytransactions On business_units.buID = weeklytransactions.businessUnit) On departments.deptid = weeklytransactions.departmentId
Where (vat_rates.vat_from <= weeklytransactions.weekendingdate and business_units.Active = true and business_units.sales=1)
Group By weeklytransactions.weekendingdate, business_units.business_unit Order By fy desc, business_unit, fyweek
Regards
Pete
Assuming I read your question correctly, your problem is about having the result of another SELECT used to be returned by the result of your main query (plus depending on how acquainted you are with SQL, maybe you haven't had the occasion to learn about JOINs?).
You can have subqueries you extract data from within a SELECT, provided you define it within the FROMclause. The following query will work, for example:
SELECT A.a, B.b
FROM A
JOIN (SELECT aggregate(c) FROM C) AS B
Notice that there is no reference to table A within the subquery. Thing is, you cannot just add it like that to the query, as the subquery doesn't know it is a subquery. So the following won't work:
SELECT A.a, B.b
FROM A
JOIN (SELECT aggregate(c) FROM C WHERE C.someValue = A.someValue) AS B
Back to basics. What you want to do here visibly, is to aggregate some data associated to each of the records of another table. For that, you will need merge your SELECT queries and use GROUP BY:
SELECT A.a, aggregate(C.c)
FROM A, C
WHERE C.someValue = A.someValue
GROUP BY A.a
Back to your tables, the following should work:
SELECT w.weekendingdate, FORMAT(MAX(v.Vat_Rate, 3)
FROM weeklytransactions AS w, vat_rates AS v
WHERE v.Vat_From <= w.weekendingdate
GROUP BY w.weekendingdate
Feel free to add and remove fields and conditions as you see fit (I wouldn't be surprised that you'd also want to use a lower bound when filtering the records from vat_rates, since the way I have written it above, for a given weekendingdate, you get records from that week + the weeks before!).
So it looks like my first try did not address the actual problem. With the additional information provided in the comments, as well as the new complete query, let's see how this goes.
We are still missing error messages, but normally the query as written should result in MySQL having the following complaint:
ERROR 1109 (42S02): Unknown table 'vat_rates' in field list
Why? Because the vat_rates table does not appear in the FROM clause, whereas it should. Let's make that more obvious by simplifying the query, removing all references to the business_units table as well as the fields, calculations and order that do not add or remove anything to the problem, leaving us with the following:
SELECT MAX(vat_rates.vat_rate) AS r,
IF(d.vat, w.takings / r, w.takings) AS Total
FROM departments AS d
INNER JOIN weeklytransactions AS w ON w.departmentId = d.deptid
WHERE vat_rates.vat_from <= w.weekendingdate
GROUP BY w.weekendingdate
That cannot work, and will produce the error mentioned above. It looks like there is no FOREIGN ID between the weeklytransactions and vat_rates tables, so we have no choice but to do a CROSS JOIN for the moment, hoping that the condition in the WHERE clause and the aggregate function used to get r are enough to fit the business logic at hand here. The following query should return the expected data instead of an error message (I also remove r since that seems to be an intermediate value judging by the comments that were written):
SELECT IF(d.vat, w.takings / MAX(v.vat_rate), w.takings) AS Total
FROM vat_rates AS v, departments AS d
INNER JOIN weeklytransactions AS w ON w.departmentId = d.deptid
WHERE v.vat_from <= w.weekendingdate
GROUP BY w.weekendingdate
From there, assuming it works, you will only need to put back all the parts I removed to get your final query. I am a tad doubtful about the way the VAT rate is gotten here, but I have no idea what your requirements are in that regard so I leave it up to you to make sure that works as expected.

Query to sum some of the values

Ive got a simple query that is used on a search. My problem is with this query is that as the records in mysql are added everytime there is a transaction, the query returns a list of data when there could only be one or a few more rows instead of a lot more.
SQLFliddle
As you can see here - the query returns a lot of rows, where I want it to return
BLSH103 A001A 31 24/01/2014
Can the qty where the product name & pallet space are the same be summed? And then show the largest date?
just use a sum function on t.Quantity (and a group by clause)
SELECT (t.ProductName) as Pname ,(s.PalletSpace) as PSpace, sum(t.Quantity) as Qty,(t.TransactionDate) as Transac
FROM PalletSpaces s
JOIN ProductTrans t
ON s.PalletSpaceID = t.PalletSpace
WHERE t.ProductName LIKE 'BLSH103' OR s.PalletSpace LIKE 'BLSH103'
group by
Pname,
pSpace,
Transac -- if you want to group by date also...
By the way, using LIKE this way (without %) doesn't make much sense...
see SqlFiddle
You just need to use GROUP BY and SUM in this way:
SELECT (t.ProductName) as Pname ,(s.PalletSpace) as PSpace, SUM(t.Quantity) as Qty,(t.TransactionDate) as Transac
FROM PalletSpaces s
JOIN ProductTrans t
ON s.PalletSpaceID = t.PalletSpace
WHERE t.ProductName LIKE 'BLSH103' OR s.PalletSpace LIKE 'BLSH103'
GROUP BY t.ProductName, s.PalletSpace;