SELECT returns multiple answers - postgresql

I have names table with columns id, name and last_name. So what i'm trying to do is select random name and last_name from it, i tried this:
SELECT (SELECT name FROM names WHERE ID =floor(random()* 18 + 1 + x - x)),
(SELECT last_name FROM names WHERE ID = floor(random()* 18 + 1 + x - x))
FROM GENERATE_SERIES(1, 100) as x;
But it says it returns more than one row, why and how can i fix it?

When you use your query it will generate random id for each row. Therefore it get match with multiple rows in name table. Therefore it return multiple rows for this part SELECT name FROM names WHERE ID =floor(random()* 18 + 1 + x - x)). SQL not allow more than one row to get select.
This will work. I think this is what you want.
SELECT (SELECT name FROM names WHERE ID =(select floor(random()* 18 + 1 + x - x))) ,
(SELECT last_name FROM scientist WHERE id = (select floor(random()* 18 + 1 + x - x))) FROM GENERATE_SERIES(1, 100) as x;

The volatile random() function will generate a different value for each row of your table, so none or more than one row could be selected. You can avoid that by putting random() into an uncorrelated subquery, then it will only be executed once:
SELECT name FROM names
WHERE id = floor((SELECT random())*18 + 1);

Related

Postgres SQL Query sum + count in one query

I need help to get an result.
perscarcountoffset
person
0
1
0
1
I need a Total from a count of the lines where is person 1 + sum of the cell perscarcountoffset
select SUM((select sum(perscarcountoffset) from table where person = 1) + (select count(*) from table where person = 1)) from table where person = 1;
Thanks for any idea.
Try to create a query in postgresql. This works but it gives me 4 as result. But it must be only 2.
This returns 4 because you're actually computing
(select sum(perscarcountoffset) from table where person = 1) + (select count(*) from table where person = 1)
for each row in table (where person = 1), then summing that. So you're getting 2+2.
This is because anything outside of the aggregation method (i.e. the outer SUM() here) is per-row, and the inner sub-selects returns 2 for both rows.
The query you want doesn't need to be this complicated, this should do:
SELECT SUM(perscarcountoffset) + COUNT(*)
FROM table
WHERE person = 1;

How to make select every iteration Postgresql

I have table names with name and surname columns. I want to grab random name and surname from it, i tried this, but it takes one name and surname and prints it 100 times so it makes only one select at the start and then uses it's value,how can i fix it?
SELECT (SELECT name FROM names WHERE ID = ROUND(RANDOM() * 10 + 1)),
(SELECT surname FROM names WHERE ID = ROUND(RANDOM() * 10 + 1))
FROM GENERATE_SERIES(1, 100);
In order for Postgres to evaluate the select in the subquery multiple times, it needs to look like a correlated subquery -- one whose results depend on the values being returned by the top-level query. A minor problem here is that you don't actually care about those values. You can hack around that by meaninglessly including them in the subqueries, like this:
SELECT (SELECT name FROM names WHERE ID = ROUND(RANDOM() * 10 + 1 + i - i)),
(SELECT surname FROM names WHERE ID = ROUND(RANDOM() * 10 + 1 + i - i))
FROM GENERATE_SERIES(1, 100) i;
Another approach would be to move the subqueries to your FROM clause, put a different generate_series clause in each one, and then join them on the output of each series, but that ends up being really complicated SQL.
you didn't use the generateseries in the subquery , try with this
SELECT (SELECT name FROM names WHERE ID = ROUND(RANDOM() * 10 + g)),
(SELECT surname FROM names WHERE ID = ROUND(RANDOM() * 10 + g))
FROM GENERATE_SERIES(1, 100) g;

How to do conditional aggregation in postgres?

I want to do conditional aggregation in Postgres. I have a table with an id column and a float items column.
The query I want to write is something like this:
SELECT ( ((SUM(items) * 3) WHERE id="123"))
+ ((SUM(items) * 2) WHERE items="124")) )
FROM mytable
And I'd like to get a single number out. So for example, if my table looked like this:
org_id items
123 10
123 3
124 12
I'd like to get back the single number 63 (i.e. 13*3 + 12*2).
I'm pretty sure I need a CASE statement, but I'm not sure how to implement it.
In PostgreSQL 9.4+:
SELECT SUM(items) FILTER (WHERE org_id = 123) * 3 +
SUM(items) FILTER (WHERE org_id = 124) * 2
FROM mytable
, or, in earlier versions,
SELECT SUM(items * CASE org_id WHEN 123 THEN 3 WHEN 124 THEN 2 END)
FROM mytable
However, if you have lots of pairs like that, it would make sense to store them in a table (rather than hardcoding) and just use this:
SELECT SUM(items * coeff)
FROM (
VALUES
(123, 3),
(124, 2)
) m (id, coeff)
JOIN mytable
USING (id)
Replace the nested query m with your actual table

how to do dead reckoning on column of table, postgresql

I have a table looks like,
x y
1 2
2 null
3 null
1 null
11 null
I want to fill the null value by conducting a rolling
function to apply y_{i+1}=y_{i}+x_{i+1} with sql as simple as possible (inplace)
so the expected result
x y
1 2
2 4
3 7
1 8
11 19
implement in postgresql. I may encapsulate it in a window function, but the implementation of custom function seems always complex
WITH RECURSIVE t AS (
select x, y, 1 as rank from my_table where y is not null
UNION ALL
SELECT A.x, A.x+ t.y y , t.rank + 1 rank FROM t
inner join
(select row_number() over () rank, x, y from my_table ) A
on t.rank+1 = A.rank
)
SELECT x,y FROM t;
You can iterate over rows using a recursive CTE. But in order to do so, you need a way to jump from row to row. Here's an example using an ID column:
; with recursive cte as
(
select id
, y
from Table1
where id = 1
union all
select cur.id
, prev.y + cur.x
from Table1 cur
join cte prev
on cur.id = prev.id + 1
)
select *
from cte
;
You can see the query at SQL Fiddle. If you don't have an ID column, but you do have another way to order the rows, you can use row_number() to get an ID:
; with recursive sorted as
(
-- Specify your ordering here. This example sorts by the dt column.
select row_number() over (order by dt) as id
, *
from Table1
)
, cte as
(
select id
, y
from sorted
where id = 1
union all
select cur.id
, prev.y + cur.x
from sorted cur
join cte prev
on cur.id = prev.id + 1
)
select *
from cte
;
Here's the SQL Fiddle link.

query for a range of records in result

I am wondering if there is some easy way, a function, or other method to return data from a query with the following results.
I have a SQL Express DB 2008 R2, a table that contains numerical data in a given column, say col T.
I am given a value X in code and would like to return up to three records. The record where col T equals my value X, and the record before and after, and nothing else. The sort is done on col T. The record before may be beginning of file and therefore not exist, likewise, if X equals the last record then the record after would be non existent, end of file/table.
The value of X may not exist in the table.
This I think is similar to get a range of results in numerical order.
Any help or direction in solving this would be greatly appreciated.
Thanks again,
It might not be the most optimal solution, but:
SELECT T
FROM theTable
WHERE T = X
UNION ALL
SELECT *
FROM
(
SELECT TOP 1 T
FROM theTable
WHERE T > X
ORDER BY T
) blah
UNION ALL
SELECT *
FROM
(
SELECT TOP 1 T
FROM theTable
WHERE T < X
ORDER BY T DESC
) blah2
DECLARE #x int = 100
;WITH t as
(
select ROW_NUMBER() OVER (ORDER BY T ASC) AS row_nm,*
from YourTable
)
, t1 as
(
select *
from t
WHERE T = #x
)
select *
from t
CROSS APPLY t1
WHERE t.row_nm BETWEEN t1.row_nm -1 and t1.row_nm + 1