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
Related
While trying to map some data to a table, I wanted to obtain the ID of a table and its modulo respect the total rows in the same table. For example, given this table:
id
--
1
3
10
12
I would like this result:
id | mod
---+----
1 | 1 <- 1 mod 4
3 | 3 <- 3 mod 4
10 | 2 <- 10 mod 4
12 | 0 <- 12 mod 4
Is there an easy way to achieve this dynamically (as in, not counting the rows on before hand or doing it in an atomic way)?
So far I've tried something like this:
SELECT t1.id, t1.id % COUNT(t1.id) mod FROM tbl t1, tbl t2 GROUP BY t1.id;
This works but you must have the GROUP BY and tbl t2 as otherwise it returns 0 for the mod column which makes sense because I think it works by multiplying the table by itself so each ID gets a full set of the table. I guess for small enough tables this is ok but I can see how this becomes problematic for larger tables.
Edit: Found another hack-ish way:
WITH total AS (
SELECT COUNT(*) cnt FROM tbl
)
SELECT t1.id, t1.id % t2.cnt mod FROM tbl t1, total t2
It similar to the previous query but it "collapses" the multiplication to a single row with the previous count.
You can use COUNT() window function:
SELECT id,
id % COUNT(*) OVER () mod
FROM tbl;
I'm sure that the optimizer is smart enough to calculate the result of the window function only once.
See the demo.
I need to increment sequence like 2018AA000001 to 2018AA100000 after completing first sequence then it should start next sequence 2018AB000001 to 2018AB100000
it is working only one sequence using trigger in postgresql but i need to implement 2018AA then 2018AB, 2018AC sequence like.
please suggest me how to do this.
Thanks,
Vittal
You can probably make a function out of this. Maybe some people here can edit this into a sequence that you can use.
This output the results you specified in your description.
discard temp;
We will generate list of letters using this.
create temp table generate_letters as
select chr(i) as letter from generate_series(65,90) i;
letter
--------
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z
(26 rows)
And generate numbers up to 100000.
create temp table generate_num as
select lpad(i::text,6,'0') as num from generate_series(1,100000) i;
select * from generate_num limit 10;
num
--------
000001
000002
000003
000004
000005
000006
000007
000008
000009
000010
(10 rows)
Then we just have to cross join.
select concat_ws('','2018',gl1.letter,gl2.letter,d.num) as seq
from generate_letters gl1
cross join generate_letters gl2
cross join generate_num d limit 100003;
seq
--------------
2018AA000001
2018AA000002
2018AA000003
2018AA000004
2018AA000005
2018AA000006
2018AA000007
2018AA000008
2018AA000009
...skipping...
2018AA099997
2018AA099998
2018AA099999
2018AA100000
2018AB000001
2018AB000002
I'm trying to find all IDs in TableA that are mentioned by a set of records in TableB and that set if defined in Table C. I've come so far to the point where a set of INNER JOIN provide me with the following result:
TableA.ID | TableB.Code
-----------------------
1 | A
1 | B
2 | A
3 | B
I want to select only the ID where in this case there is an entry for both A and B, but where the values A and B are based on another Query.
I figured this should be possible with a GROUP BY TableA.ID and HAVING = ALL(Subquery on table C).
But that is returning no values.
Since you did not post your original query, I will assume it is inside a CTE. Assuming this, the query you want is something along these lines:
SELECT ID
FROM cte
WHERE Code IN ('A', 'B')
GROUP BY ID
HAVING COUNT(DISTINCT Code) = 2;
It's an extremely poor question, but you you probably need to compare distinct counts against table C
SELECT a.ID
FROM TableA a
GROUP BY a.ID
HAVING COUNT(DISTINCT a.Code) = (SELECT COUNT(*) FROM TableC)
We're guessing though.
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;
I have two tables like this
A B
---- -------
col1 col2 col1 col2
---------- -----------
A table contains 300k rows
B table contains 400k rows
I need to count the col1 for table A if it is matching col1 for table B
I have written a query like this:
select count(distinct ab.col1) from A ab join B bc on(ab.col1=bc.col1)
but this takes too much time
could try a group by...
Also ensure that the col1 is indexed in both tables
SELECT COUNT (col1 )
FROM
(
SELECT aa.col1
FROM A aa JOIN B bb on aa.col1 = bb.col1
GROUP BY (aa.col1)
)
It's difficult to answer without you positing more details: did you analyze the tables? Do you have an index on col1 on each table? How many rows are you counting?
That being said, there aren'y so many potential query plans for your query. You likely have two seq scans that are hash joined together, which is about the best you can do... If you've a material numbers of rows, you'll be counting a gazillion rows, and this takes time.
Perhaps you could rewrite the query differently? If every B.col1 is in A.col1, you could get the same result without the join:
select count(distinct col1) from B
If A has low cardinality, it might be faster to rely on exists():
with vals as (
select distinct A.col1 as val from A
)
select count(*) from vals
where exists(select 1 from B where B.col1 = vals.val)
Or, if you know every possible value from A.col1 and it's reasonably small, you could unnest an array without querying A at all:
select count(*) from unnest(Array[val1, val2, ...]) as vals (val)
where exists(select 1 from B where B.col1 = vals.val)
Or vice-versa, in each of the above, if every B holds the reference values.