SQL - View column that calculates the percentage from other columns - sql

I have a query from Access where I caluclated the percentage score of three seperate numbers Ex:
AFPercentageMajor: [AFNumberOfMajors]/([AFTotalMajor]-[AFMajorNA])
which could have values of 20/(23-2) = 95%
I have imported this table into my SQL database and tried to write a expression in the view (changed the names of the columns a bit)
AF_Major / (AF_Major_Totals - AF_Major_NA)
I tried adding *100 to the end of the statement but it only works if the calculation is at 100%. If it is anything less than that it puts it as a 0.
I have a feeling it just doesn't like the combincation of the three seperate column names. But like I said I'm still learning so I could be going at this completely wrong!

SQL Server does integer division. You need to change one of the values to a floating point representation. The following will work:
cast([AFNumberOfMajors] as float)/([AFTotalMajor]-[AFMajorNA])
You can multiply this by 100 to get the percentage value.

Related

How to do some aggregate calculation through several columns one by one?

I am new to SQL and needed some help. I have a table that has some numeric values and I need to populate a column (all values null) with calculations from other columns in the table.
For example. I have some values and a total value. I need another column to calculate the percentage between those two.
I have many columns that need populating from calculation based on different columns. For eg. A column name "risk1" will help me calculate and populate another column called "1per". My code looks something like this:
UPDATE DPRA2_Export
SET "1Per" = ((CAST(Risk1 AS DECIMAL (38,2))/CAST(GrandTotal AS DECIMAL(38,2))) * 100);
UPDATE DPRA2_Export
SET "2Per" = ((CAST(Risk2 AS DECIMAL (38,2))/CAST(GrandTotal AS DECIMAL(38,2))) * 100);
UPDATE DPRA2_Export
SET "3Per" = ((CAST(Risk3 AS DECIMAL (38,2))/CAST(GrandTotal AS DECIMAL(38,2))) * 100);
.................
It goes on like this.
Is there a way I can for-loop this thing instead of writing over and over again. The only thing that changes in the code is the column name "Risk%" and the SET column name "%Per"
Any ideas?
First, having columns with sequential names -- , , . . . -- is suspicious. In general, this format is not a good fit for relational databases. Instead, the data should be stored with one row per risk and an identifier for the risk.
Such tables are often useful for output purposes, but not for storing data.
Second, the data types for the division are probably entirely unnecessary. If you are using a database that does integer division and your values are integers, you can convert using a simpler method such as '*1.0'.
Finally, you can issue a single update:
UPDATE DPRA2_Export
SET "1Per" = Risk1*1.0 / GrandTotal,
"2Per" = Risk2*1.0 / GrandTotal,
"3Per" = Risk3*1.0 / GrandTotal ;
You can construct the logic by querying for the columns, using the information_schema tables.

SQL to powerBI expression?

How to write this expression in PowerBI
select distinct([date]),Temperature from Device47A8F where Temperature>25
Totally new to PowerBI. Is there any tool that can change the query from sql to PowerBI expression?
I have tried so many type of different type of expressions but getting error, Most of the time I am getting this:
The expression refers to multiple columns. Multiple columns cannot be converted to a scalar value.
Need help, Thanks.
After I posted my answer, wondered if your expected result is get only one date by temperature, In other words, without repeated dates in your result set.
A side note: select distinct([date]),Temperature from Device47A8F where Temperature>25 returns repeated dates since DISTINCT keyword evaluate distinct columns values specified in the SELECT statement, it doesn't return distinct values in a specific column even if you surround it with parenthesis.
Now what brings us here. What I can see in your error is that you are trying to use a table-valued (produces a table with multiple columns) expression in a measure which only accepts scalar-valued (calculate only one value).
Supposing you have a table like this:
Running your SQL query you will get the highlighted in yellow rows:
You can see 01/09/2016 date is repeated. If you want to create a measure you have to define what calculation you want to show for temperature. i.e, average, max or min etc.
In the below expression is being calculated the maximum temperature greater than 25 per date:
MaxTempGreaterThan25 =
CALCULATE ( MAX ( Device47A8F[Temperature] ), Device47A8F[Temperature] > 25 )
In this case the measure MaxTempGreaterThan25 is calculated per date.
If you don't want to produce a measure but a table. In the Power BI Tool bar select Modeling tab and click New Table icon.
Use this expression:
MyTemperatureTable =
FILTER ( Device47A8F, Device47A8F[Temperature] > 25 )
It should produce a new table named MyTemperatureTable like this:
I recommend you learn some basics about DAX, it is pretty different from SQL / T-SQL and there are things you can't do depending on your model and data.
Let me know if this helps.
You probably don't need to write any code if your objective is to show the result in a Power BI visual e.g. a table. Power BI naturally aggregates data if the datatype is numeric (e.g. Temperature).
I would just add a Table visual on a Report page and add the Date and Temperature columns to it. Then in Visualizations / Fields / Values I would click the little down-arrow on the Temperature field and set the Aggregation e.g. Maximum. Then in Visualizations / Fields / Filters I would click the little down-arrow on the Temperature field and set the Filter e.g. is greater than: 25
Hard-coded solutions are unlikely to survive the next question from your users e.g. "but what if I want to see Temperature > 24? Or 20? Or 30?"

Microsoft Access - SQL-generated field evaluated as Text instead of Single data type

I have a SQL statement (saved as "LocationSearch" in Access) that calculates distance between two points and returns the "Distance" as a generated field.
SELECT Int((3963*(Atn(-(Sin(LATITUDE/57.2958)*
Sin([#lat]/57.2958)+Cos(LATITUDE/57.2958)*Cos([#lat]/57.2958)*
Cos([#lng]/57.2958-LONGITUDE/57.2958))/Sqr(-(Sin(LATITUDE/57.2958)*
Sin([#lat]/57.2958)+Cos(LATITUDE/57.2958)*Cos([#lat]/57.2958)*
Cos([#lng]/57.2958-LONGITUDE/57.2958))*(Sin(LATITUDE/57.2958)*
Sin([#lat]/57.2958)+Cos(LATITUDE/57.2958)*Cos([#lat]/57.2958)*
Cos([#lng]/57.2958-LONGITUDE/57.2958))+1))+2*Atn(1)))*10)/10 AS Distance, *
FROM Locations
ORDER BY (3963*(Atn(-(Sin(LATITUDE/57.2958)*
Sin([#lat]/57.2958)+Cos(LATITUDE/57.2958)*Cos([#lat]/57.2958)*
Cos([#lng]/57.2958-LONGITUDE/57.2958))/Sqr(-(Sin(LATITUDE/57.2958)*
Sin([#lat]/57.2958)+Cos(LATITUDE/57.2958)*Cos([#lat]/57.2958)*
Cos([#lng]/57.2958-LONGITUDE/57.2958))*(Sin(LATITUDE/57.2958)*
Sin([#lat]/57.2958)+Cos(LATITUDE/57.2958)*Cos([#lat]/57.2958)*
Cos([#lng]/57.2958-LONGITUDE/57.2958))+1))+2*Atn(1)));
All the nasty math code you see is what calculates the distance (in miles) in the SQL statement using Latitude and Longitude coordinates.
However, the problem is that the Distance field that is generated by the SQL statement seems to be returned as a string. If I then add SQL code that asks for locations between a distance of 0 and 45 miles, it returns ANY Distance value that starts between "0" and "45". This includes a location with a distance of "1017" miles. Apparently, the Distance field is a text field, not a number field. So I can't use the "BETWEEN" statement. I also can't evaluate using "<" and ">" because it has the same problem.
I saved the SQL query above as a saved query called "LocationSearch". This way I can run secondary queries against it, like this:
SELECT * FROM LocationSearch WHERE Distance < #MaxDistance
Access will ask for the #lat, #long and #MaxDistance parameters, then the locations will be returned in a recordset, ordered by distance. However, the problem that occurs is when I enter a MaxDistance of 45. With a table containing locations on the West Coast of the US, and a #lat of 47 and a #long of -122 (near Seattle), Access returns the following:
Notice also that the "Distance" field is right-formatted so it appears to be a numeric field, yet for some reason the query returns a location in San Diego, which is 1,017 miles away. My guess is that it was evaluating the Distance field as a text field, and in an ASCII comparison, I believe that "1017" lies between "0" and "45".
One other thing: I'm using ASP 3.0 (classic) to access this query using JET OLEDB 4.0.
Anyone know how to define the Distance field as a number?
Thanks!
--- EDIT ---
Using HansUp's idea from his answer below, I tried this query to force Access to consider the Distance field as a Single precision number:
SELECT * FROM LocationSearch WHERE CSng(Distance) < #MaxDistance
Even this returned the exact same results as before which included the location in San Diego, 1017 miles away.
If you can't find a way to return numerical values instead of text from that Duration field expression, use your query as a subquery, then cast Duration in the containing query.
SELECT CSng(sub.Duration) AS Duration_as_single
FROM
(
-- your existing query --
) AS sub
WHERE CSng(sub.Duration) BETWEEN 0 AND 45
ORDER BY 1;
That approach also makes for a nicer ORDER BY ... if that counts for anything. :-)
I tried your query without the select *, and without the FROM and ORDER BY clauses.
I added in an extra column into the SELECT to prove that strings return as left-justified in access's grid.
SELECT Int((3963*(Atn(-(
Sin(LATITUDE/57.2958)*Sin([#lat]/57.2958)+Cos(LATITUDE/57.2958)*
Cos([#lat]/57.2958)*Cos([#lng]/57.2958-LONGITUDE/57.2958))/Sqr(-(Sin(LATITUDE/57.2958)*
Sin([#lat]/57.2958)+Cos(LATITUDE/57.2958)*Cos([#lat]/57.2958)*
Cos([#lng]/57.2958-LONGITUDE/57.2958))*(Sin(LATITUDE/57.2958)*
Sin([#lat]/57.2958)+Cos(LATITUDE/57.2958)*Cos([#lat]/57.2958)*
Cos([#lng]/57.2958-LONGITUDE/57.2958))+1))+2*Atn(1)))*10)/10 AS Distance,
'test' as test
I was prompted for four parameters, but in the end, I got back a two-column table:
Since the first column in right-justified, and the second (clearly a string) is left-justified, it appears that access is indeed returning it as a numeric for me. This was in Access 2010.
--EDIT--
I just created a new two-column table called Locations. It has a field id (autonumber) and a field Field1 (text). I ran the original query provided by OP and it works fine (distance is returned as a number).
This leads to wonder... Does the OP's Locations table have it's own Distance field, that is a string? Otherwise, the problem has got to be in the code calling the SQL statement, not in the statement or the jet engine itself.
Okay, solved it!
HansUp, your idea turned out to be the solution. I tried adding the CSng() function on the #MaxDistance parameter in the SQL query and that was what fixed it.
Here's the modified secondary SQL query:
SELECT * FROM LocationSearch WHERE CSng(Distance) < CSng(#MaxDistance)
Thanks for your help, everybody! You all rock.
Happy New Year.

How do I get MS Access 2007 to calculate row percentages?

How do I write a query in MS Access 2007 that displays both the count AND the percentage of the total records in a table for each row in a specified field?
For instance, if my table has a field called "gender," what is the query I should write to see the row count and percentage of Men and the row count and percentage of Women?
So, if the table had 1000 records, the result would look something like:
Men.....600.....60%
Women...400.....40%
I can easily write a query that just gives me the row count, but I can't figure out how to also see the percentages.
I should mention that I do not know SQL. I use the Design View when creating queries. But if you can give me the text for the query in SQL, I can copy and paste it into a new query and then save it.
It's not part of SQL itself, but you can use a VBA function in a query to count the amount of records in a table: DCount (MSDN).
Copy and paste the following lines in the query designer (top row, one line per column):
TotalMen: DCount("*";"[TableNameHere]";"[Gender]='Male'")
TotalWomen: DCount("*";"[TableNameHere]";"[Gender]='Female'")
You can then get the percentage by performing some simple math on the return values (again one line per column):
TotalPersons: [TotalMen]+[TotalWomen]
PercentageMen: [TotalMen]/[TotalPersons]
PercentageWomen: [TotalWomen]/[TotalPersons]
Don't forget to set the format to Percentage or the values will show up as 0,6 and 0,4 instead of 60% and 40%.
By the way, there are probably more consise ways to do it. I tried to make it readable.
PS: don't forget to replace the names of the tables and fields.

How to average values based on location proximity

I have an SQL table with geo-tagged values (Longitude, Latitude, value). The table is accumulated quickly and has thousands entries. Therefore, querying the table for values in some area return very large data-set.
I would like to know the way to average value with close location proximity to one value, here is an illustration:
Table:
Long lat value
10.123001 53.567001 10
10.123002 53.567002 12
10.123003 53.567003 18
10.124003 53.568003 13
lets say my current location is 10.123004, 53.567004. If I am querying for the values near by I will get the four raws with values 10, 12, 18, and 13. This works if the data-set is relatively small. If the data is large I would like to query sql for rounded location (10.123, 53.567) and need sql to return something like
Long lat value
10.123 53.567 10 (this is the average of 10, 12, and 18)
10.124 53.568 13
Is this possible? how we can average large data set based on locations?
Is sql database is the right choice in the first place?
GROUP BY rounded columns, and the AVG aggregate function should work fine for this:
SELECT ROUND(Long, 3) Long,
ROUND(Lat, 3) Lat,
AVG(value)
FROM Table
GROUP BY ROUND(Long, 3), ROUND(Lat, 3)
Add a WHERE clause to filter as needed.
Here's some rough pseudocode that might be a start. You need to provide the proper precision arguments for the round function in the dialect of SQL you are using for your project, so understand that the 3 I provide as the second argument to Round is the number of decimals of precision to which the number is rounded, as indicated by your original post.
Select round(lat,3),round(long,3),avg(value)
Group by round(lat,3),round(long,3)
The problem with the rounding approach is the boundary conditions -- what happens when points are close to the bounday.
However, for the neighborhood of a given point it is better to use something like:
select *
from table
where long between #MyLong - #DeltaLong and #MyLong + #DeltaLong and
lat between #MyLat - #DeltaLat and #MyLat + #DeltaLat
For this, you need to define #DeltaLong and #DeltaLat.
Rounding works fine for summarization, if that is your problem.