I have the following data:
letter number
A 1
A 2
B 3
B 4
C 5
C 6
How can I write a select statement in Postgres to select this data into a table with an array of all possible numbers for each letter??
letter number array
A {1,2}
B {3,4}
C {5,6}
select letter, array_agg(number) as numbers
from the_table
group by letter;
See also the manual: http://www.postgresql.org/docs/current/static/functions-aggregate.html
If your Postgres version doesn't have "array_agg" function, you can try like this:
select letter,
array(
select number
from the_table t2
where t2.letter = t1.letter
order by number
) as numbers
from the_table t1
group by letter;
Related
How do I concatenate below's records such that they would be concatenated a maximum of 3 records?
Column A
Column B
Numbers
One
Numbers
Two
Numbers
Three
Alphabets
A
Alphabets
B
Alphabets
C
Alphabets
D
Will return:
Column A
Column B
Numbers
One, Two, Three
Alphabets
A, B, C
Alphabets
D
Thanks in advance.
WITH tableA as (
SELECT tbl.columnA, tbl.columnB, CAST(row_number() OVER (PARTITION BY columnA ORDER BY columnB) as INT) AS row_number
FROM tbl
ORDER BY columnA
)
SELECT tableA.columnA, string_agg(DISTINCT columnB, ', ') as columnB
FROM tableA
GROUP BY tableA.columnA, row_number/5
I'm trying to create a table with the following columns:
I want to use a with recursive table to do this. The following code however is giving the following error:
'ERROR: column "b" does not exist'
WITH recursive numbers AS
(
SELECT 1,2,4 AS a, b, c
UNION ALL
SELECT a+1, b+1, c+1
FROM Numbers
WHERE a + 1 <= 10
)
SELECT * FROM numbers;
I'm stuck because when I just include one column this works perfectly. Why is there an error for multiple columns?
This appears to be a simple syntax issue: You are aliasing the columns incorrectly. (SELECT 1,2,4 AS a, b, c) is incorrect. Your attempt has 5 columns: 1,2,a,b,c
Break it down to just: Select 1,2,4 as a,b,c and you see the error but Select 1 a,2 b,4 c works fine.
b is unknown in the base select because it is being interpreted as a field name; yet no table exists having that field. Additionally the union would fail as you have 5 fields in the base and 3 in the recursive union.
DEMO: http://rextester.com/IUWJ67486
One can define the columns outside the select making it easier to manage or change names.
WITH recursive numbers (a,b,c) AS
(
SELECT 1,2,4
UNION ALL
SELECT a+1, b+1, c+1
FROM Numbers
WHERE a + 1 <= 10
)
SELECT * FROM numbers;
or this approach which aliases the fields internally so the 1st select column's names would be used. (a,b,c) vs somereallylongalias... in union query. It should be noted that not only the name of the column originates from the 1st query in the unioned sets; but also the datatype for the column; which, must match between the two queries.
WITH recursive numbers AS
(
SELECT 1 as a ,2 as b,4 as c
UNION ALL
SELECT a+1 someReallyLongAlias
, b+1 someReallyLongAliasAgain
, c+1 someReallyLongAliasYetAgain
FROM Numbers
WHERE a<5
)
SELECT * FROM numbers;
Lastly, If you truly want to stop at 5 then the where clause should be WHERE a < 5. The image depicts this whereas the query does not; so not sure what your end game is here.
I have a table (only one row) in my PostgreSQL 9.5 db with two columns i.e., count (bigint) and array (text).
count array
6 "112,19.3,142,142,19.3,172,172,20.3,202,202,20.3,232,232,19.3,262,262,19.3,292"
The array represents six (thus count = 6) set of values i.e., Lower_limit, Value and Upper_limit. Now, I need to conditionally modify my array i.e., when upper limit and lower limits are coinciding then select the first upper limit and last lower limit and return the most common value (which is 19.3) among the limits. My desired output would be like:
count array
1 112, 19.3, 292
Could anyone help me to have some pointers towards my desired output?
I must admin - I dont understand how you get count =1, but below is an example of how you can build array with firsrt, last and most common values. Mind if there would be several mos common values it would unpredictably pick on of em
t=#
with a(r) as (values(array[112,19.3,142,142,19.3,172,172,20.3,202,202,20.3,232,232,19.3,262,262,19.3,292]))
, p as (select * from a,unnest(a.r) with ordinality)
, t as (
select count(1) over (partition by unnest)
, unnest u
, r[1] a
, r[array_length(r,1)] e
from p
order by unnest
limit 1
)
select array[a,u,e]
from t
;
array
----------------
{112,19.3,292}
(1 row)
Table A
id name keywords
1 Obj1 a,b,c,austin black
2 Obj2 e,f,austin black,h
3 Obj3 k,l,m,n
4 Obj4 austin black,t,u,s
5 Obj5 z,r,q,w
I need to get those records which contains similar type of keywords. Hence the result for the table needs to be:
Records:
1,2,4
Since records 1,2,4 are the one whose some or the other keyword match with at least any other keyword.
You can convert the "csv" to an array and then use Postgres' array functions:
select *
from the_table t1
where exists (select *
from the_table t2
where string_to_array(t1.keywords, ',') && string_to_array(t2.keywords, ',')
and t1.id <> t2.id);
I'm trying to do what I would call a "reverse count(*)" in PostgreSQL (8.4 +). I want my output to have the exact same number of rows as the number specified in the total column for each letter...
Table 1:
letter | total
-------------
a | 3
b | 2
c | 4
d | 1
Expected table output:
letter
-----
a
a
a
b
b
c
c
c
c
d
I am unsure if and how I could use the unnest function here....
Yes - unnest is what you'll want (once you've got an array of course)
richardh=> SELECT array_fill(letter, ARRAY[total]) FROM expand;
array_fill
------------
{a,a,a}
{b,b}
{c,c,c,c}
{d}
(4 rows)
richardh=> SELECT unnest(array_fill(letter, ARRAY[total])) FROM expand;
unnest
--------
a
a
a
b
b
c
c
c
c
d
(10 rows)
Here's solution that uses a tally or numbers table instead of UNNEST. It's a fairly cross platform solution in that every database has a solution for creating a numbers table although most not as nice as postgresql.
SELECT Letter
FROM
table1
INNER JOIN generate_series(1,100) num
ON table1.total >= num
ORDER BY Letter
SQL Fiddle Demo
I hardcoded the generate_series to 100. However as Clodoado demonstrates you can use MAX(Total) in the call to Generate_series
SELECT Letter
FROM
table1
INNER JOIN
generate_series(
1,
(select max(total) from table1)
) num ON table1.total >= num
ORDER BY Letter
SQL Fiddle Demo