Postgres division incorrect and rows disappear in WITH query - postgresql

I have a WITH AS query, I hope the brevity can be appreciated, i've distilled this down to what the problem is:
WITH XX AS (
SELECT ....,
floor(GREATEST(value*-1, value2) * (value4*value5/value) * -1 * 100)/100 as x,
....
)
Then I use this later in the query
SELECT 1/x as "ratio" from XX
This is where a whole bunch of rows disappear,
now if i do:
SELECT 2/1*x "ratio" from XX
also weird is this returns the same result:
SELECT 2*1*x "ratio" from XX
The rows come back but the value of ratio is incorrect. I've tried to also use CAST but it will still return the incorrect result. Curiously the result is actually the result of 2*x instead of 2/x
Why is the result incorrect, and why do the rows disappear?

SELECT 2/1*x "ratio" from XX
is equivalent to
SELECT 2*1*x "ratio" from XX
because of multiplications and divisions are evaluated from left to right. Thus, the first expression is evaluated as (2 / 1) * x, and not as 2 / (1 * x).
BTW: Your arithmetics smell like integer arithmethics which should be done as float arithmetics, e.g. you better wrote the expression as 2.0 / x.

Related

Can PostgreSQL LAG() function refer to itself?

I've just discovered LAG() function in PostgreSQL and I've been experimenting to see what it can achieve. I've though that I might calculate factorial with it and I wrote
SELECT i, i * lag(factorial, 1, 1) OVER (ORDER BY i, 1) as factorial FROM generate_series(1, 10) as i;
But online IDE complains that 42703 column "factorial" does not exist.
Is there any way I can access the result of previous LAG call?
You can't refer to the column recursively in its definition.
However, you can express the factorial calculation as:
SELECT i, EXP(SUM(LN(i)) OVER w)::int factorial
FROM generate_series(1, 10) i
WINDOW w AS (ORDER BY i ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW);
-- outputs:
i | factorial
----+-----------
1 | 1
2 | 2
3 | 6
4 | 24
5 | 120
6 | 720
7 | 5040
8 | 40320
9 | 362880
10 | 3628800
(10 rows)
Postgresql does support an advanced SQL feature called recursive query, which can also be used to express the factorial table recursively:
WITH RECURSIVE series AS (
SELECT i FROM generate_series(1, 10) i
)
, rec AS (
SELECT i, 1 factorial FROM series WHERE i = 1
UNION ALL
SELECT series.i, series.i * rec.factorial
FROM series
JOIN rec ON series.i = rec.i + 1
)
SELECT *
FROM rec;
what EXP(SUM(LN(i)) OVER w) does:
This exploits the mathematical identities that:
[1]: log(a * b * c) = log (a) + log (b) + log (c)
[2]: exp (log a) = a
[combining 1&2]: exp(log a + log b + log c) = a * b * c
SQL does not have an aggregate multiply operation, so to perform an aggregate multiply operation, we first have to take the log of each value, then we can use the sum aggregate function to give us the the log of the values' product. This we invert with the final exponentiation step.
This works as long as the values being multiplied are positive as log is undefined for 0 and negative numbers. If you have negative numbers, or zero, the trick is to check if any value is 0, then the whole aggregation is 0, and check if the number of negative values is even, then the result is positive, else it is negative. Alternatively, you could also convert the reals to the complex plane and then use the identity Log(z) = ln(r) - iπ
what ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW does
This declares an expanding window frame that includes all preceding rows, and the current row.
e.g.
when i equals 1 the values in this window frame are {1}
when i equals 2 the values in this window frame are {1,2}
when i equals 3 the values in this window frame are {1,2,3}
what is a recursive query
A recursive query lets you express recursive logic using SQL. Recursive queries are often used to generate parent-child relationships from relational data (think manager-report, or product classification hierarchy), but they can generally be used to query any tree like structure.
Here is a SO answer I wrote a while back that illustrates and explains some of the capabilities of recursive queries.
There are also a tonne of useful tutorials on recursive queries. It is a very powerful sql-language feature and solves a type of problem that are very difficult do do without recursion.
Hope this gives you more insight into what the code does. Happy learning!

Postgres WHERE clause with infinity

I have the following WHERE clause on a table x with column 1 as integer.
The SELECT is called in a function with parameters (a integer, b integer)
Call the function:
SELECT * FROM function(0, 10)
Script in funcion:
SELECT * FROM tablex x WHERE x.column1 between a and b
Now i miss the results where column1 is null, but in this case it is important to get these. Depends who calls the function. What should be parameter "a" to also get the null values. Or is there a way to disable the where clause depending on the paramter which are coming?
I found a nice solution for this:
SELECT * FROM tablex x WHERE coalesce(x.column1, 0) between a and b
Add logic to admit null column1 values:
SELECT *
FROM tablex x
WHERE x.column1 BETWEEN a AND b OR x.column1 IS NULL;
To make the NULLs behave as actual values, invert the logic.
[and add a comment to the code, because the negation might confuse future readers/maintainers]:
SELECT * FROM tablex x WHERE NOT x.column1 < a and NOT x.column1 >= b;
Note the above assumes you want NULLs in both a and b to be treated as -inf and +inf , respectively.

JSON building functions produce numeric values with trailing zeros after division

Next json functions produce values with trailing zeros and the question is how to avoid it?
SELECT JSON_BUILD_OBJECT('a', (1::NUMERIC / 10));
SELECT JSONB_SET('{}'::JSONB, '{a}', (1::NUMERIC / 10)::TEXT::JSONB);
The oputput is
{"a": 0.10000000000000000000}
And it is observed only after division, for example, the next function produces the result without zeros
SELECT JSON_BUILD_OBJECT('a', 0.1::NUMERIC); -- {"a" : 0.1}
Division without json function works the same
SELECT 1::NUMERIC / 10;-- 0.1
If it matters, Postgres version is 10.5
It may be weird if you display a json value to the screen. Try convert number to double precision and then back to numeric, like:
SELECT JSON_BUILD_OBJECT('a', (1::NUMERIC / 10)::double precision::numeric);
SELECT JSONB_SET('{}'::JSONB, '{a}', (1::NUMERIC / 10)::double precision::numeric::TEXT::JSONB);

TSQL So weird, dividing doesn't work in select (but * - + works fine), but only for one column

I have so weird issue:
select ****
COALESCE(Customers / (NULLIF(Visitors,0)),0) AS CR
for 3/3 returns 1
for 157/2 returns 0
or any other non 1 will return 0.
The CR is decimal(8,2) and for all other columns the same line is working (with mix of different columns)
I have tried + - *, all works as should, however as soon I use division it won't return a value unless is one.
What is going on ??? Why dividing doesn't work, while all other arithmetic functions works just fine. Looks like it won't return decimals...
Can't replicate your results, but perhaps this will help clarify.
Example
Declare #T table (Customers int,Visitors int)
Insert Into #T values
(2,157),
(5,14),
(2,0),
(null,25),
(15,null)
select CR = IsNull((Customers+0.0) / nullif(Visitors,0),0)
From #T
Returns
CR
0.012738853503
0.357142857142
0.000000000000
0.000000000000
0.000000000000

How should I query an integer where there are decimals in the data?

SELECT * FROM table1 WHERE spent>= '1000'
This query still bring out numbers such as 598.99 and 230.909. My question is why is it doing this when I asked to search over or equal to 1000. Is there anyway to query so it only shows equal and more than 1000?
This happens because your '1000' is a text value. The other value is (or is converted to) text, too, so you end up with byte-per-byte comparison.
598.99 is greater then 1000 because 5... is greater then 1....
Cast to numeric types to do a proper comparison:
SELECT * FROM table1 WHERE spent::numeric >= '1000'::numeric
Or simply:
SELECT * FROM table1 WHERE spent::numeric >= 1000
You must compare numbers to get numeric comparison.
Use
WHERE CAST(spent AS numeric) >= 1000