sequence increment like 2018AA000001, 2018AB000001, 2018AC000001 - postgresql

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

Related

Get the ID of a table and its modulo respect the total rows in the same table in Postgres

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.

reshaping table based on column values

I was looking at a problem of reshaping a table creating new columns according based on values.
I'm using the same example as this problem discussed there: A complicated sum in R data.table that involves looking at other columns
so I have a table:
df:([]ID:1+til 5;
Group:1 1 2 2 2;
V1:10 + 2 * til 5;
Type_v1:`t1`t2`t1`t1`t2;
V2:3 0N 0N 7 8;
Type_v2:`t2```t3`t3);
ID Group V1 Type_v1 V2 Type_v2
------------------------------
1 1 10 t1 3 t2
2 1 12 t2
3 2 14 t1
4 2 16 t1 7 t3
5 2 18 t2 8 t3
and the goal is to transform it to get the sum of values by group and type. please note the new columns created. basically all types in Type_v1 and Type_v2 are used to create columns for the resulting table.
# group v_1 type_1 v_2 type_2 v_3 type_3
#1: 1 10 t1 15 t2 NA <NA>
#2: 2 30 t1 18 t2 15 t3
I did the beginning but I am unable to transform the table and create the new columns.
also of course I'm trying to get all the columns created in a dynamic way, as it would not be possible to input 20k columns manually.
df1:select Group, Value:V1, Type:Type_v1 from df;
df2:select Group, Value:V2, Type:Type_v2 from df;
tr:df1,df2;
tr:0!select sum Value by Group, Type from tr where Type <> ` ;
basically I'm missing the equivalent of:
dcast(tmp, group ~ rowid(group), value.var = c("v", "type"))
any help and explanations appreciated,
The last piece you're missing is a pivot: https://code.kx.com/q/kb/pivoting-tables/
q)P:exec distinct Type from tr
q)exec P#(Type!Value) by Group:Group from tr
Group| t1 t2 t3
-----| --------
1 | 10 15
2 | 30 18 15
It doesn't quite get you the exact output but pivot is the concept
You could expand on Terry's pivot to dynamically do the select parts above using functional form. See more detail here:
https://code.kx.com/q/basics/funsql/
// Personally, I would try to stay clear of column names too similar to reserved keywords in kdb
df: `id`grpCol`v_1`typCol_1`v_2`typCol_2 xcol df;
{[df;n]
// dynamically create cols from 1 to n
cls:`$("v_";"typCol_"),\:/:string 1 + til n;
// functional form of select for each type/value col before joining together
df:(,/) {?[x;();0b;`grpCol`v`typCol!`grpCol,y]}[df] each cls;
// sum, then pivot
df:0!select sum v by grpCol, typCol from df where typCol <> `;
P:exec distinct typCol from df;
df:exec P#(typCol!v) by grpCol:grpCol from df;
// Type cols seem unnecessary but
// Can be done with another functional select
?[df;();0b;(`grpCol,raze P,'`$"typCol_",/:string 1 + til count P)!`grpCol,raze flip (P;enlist each P)]
}[df;2]
grpCol t1 typCol_1 t2 typCol_2 t3 typCol_3
1 10 t1 15 t2 0N t3
2 30 t1 18 t2 15 t3
EDIT - More detailed breakdown below:
cls:`$("v_";"typCol_") ,\:/: string 1 + til n;
Dynamically create a symbol list for the columns as they are required for column names when using functional form. I start by creating a list of v_ and typCol_ up to number n.
,\:/: -> join with each left and each right iterators
https://code.kx.com/q/ref/maps/#each-left-and-each-right
This allows me to join every item on the left ("v_";"typCol_") with every item on the right.
The same could be achieved with cross but you would have to restructure the list with flip and cut
flip n cut `$("v_";"typCol_") cross string 1 + til n
(,/) {?[x;();0b;`grpCol`v`typCol!`grpCol,y]}[df] each cls;
(,/) -> This is the over iterator used with join. It takes the 1st table, joins it to the 2nd, then takes that and joins on to the 3rd etc.
https://code.kx.com/q/ref/over/
{?[x;();0b;`grpCol`v`typCol!`grpCol,y]}[df] each cls
// functional select
?[table; where; by; columns]
?[x; (); 0b; `grpCol`v`typCol!`grpCol,y]
This creates a list of tables, 1 for each column pair in the cls variable. Notice how I don't explicitly state x or y in the function like this {[x;y]}. This is because x y and z can be used implicitly, so this function works with or without.
The important part here is the last param (columns). For a functional select it is a dictionary with column names as the key and what the columns are as the values
e.g. `grpCol`v`typCol!`grpCol`v_1`typCol_1 -> this is renaming each v and typCol so they are the same to then join them all together with (,/).
There is a useful keyword to help with figuring out functional form -> parse
parse"select Group, Value:V1, Type:Type_v1 from df"
0 ?
1 `df
2 ()
3 0b
4 (`Group`Value`Type)!`Group`V1`Type_v1
P:exec distinct typCol from df;
df:exec P#(typCol!v) by grpCol:grpCol from df;
pivoting is outlined here: https://code.kx.com/q/kb/pivoting-tables/
It effectively flips/rotates a section of the table. It takes the distinct types from typCol as the columns and uses the v column as the rows for each corresponding typCol
?[table; where; by; columns]
?[df;();0b;(`grpCol,raze P,'`$"typCol_",/:string 1 + til count P)!`grpCol,raze flip (P;enlist each P)]
Again look at the last param in the functional select i.e. columns. This is how it looks after being dynamically generated:
(`grpCol`t1`typCol_1`t2`typCol_2`t3`typCol_3)!(`grpCol;`t1;enlist `t1;`t2;enlist `t2;`t3;enlist `t3)
It is kind of a hacky way to get the type columns, I select each t1 t2 t3 with a typeCol_1 _2 _3,
`t1 = (column) `t1
`typCol_1 = enlist `t1 -> the enlist here tells kdb I want the value `t1 rather than the column

calculate rank without using rank or rownums function by using single column

Do not use any functions like rank or rownums.
Hint: Formulate matrix operation using sql. A rank of an item indicates how many items are less than or equal to it.
A matrix can be simulated by cross join and rank can be derived by
counting items smaller than the current item.
Table A:-
x
----
d
b
a
g
c
k
k
g
Expected output:
x1 | rank
----+------
a | 1
b | 2
d | 3
g | 4
c | 5
k | 6
select x as x1, count(x) as rank
from (select DISTINCT x from A order by x) as sub
Your current query is on the right track, using a distinct subquery. For a working version, use a correlated subquery in the select clause which takes counts:
SELECT
x AS x1,
(SELECT COUNT(DISTINCT x) FROM A t WHERE t.x <= sub.x) rank
FROM (SELECT DISTINCT x FROM A) AS sub
ORDER BY
x;
Demo

kdb: What's the idiomatic way to join two tables by a composite foreign key?

I have two tables t1 and t2 defined as:
t1:([a:`datetime$(); b:`$()] x:`float$(); y:`float$());
meta t1
> c| t f a
> -| -----
> a| z
> b| s
> x| f
> y| f
t2:([t1:`t1$(); c:`$()] z:`float$());
meta t2
> c | t f a
> --| ------
> t1| i t1
> c | s
> z | f
where t1 defines a composite primary key from attributes a and b. t2 defines a forein key t1 to table t1.
I have looked all over the documentation how to join these two tables but had no luck. Is there a straighforward way to join them? I worked out the following way though:
ej[`t1;update t1:`t1$(a,'b) from t1;t2]
> a b x y t1 c z
> --------------
Basically doing an equal join between tables t1 and t2 after expanding table t1 to expose the composite foreign key i.e. the column type t1. Is there a more idiomatic and simpler way? for example doing t2 ij t1 leads to error: ``a
A slightly more efficient & neater way to do this would be to utilise the hidden i column (i.e. row index) in kdb tables instead of generating the composite of the key columns of t1 & enumerating against t1 e.g.
q)ej[`t1;update t1:`t1!i from t1;t2]
a b x y t1 c z
--------------
This is slightly more efficient:
q)\ts:1000 ej[`t1;update t1:`t1!i from t1;t2]
11 1904
q)\ts:1000 ej[`t1;update t1:`t1$(a,'b) from t1;t2]
12 2256
(efficiency gain will be increased with populated tables, of course)
EDIT:
Another option is to use the foreign keys in a select statement something like:
select t1.a,t1.b,t1.x,t1.y,c,z from t2
This is considerably more efficient than using an actual join:
q)\ts:1000 select t1.a,t1.b,t1.x,t1.y,c,z from t2
2 1712
q)\ts:1000 ej[`t1;update t1:`t1!i from t1;t2]
12 2496
The downside here is having to name all the fields in the select statement.
One more option involving a join is to use the "t1" column from t2 to index into t1, and then join each record. To do this you'll have to use 0! to unkey the tables for indexing:
q)((0!t1)#(0!t2)`t1),'t2
t1 c | a b x y z
------| -------------------------------------------------------
0 gck| 2004.02.13T15:53:44.342 ndd 4.49731 7.833686 9.030751
1 job| 2001.07.22T05:29:31.118 hpb 0.1392076 4.099561 7.750292
(I added some dummy records for demonstration)
This is slightly less efficient than the select statement, but better than the ej:
q)\ts:1000 ((0!t1)#(0!t2)`t1),'t2
4 1920

Postgres "reverse count(*)" (unnest?)

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