Cursor size (number of results) - postgresql

How I can know cursor size (numbers of results)?
c CURSOR IS SELECT foo FROM mytable WHERE name='ok';

In my understanding, a cursor is NOT the result. You can use a cursor to GET your results row by row, and at the end of this row by row operations, you know how many results you got.
To know how many records you will (possibly) get, you can use a
select count(*) from ... where ...
assuming you have an index on column name, you could also write:
select count(name) from foo where name = 'ok'

If you want to obtain the total number of results without issuing a separate count query, you can:
SELECT count(1) OVER (), ... FROM ... WHERE ...
The count will be unaffected by ORDER/LIMIT clauses.

Related

Single Value Expression in When Then Aggregate Function TSQL

I am trying to map a certain value of a column based on its count on another table. If the count of [Location] i.e a column of IMPORT.DATA_SCRAP table in each row. For now for location static value i.e Utah and Kathmandu is supplied for test purpose only is equal to 1, then only i need to get the result in the select statement i.e only single value expression must be returned but here n rows of table with value is returned.
For. eg. In the below query,total rows of IMPORT.DATA_SCRAP gets returned, i only need the single first row value in my case.
I came to know whether cursor or CTE will acheive my result but i am unable to figure it out.
Here,
select
case
when
((SELECT COUNT(stateName) FROM Location.tblState where stateName = 'Utah')=1)
then (select stateName, CountryName from Location.tblState where stateName= 'Utah')
end as nameof
from IMPORT.DATA_SCRAP
The relation between country, state, city is as below:
select
case
when
((SELECT COUNT(cityName) FROM Location.tblCity where cityName = 'Kathmandu')=1)
then (select ct.countryName from Location.tblCity c
inner join Location.tblState s
on c.stateID = s.StateID
inner join Location.tblCountry ct
on ct.countryId = s.CountryId
where c.cityName = 'Kathmandu'
)
end as nameof
from IMPORT.DATA_SCRAP
How can i return only a single value expresion despite of multiple nmax rows of IMPORT.DATA_SCRAP row in the result.
If i comment out the -- from IMPORT.DATA_SCRAP in the above query i would get the desired single result expression in my case, but unable how can i acheive it in other ways or suggest me the appropriate way to do these types of situation.

PostgreSQL regexp_matches only returning rows that match it?

This is my first time using regexp_matches and I find that using it will only return rows that match all regexp_matches in the SELECT clause.
For example:
SELECT parameters,
regexp_matches(parameters, 'a=(\d+)'),
regexp_matches(parameters, 'b=(\d+)')
FROM table;
Will return result with row where parameters is a=1&b=1 but not a=1 or b=1
It's acting as if it was a where clause. Why is this?
This is because regexp_matches() returns set of rows.
With no matches it returns no rows.
Use search by one regexp, e.g.:
SELECT
parameters,
regexp_matches(parameters, '[a|b]=(\d+)')
FROM a_table;
or, if you want to get two columns for aand b:
SELECT parameters, a, b
FROM (
SELECT
parameters,
regexp_matches(parameters, 'a=(\d+)') a,
null b
FROM a_table
UNION
SELECT
parameters,
null,
regexp_matches(parameters, 'b=(\d+)')
FROM a_table
) s;
Another way around this is to match on the end of the string in addition to the pattern you want to find.
SELECT parameters,
regexp_matches(parameters, '(a=(\d+))|$'),
regexp_matches(parameters, '(b=(\d+))|$')
FROM table;
Then you might want to do some other processing since any string missing the pattern will show up in results as {NULL} (or {NULL,NULL<,...>}, one per match group).

comprare aggregate sum function to number in postgres

I have the next query which does not work:
UPDATE item
SET popularity= (CASE
WHEN (select SUM(io.quantity) from item i NATURAL JOIN itemorder io GROUP BY io.item_id) > 3 THEN TRUE
ELSE FALSE
END);
Here I want to compare each line of inner SELECT SUM value with 3 and update popularity. But SQL gives error:
ERROR: more than one row returned by a subquery used as an expression
I understand that inner SELECT returns many values, but can smb help me in how to compare each line. In other words make loop.
When using a subquery you need to get a single row back, so you're effectively doing a query for each record in the item table.
UPDATE item i
SET popularity = (SELECT SUM(io.quantity) FROM itemorder io
WHERE io.item_id = i.item_id) > 3;
An alternative (which is a postgresql extension) is to use a derived table in a FROM clause.
UPDATE item i2
SET popularity = x.orders > 3
FROM (select i.item_id, SUM(io.quantity) as orders
from item i NATURAL JOIN itemorder io GROUP BY io.item_id)
as x(item_id,orders)
WHERE i2.item_id = x.item_id
Here you're doing a single group clause as you had, and we're joining the table to be updated with the results of the group.

Unpack a PostGIS/PostgreSQL record with SQLAlchemy

How would I write the following query using SQLAlchemy's ORM?
SELECT filename, (stats).*
FROM (
SELECT filename, ST_SummaryStats(rast, 1, TRUE) AS stats FROM tiles
) AS stats_table;
Here, ST_SummaryStats is a PostGIS function that returns the record that I wish to unpack. tiles is a PostGIS table with filename and rast (raster) columns. My attempt is as follows:
sub_q = db_session.query(
Tiles.filename,
func.ST_SummaryStats(Tiles.rast, 1, True).label('stats'),
).subquery()
q = db_session.query(
sub_q.columns.filename,
sub_q.columns.stats,
)
However, I don't know how to write the (stats).* expression -- and hence unpack the record -- with SQLAlchemy's ORM. Consequently, stats appears to be a tuple.
Thanks in advance for any help.
ST_SummaryStats() returns a record, so rather than use it as a SELECT expression (which would return the record), use it as a FROM clause and pick the desired statistics at the SELECT level, so it becomes very simply:
SELECT filename, count, sum, mean, stddev, min, max
FROM tiles, ST_SummaryStats(tiles.rast, 1, true);
This results in a so-called LATERAL JOIN and since ST_SummaryStats() returns only a single row for the indicated raster in tiles you do not need a join condition, filter or anything else.
I am not sure about SQLAlchemy's ability to use the result of a function as a class, but a sure-fire way of making this work is to wrap the above SELECT into a VIEW and then access the view from SQLAlchemy:
CREATE VIEW raster_stats AS
SELECT filename, count, sum, mean, stddev, min, max
FROM tiles, ST_SummaryStats(tiles.rast, 1, true);

Using two different rows from the same table in an expression

I'm using PostgreSQL + PostGIS.
In table I have a point and line geometry in the same column of the same table, in different rows. To get the line I run:
SELECT the_geom
FROM filedata
WHERE id=3
If i want to take point I run:
SELECT the_geom
FROM filedata
WHERE id=4
I want take point and line together, like they're shown in this WITH expression, but using a real query against the table instead:
WITH data AS (
SELECT 'LINESTRING (50 40, 40 60, 50 90, 30 140)'::geometry AS road,
'POINT (60 110)'::geometry AS poi)
SELECT ST_AsText(
ST_Line_Interpolate_Point(road, ST_Line_Locate_Point(road, poi))) AS projected_poi
FROM data;
You see in this example data comes from a hand-created WITH expression. I want take it from my filedata table. My problem is i dont know how to work with data from two different rows of one table at the same time.
One possible way:
A subquery to retrieve another value from a different row.
SELECT ST_AsText(
ST_Line_Interpolate_Point(
the_geom
,ST_Line_Locate_Point(
the_geom
,(SELECT the_geom FROM filedata WHERE id = 4)
)
)
) AS projected_poi
FROM filedata
WHERE id = 3;
Use a self-join:
SELECT ST_AsText(
ST_Line_Interpolate_Point(fd_road.the_geom, ST_Line_Locate_Point(
fd_road.the_geom,
fd_poi.the_geom
)) AS projected_poi
FROM filedata fd_road, filedata fd_poi
WHERE fd_road.id = 3 AND fd_poi.id = 4;
Alternately use a subquery to fetch the other row, as Erwin pointed out.
The main options for using multiple rows from one table in a single expression are:
Self-join the table with two different aliases as shown above, then filter the rows;
Use a subquery expression to get a value for all but one of the rows, as Erwin's answer shows;
Use a window function like lag() and lead() to get a row relative to the current row within the query result; or
JOIN on a subquery that returns a table
The latter two are more advanced options that solve problems that're difficult or inefficient to solve with the simpler self-join or subquery expression.