MS Access Query to output all values and treat unavailable values as zero - sql

I've created a query MS Access 2010 that is intended to take all fuel types (all values) for each date. I have the query relationship below: ) and have the following 6 values for fuel type: Diesel #2, MSFO, ULSD, Biodiesel, Used Oil, Heat Recovery.
I'm trying to output the fuel delivery for each fuel type for each date regardless if there's any fuel delivered that date
and
. What I'm getting as my output is below
.
I have tried to change the relationships such that all values on tbl_FuelType would output. This gave me the output on the figure above. I've tried entering a criteria to look for the specific fuel type (e.g. "ULSD") but if there's no data for that day, it will output with Null values, which I don't want. See criteria below
I've tried some program flow functions such as IIF and Switch but still getting null values. Is there an easy way to do this without having to go into the table and filling out values as zero's for all the different fuel types on the tbl_FuelDelivery? The SQL view is as follows:
SELECT tbl_FuelDelivery.DateLog, Sum(Nz([tbl_FuelDelivery].[F_FO_gal_Gross],0)) AS Fuel_Delivery_Gross, Sum(Nz([tbl_FuelDelivery].[F_FO_gal_Net],0)) AS Fuel_Delivery_Net, tbl_FuelType.FuelType
FROM tbl_FuelType LEFT JOIN tbl_FuelDelivery ON tbl_FuelType.ID = tbl_FuelDelivery.FuelType
GROUP BY tbl_FuelDelivery.DateLog, tbl_FuelType.FuelType
ORDER BY tbl_FuelDelivery.DateLog;
​

What you need to add to your query is a table with all dates. You can have a separate table where all dates are entered, such a calendar table or have it derived from your tbl_FuelDelivery like this:
SELECT DISTINCT tbl_FuelDelivery.DateLog
FROM tbl_FuelDelivery;
Now, you need to CROSS JOIN this table with tbl_FuelType. Access does not natively support cross joins, so you'll have to use a workaround: just add the cross join as a comma separated table to your FROM clause:
SELECT a.DateLog, tbl_FuelType.FuelType, tbl_FuelType.ID
FROM (SELECT DISTINCT tbl_FuelDelivery.DateLog FROM tbl_FuelDelivery) a,
tbl_FuelType;
The query above will give you the all fuel types for all dates. You can save it as a new query (let's call it allDatesFuels). Now, all you need to do is to join it with your query:
SELECT
allDatesFuels.DateLog,
Sum(Nz([tbl_FuelDelivery].[F_FO_gal_Gross],0)) AS Fuel_Delivery_Gross,
Sum(Nz([tbl_FuelDelivery].[F_FO_gal_Net],0)) AS Fuel_Delivery_Net,
allDatesFuels.FuelType
FROM allDatesFuels LEFT JOIN tbl_FuelDelivery ON allDatesFuels.ID = tbl_FuelDelivery.FuelType And allDatesFuels.DateLog = tbl_FuelDelivery.DateLog
GROUP BY allDatesFuels.DateLog, allDatesFuels.FuelType
ORDER BY allDatesFuels.DateLog;
​

Related

MS Access 2013, How to add totals row within SQL

I'm in need of some assistance. I have search and not found what I'm looking for. I have an assigment for school that requires me to use SQL. I have a query that pulls some colunms from two tables:
SELECT Course.CourseNo, Course.CrHrs, Sections.Yr, Sections.Term, Sections.Location
FROM Course
INNER JOIN Sections ON Course.CourseNo = Sections.CourseNo
WHERE Sections.Term="spring";
I need to add a Totals row at the bottom to count the CourseNo and Sum the CrHrs. It has to be done through SQL query design as I need to paste the code. I know it can be done with the datasheet view but she will not accept that. Any advice?
To accomplish this, you can union your query together with an aggregation query. Its not clear from your question which columns you are trying to get "Totals" from, but here's an example of what I mean using your query and getting counts of each (kind of useless example - but you should be able to apply to what you are doing):
SELECT
[Course].[CourseNo]
, [Course].[CrHrs]
, [Sections].[Yr]
, [Sections].[Term]
, [Sections].[Location]
FROM
[Course]
INNER JOIN [Sections] ON [Course].[CourseNo] = [Sections].[CourseNo]
WHERE [Sections].[Term] = [spring]
UNION ALL
SELECT
"TOTALS"
, SUM([Course].[CrHrs])
, count([Sections].[Yr])
, Count([Sections].[Term])
, Count([Sections].[Location])
FROM
[Course]
INNER JOIN [Sections] ON [Course].[CourseNo] = [Sections].[CourseNo]
WHERE [Sections].[Term] = “spring”
You can prepare your "total" query separately, and then output both query results together with "UNION".
It might look like:
SELECT Course.CourseNo, Course.CrHrs, Sections.Yr, Sections.Term, Sections.Location
FROM Course
INNER JOIN Sections ON Course.CourseNo = Sections.CourseNo
WHERE Sections.Term="spring"
UNION
SELECT "Total", SUM(Course.CrHrs), SUM(Sections.Yr), SUM(Sections.Term), SUM(Sections.Location)
FROM Course
INNER JOIN Sections ON Course.CourseNo = Sections.CourseNo
WHERE Sections.Term="spring";
Whilst you can certainly union the aggregated totals query to the end of your original query, in my opinion this would be really bad practice and would be undesirable for any real-world application.
Consider that the resulting query could no longer be used for any meaningful analysis of the data: if displayed in a datagrid, the user would not be able to sort the data without the totals row being interspersed amongst the rest of the data; the user could no longer use the built-in Totals option to perform their own aggregate operation, and the insertion of a row only identifiable by the term totals could even conflict with other data within the set.
Instead, I would suggest displaying the totals within an entirely separate form control, using a separate query such as the following (based on your own example):
SELECT Count(Course.CourseNo) as Courses, Sum(Course.CrHrs) as Hours
FROM Course INNER JOIN Sections ON Course.CourseNo = Sections.CourseNo
WHERE Sections.Term = "spring";
However, since CrHrs are fields within your Course table and not within your Sections table, the above may yield multiples of the desired result, with the number of hours multiplied by the number of corresponding records in the Sections table.
If this is the case, the following may be more suitable:
SELECT Count(Course.CourseNo) as Courses, Sum(Course.CrHrs) as Hours
FROM
Course INNER JOIN
(SELECT DISTINCT s.CourseNo FROM Sections s WHERE s.Term = "spring") q
ON Course.CourseNo = q.CourseNo

Query to return the amount of time each field equals a true value

I'm collecting data and storing in SQL Server. The table consist of the data shown in the Example Table below. I need to show the amount of time that each field [Fault0-Fault10] is in a fault state. The fault state is represented as a 1 for the fields value.
I have used the following query and got the desired results. However this is for only one field. I need to have the total time for each field in one query. I'm having issues pulling all of the fields into one query.
SELECT
Distinct [Fault0]
,datediff(mi, min(DateAndTime), max(DateAndTime)) TotalTimeInMins
FROM [dbo].[Fault]
Where Fault0 =1
group by [Fault0]
Results
Assuming you want the max() - min(), then you simply need to unpivot the data. Your query can look like:
SELECT v.faultname,
datediff(minute, min(t.DateAndTime), max(t.DateAndTime)) as TotalTimeInMins
FROM [dbo].[Fault] f CROSS APPLY
(VALUES ('fault0', fault0), ('fault1', fault1), . . ., ('fault10', fault10)
) v(faultname, value)
WHERE v.value = 1
GROUP BY v.faultname;

SQL Calculations over tables

There are 2 tables, there is an expected result, the result is to have the total cost of each engagement calculated, there are multiple tests taken during each engagement, each test ranges in cost (all set values), the expected result must be in terms of EngagementId, EngagementCost
The 2 tables, with there respective fields
- EngagementTest (EngagementId, TestId)
- Test (TestId, TestCost)
How would one go calculating the cost of each engagement.
This is as far as i managed to get
SELECT EngagementId, COUNT(TESTId)
FROM EngagementTest
GROUP BY EngagementId;
Try a SUM of the TestCost column rather than a COUNT. COUNT just tells you the number of rows. SUM adds up the values within the rows and gives you a total. Also your existing query doesn't actually use the table that contains the cost data. You can INNER JOIN the two tables via TestId and then GROUP BY the EngagementId so you get the sum of each engagement.
Something like this:
SELECT
ET.EngagementId,
SUM(T.TestCost)
FROM
EngagementTest ET
INNER JOIN Test T
ON T.TestId = ET.TestId
GROUP BY
ET.EngagementId
It can be achieved using below query.
SELECT i.EngagementId, SUM(TestCost)
FROM EngagementTest i
INNER JOIN Test t
ON e.TestId = t.TestId
GROUP BY i.EngagementId

SQL : how to calculate an average from a query

I've been using SQL for about a week at my first full time job, and I'm trying to calculate some statistics from a query where I've combined columns from separate tables.
Specifically, I'm trying to calculate an average from a combined table, where I have applied filters (or constraints? I'm not clear on the SQL lingo).
From doing research on Google, I learned how to calculate an average:
SELECT AVG(column_name)
FROM table_name
The problem I'm having is that this only seems to work with existing tables in the database, not with new queries I have created.
A simplified version of my code is as follows:
SELECT
Animal_Facts.Animal_Name, Animal_Facts.Prev_Reg_Amount,
Names.Given_Name, Animal_Class.Class_Description
FROM
Names
INNER JOIN
Animal_Facts ON Names.Name_Key = Animal_Facts.Name_Key
INNER JOIN
Animal_Class ON Animal_Facts.Class_Key = Animal_Class.Class_Key
This query creates combines four columns from three tables, where Class_Description describes whether the animal is desexed, microchipped, owned by a pensioner etc, and Pre_Reg_Amount is the registration fee paid.
I want to find the average fee paid by pensioners, so I included the following line of code to filter the table:
AND Animal_Class.Class_Description LIKE ('%pensioner%')
And then to calculate the average I add:
SELECT AVG(Animal_Facts.Prev_Reg_Amount) from Animal_Facts
So my total code is:
SELECT
Animal_Facts.Animal_Name, Animal_Facts.Prev_Reg_Amount,
Names.Given_Name, Animal_Class.Class_Description
FROM
Names
INNER JOIN
Animal_Facts ON Names.Name_Key = Animal_Facts.Name_Key
INNER JOIN
Animal_Class ON Animal_Facts.Class_Key = Animal_Class.Class_Key
AND Animal_Class.Class_Description LIKE ('%pensioner%')
SELECT AVG(Animal_Facts.Prev_Reg_Amount)
FROM Animal_Facts
Now the problem is, after checking this calculation in Excel, I'm not actually getting the average of the pensioner data, but the average of all the data. Is there a way to calculate averages (and other statistics) directly from my created table in SQL?
Note: I am able to calculate all these statistics by exporting the data to Excel, but it is much more time consuming. I'd much rather learn how to do this within SQL.
SELECT AVG(af.Prev_Reg_Amount)
FROM
Animal_Facts af
INNER JOIN Animal_Class ac
ON af.Class_Key = ac.Class_Key
AND Class_Description LIKE ('%pensioner%')

Parameters being passed in are in wrong format for table

I have a query whereby parameters are being passed in in the format 'GRB','MIN','OSH' and so on. These are called "Divisions". They may be passed in singly or in a list of any number of them. These are used in one of the tables n a report.
The problem is that the table I am going to read other divisions are going to have them in numerical format. so GRB = 02, MIN=04 and OSH = 08. There are 12 different values.
So in essence, the SSRS report might pass in all these for an "IN" statement. They have to be presented in this manner.
I need to find a way to convert all of these alphanumeric codes into their corresponding numeric codes.
Main query with alphanumeric:
dbo.TQMNCR.PlantID IN (#PlantID)
Temp table with (hopefully) corresponding numeric values:
ProdTable.DIMENSION2_ in (????????)
Presuming that dbo.TQMNCR has a PlantNumber column for the numeric key, you could use a join like this.
SELECT ...
FROM dbo.TQMNCR AS Source
INNER JOIN ProdTable AS Mapping
ON Mapping.DIMENSION2_ = Source.THE_NUMERIC_KEY_COLUMN_YOU_SPEAK_OF
WHERE Mapping.PlantID IN (#PlantID)
Alternatively, if you don't want to use a permanent table to map them, you can also use a common table expression (numerous other options).
WITH Mapping_CTE AS (
SELECT 'GRB' AS PlantID, '02' AS PlantNumber
UNION ALL
SELECT 'MIN' AS PlantID, '04' AS PlantNumber
UNION ALL
...
)
SELECT ...
FROM dbo.TQMNCR AS Source
INNER JOIN Mapping_CTE AS Mapping
ON Mapping.PlantNumber = Source.THE_NUMERIC_KEY_COLUMN_YOU_SPEAK_OF
WHERE Mapping.PlantID IN (#PlantID)