Using a Calculated field in SQL Query - sql

I have a sql query in which i have a calculated field which calculates the Contribution Margin. I get it to display and the math works fine. The problem i'm having is that i want to only display the records in which the Contribution Margin is lower than 0.25. I know you cant use column alias in the where clause. I was wondering what the best way to go about doing this would be. I'm also using Visual Studio for this.

SELECT *
FROM (
SELECT m.*,
compute_margin(field1, field2) AS margin
FROM mytable m
) q
WHERE margin < 0.25

You can't use the column alias (unless you use your original query as a subquery), but you can use the expression that you're using to define the calculated value.
For example, if your query is this now:
select
contribution_amount,
total_amount,
contribution_amount / total_amount as contribution_margin
from records
You could do this:
select
contribution_amount,
total_amount,
contribution_amount / total_amount as contribution_margin
from records
where contribution_amount / total_amount < 0.25
Or this:
select * from
(
select
contribution_amount,
total_amount,
contribution_amount / total_amount as contribution_margin
from records
)
where contribution_margin < 0.25
(Personally I find the first version to be preferable, but both will likely perform the same)

You can either
repeat the calculation in the where clause
wrap the query in a table expression (CTE or derived table) and use the alias in the where clause
assign the alias in a cross apply.
To give an example of the last approach
select doubled_schema_id,*
from sys.objects
cross apply (select schema_id*2 as doubled_schema_id) c
where doubled_schema_id= 2

two ways, either the solution that Quassnoi posted(you can also use a CTE which is similar)
or WHERE compute_margin(field1, field2) < 0.25

Related

counts' division doesn't work in full code

I do have a problem with a task because my division value is different when I use it alone and when I use it in full code. Let's say I do this code:
SELECT (count(paimta))::numeric / count(distinct paimta) as average
FROM Stud.Egzempliorius;
and finally a number I get is 2.(6)7, but when I use it in full code which is:
SELECT Stud.Egzempliorius.Paimta, COUNT(PAIMTA) as PaimtaKnyga
FROM Stud.Skaitytojas, Stud.Egzempliorius
WHERE Stud.Skaitytojas.Nr=Stud.Egzempliorius.Skaitytojas
GROUP BY Stud.Egzempliorius.Paimta
HAVING count(paimta) > (count(paimta))::numeric / count(distinct paimta);
it's value changes because division is not working anymore and let's say instead of having
HAVING count(paimta) > (count(paimta))::numeric / count(distinct paimta);
my codes turns into
HAVING count(paimta) > (count(paimta))::numeric;
and these values are equal, so I can't get final answer. That's database I use https://klevas.mif.vu.lt/~baronas/dbvs/biblio/show-table.php?table=Stud.Egzempliorius
I was struggling for 10 hours now and finally I've lost my patience... So, my question is what I have to do that this code:
SELECT (count(paimta))::numeric / count(distinct paimta) as average
FROM Stud.Egzempliorius;
value doesn't change in full code?
Picture how it changes Photo
Your solution fails because the two queries operate on a different groups of rows. The first query does a computation over the whole dataset, while the second one groups by paimta.
One option would have been to use window functions, but as far as concerns Postgres does not support count(distinct) as a window function.
I think that the simplest approach is to use a subquery :
select e.paimta, count(paimta) as paimtaknyga
from stud.skaitytojas s
inner join stud.egzempliorius e on s.nr = e.skaitytojas
group by e.paimta
having count(paimta) > (
select (count(paimta))::numeric / count(distinct paimta) from stud.egzempliorius
)

PostgreSQL : Percentage without a WHERE

i need to get a percentage but can't use the WHERE clause because it is a part of a large SQL query.
I try to do this :
select (count(sector='Rurality'))/(count(sector))*100 as test from study
But the first count get full results instead of filtering.
In other words, this doesn't work :
select COUNT(sector='Rurality') AS test FROM study;
Maybe somebody could have any idea ? The problem is that filters are glued to the SQL query after all of this but can't add a WHERE sector="rurality".
This is what FILTER is for:
select count(*) filter (where sector = 'Rurality') test from study;
For older PostgreSQL, you can use the CASE construct, but don't forget to omit the ELSE clause to not count NULL values:
select count(case sector when 'Rurality' then 1 end) test from study;
Also, bigint / bigint will be bigint, so use casts and/or parenthesis, or just re-structure your formula, like:
select 100.0 * count(*) filter (where sector = 'Rurality') / count(sector) test
from study;
Your approach works with sum():
select sum((sector='Rurality')::int)::dec / count(sector)*100 as test from study
Use a CASE statement inside the COUNT.
SELECT (COUNT(CASE WHEN sector = 'Rurality' THEN 1 END)) / (COUNT(sector)) * 100 AS test
FROM study

How to force Total Column to appear at last in a TRANSFORM SQL statement

I have the following SQL statement to create a summary view
TRANSFORM Sum(Amount) AS CurrAmount
SELECT Currency, Sum(Amount) AS TotalAmount
From MyTable
GROUP BY Currency
ORDER BY Currency
PIVOT Source
It creates the following view
Currency TotalAmount Retail Corporate Others
EUR 7,071 585 2,345 4,141
GBP 10,444 2,322 4,889 3,233
JPY 7,050 1,295 4,500 1,255
USD 1,625 250 450 925
I am looking for help wherein I need the 'TotalAmount' field to appear as the last column. Much appreciated
Niz
I think your requirement for column ordering/sequence can be handled by the IN clause that is supported by the TRANSFORM operator. Have a look at this:
TRANSFORM <aggregate-function-expression>
<select-statement>
PIVOT <expression>
[IN (<column-value-list>)]
where <aggregate-function-expression> is an expression created with one of the aggregate functions, <select-statement> contains a GROUP BY clause, and <column-value-list> is a list of required values expected to be returned by the PIVOT expression, enclosed in quotes and separated by commas. (You can use the IN clause to force the output sequence of the columns.)
In other words, just use IN and put your quote/comma delimited list of columns in the desired order (e.g. IN ("Currency", "Retail", "Corporate", "Others", "TotalAmount"))
Seems a little complicated to me, but it appears to be supported by Access.
Note: this info was grabbed from the following article:
TRANSFORM Statement
The solution using IN clause somewhat does the job but behaves quite strange at times. Moreover, the departments (retail, corporate) are not fixed for me. New departments keep coming and therefore I cannot be hard coding it every time. I had it resolved in a simpler way.
SELECT Currency,
(SELECT SUM(t1.Amount) FROM MyTable t1 WHERE t1.Source = 'Retail' AND t1.Curr = pos.Curr) Retail,
(SELECT SUM(t1.Amount) FROM MyTable t1 WHERE t1.Source = 'Corporate' AND t1.Curr = pos.Curr) Corporate,
(SELECT SUM(t1.Amount) FROM MyTable t1 WHERE t1.Source NOT IN ('Retail','Corporate') AND t1.Curr = pos.Curr) Others,
(SELECT SUM(t1.Amount) FROM MyTable t1 WHERE t1.Curr = pos.Curr) Total
FROM MyTable pos
GROUP BY Curr
ORDER BY Curr
Even in the above, if there are new departments (appearing in Others) I will end up changing the SQL if I may need to specify, but still is in my control unlike the TRANSFORM statement where is goes out of control.
Thanks guys.

Emulate subquery with no main table in access

I can do this in SQL Server:
SELECT 'HERRAMIENTA ELÉCTRICA' AS TIPO_PRODUCTO,
0 AS DEPRECIACION,
(select sum(empid) from HR.employees) STOCK
but in Access the same query show me the next error:
Query input must contain at least one table or query
So which could be the best form to emulate this? Make a query with any other table looks dirty for me.
EDIT 1:, HR.employees It may no have data, but i want show constants ('HERRAMIENTA ELÉCTRICA',''0') and 0 in the third column, maybe using isnull and this is not the problem here.
Why not to select directly:
select 'HERRAMIENTA ELÉCTRICA' AS TIPO_PRODUCTO,
0 AS DEPRECIACION,
IIF(ISNULL(sum(empid)), 0, sum(empid)) AS STOCK
from HR.employees
This simply doesn't work in Access. You need a FROM clause.
So you need to have a dummy table with one record, even if you don't use a single field from that table.
SELECT 'HERRAMIENTA ELÉCTRICA' AS TIPO_PRODUCTO,
0 AS DEPRECIACION,
(select sum(empid) from HR.employees) STOCK
FROM Dummy_Table
Using this example as empty table:
with employ as
(select 2 as col from dual
minus
select 2 as col from dual)
The query is this one:
select 'HERRAM' as tipo,
0 as deprec,
coalesce(sum(col), 0) as STOCK
from employ;
coalesce(x, value) sets the column to value when X is null
In Access, you can use a system table, and Val and Nz for the zero value:
SELECT TOP 1
'HERRAMIENTA ELÉCTRICA' AS TIPO_PRODUCTO,
0 AS DEPRECIACION,
Val(Nz((select sum(empid) from HR.employees), 0)) AS STOCK
FROM
MSysObjects

Doing Math with 2 Subquerys

I have two subquerys both calculating sums. I would like to do an Artithmetic Minus(-) with the result of both Querys . eg Query1: 400 Query2: 300 Result should be 100.
Obvious a basic - in the query does not work. The minus works as MINUS on sets. How can I solve this? Do you have any ideas?
SELECT CustumersNo FROM Custumers WHERE
(
SELECT SUM(value) FROM roe WHERE roe.credit = Custumers.CustumersNo
-
SELECT SUM(value) FROM roe WHERE roe.debit = Custumers.CustumersNo
)
> 500
Using Informix - sorry missed that point
To get the original syntax to work, you would need to surround the sub-selects in parentheses:
SELECT CustumersNo
FROM Custumers
WHERE ((SELECT SUM(value) FROM roe WHERE roe.credit = Custumers.CustumersNo)
-
(SELECT SUM(value) FROM roe WHERE roe.debit = Custumers.CustumersNo)
) > 500
Note that aggregates are defined to ignore nulls in the values they aggregate in standard SQL. However, the SUM of an empty set of rows is NULL, not zero.
You can get inventive and devise ways to always have a value for each customer listed in the roe table, such as:
SELECT CustomersNo
FROM (SELECT CustomersNo, SUM(value) AS net_credit
FROM (SELECT credit AS CustomersNo, +value
UNION
SELECT debit AS CustomersNo, -value
) AS x
GROUP BY CustomersNo
) AS y
WHERE net_credit > 500;
You can also do that with an appropriate HAVING clause if you wish. Note that this avoids issues with customers who have credit entries but no debit entries or vice versa; all the entries that are present are treated appropriately.
Your misspelling (or unorthodox spelling) of 'customers' is nearly as good as 'costumers'.
Something like what you tried should work. It may be a syntax problem, and it may depend on what type of SQL you are using. However, an approach like this would be more efficient:
Update: I see you were having a problem with nulls, so I updated it to handle nulls properly.
select CustumersNo from (
select CustumersNo,
sum(coalesce(roecredit.value,0)) - sum(coalesce(roedebit.value,0))
as balance
FROM Custumers
join roe roecredit on roe.credit = Custumers.CustumersNo
join roe roedebit on roe.debit = Custumers.CustumersNo
group by CustumersNo
)
where balance > 500
Caveat: I don't have experience with Informix specifically.