create new sql column to get new value - postgresql

I have this transaction table how can I query to find if a person is a New Client,Returning-Member, Returning-Non-member. for instance id 1 is a new client when sequence = 1, They can only be a member/returning-member after a type(member) has been purchased for example id 1 and sequence 4 is a returning-Non-member because this is the first time they are buying a member. After that transaction seq 5 they are now a returning-member
while for id 2 never bought a member so first sequence will be new client but others will be returning-non-member until they buy a member.
Question
id
Type
Date
Sequence
1
Member
2021-02-24
4
1
product
2021-01-03
2
2
service
2022-04-21
5
1
product
2021-02-01
3
2
service
2022-02-16
3
1
Member
2022-02-03
6
1
Service
2021-10-23
5
2
product
2022-01-03
2
1
service
2020-12-16
1
2
product
2022-03-30
4
2
service
2021-12-01
1
1
Member
2022-04-03
7
Result
id
Type
Date
Sequence
New column
1
Member
2021-02-24
4
Returning-Non-member
1
product
2021-01-03
2
Returning-Non-member
2
service
2022-04-21
5
Returning-Non-member
1
product
2021-02-01
3
Returning-Non-Member
2
service
2022-02-16
3
Returning-Non-member
1
Member
2022-02-03
6
Returning-Member
1
Service
2021-10-23
5
Returning-Member
2
product
2022-01-03
2
Returning-Non-Member
1
service
2020-12-16
1
New Client
2
product
2022-03-30
4
Returning-Non-Member
2
service
2021-12-01
1
New Client
1
Member
2022-04-03
7
Returning-Member

You can do it in a pretty strait forward way with an additional subquery, but it's not the best way in terms of performance.
SELECT
*,
CASE
WHEN t.Sequence = 1 THEN 'New Client'
WHEN
EXISTS (
SELECT *
FROM YourTable AS th
WHERE
th.Date < t.Date
AND th.Id = t.Id
AND th.Type ILIKE 'Member'
) THEN 'Returning-Member'
ELSE 'Returning-Non-Member'
END AS Membership
FROM YourTable AS t

Related

How to group by total of occurrences and don't repeat records

I have these tables:
products:
id
title
1
product a
2
product b
3
product c
clicks:
id
product_id
created_at
1
1
2022-01-01
2
1
2022-03-02
3
2
2022-10-01
I need to have the following result:
product_id
total_clciks
1
2
2
1
How can I solve this?
Thanks

Map the column value against same sequences in PostgreSQL

I want to write a query as per below input and output
Input :-
Num Sr_no Exp_no
NULL 1 1
NULL 2 1
ABC_1 3 1
NULL 4 1
NULL 1 2
NULL 2 2
ABC_2 3 2
NULL 4 4
Expected Output:-
Num Sr_no Exp_no
ABC_1 1 1
ABC_1 2 1
ABC_1 3 1
ABC_1 4 1
ABC_2 1 2
ABC_2 2 2
ABC_2 3 2
ABC_2 4 4
As there is no details in question, this answer is on below assumptions
you want to fill num field based on exp_no grouping.
Assuming there is only one value in a exp_no group.
Try this:
with cte as
(
select distinct on (num,exp_no) num, exp_no
from test
where num is not null
order by 1)
select
coalesce(t1.num, cte.num),
t1.sr_no,
t1.exp_no
from test t1 left join cte on t1.exp_no=cte.exp_no
DEMO

KDB+: How to retrieve the rows immediately before and after a given row that conform to a specific logic?

Given the following table
time kind counter key1 value
----------------------------------------
1 1 1 1 1
2 0 1 1 2
3 0 1 2 3
5 0 1 1 4
5 1 2 2 5
6 0 2 3 6
7 0 2 2 7
8 1 3 3 8
9 1 4 3 9
How would one select the value in the first row
immediately after and immediately before each
row of kind 1 ordered by time where the key1
value is the same in both instances .i.e:
time value prevvalue nextvalue
---------------------------------------------
1 1 0n 2
5 5 3 7
8 8 6 0n
9 9 6 0n
Here are some of the things I have tried, though
to be honest I have no idea how to canonically achieve
something like this in q whereby the prior value has a
variable offset to the current row?
select
prev[value],
next[value],
by key1 where kind<>1
update 0N^prevval,0N^nextval from update prevval:prev value1,nextval:next value1 by key1 from table
Some advice or a pointer on how to achieve this would be great!
Thanks
I was able to use the following code to return a table meeting your requirements. If this is correct, the sample table you have provided is incorrect, otherwise I have misunderstood the question.
q)table:([] time:1 2 3 5 5 6 7 8 9;kind:1 0 0 0 1 0 0 1 1;counter:1 1 1 1 2 2 2 3 4;key1:1 1 2 1 2 3 2 3 3;value1:1 2 3 4 5 6 7 8 9)
q)tab2:update 0N^prevval,0N^nextval from update prevval:prev value1,nextval:next value1 by key1 from table
q)tab3:select from tab2 where kind=1
time value1 prevval nextval
---------------------------
1 1 2
5 5 3 7
8 8 6 9
9 9 8
The update statement in tab2:
update 0N^prevval,0N^nextval from update prevval:prev value1,nextval:next value1 by key1 from table
is simply adding 2 columns onto the original table with the previous and next values for each row. 0^ is filling the empty fields with nulls.
The select statement in tab3:
tab3:select from tab2 where kind=1
is filtering tab2 for rows where kind=1.
The final select statement:
select time,value1,prevval,nextval from tab3
is selecting the rows you want to be returned in the final result.
Hope this answers your question.
Thanks,
Caitlin

spreading the days and the number of repetitions of each person for each specific day in postgresql

i have this table in postgresql database
id name time
1 poi 2018-05-13 08:45:48.846887
2 poi 2018-05-13 08:11:04.671437
3 roik 2018-05-14 16:32:04.671437
4 ceil 2018-05-14 17:38:04.671437
5 verk 2018-05-14 19:46:04.671437
6 roik 2018-05-16 08:21:04.671437
7 poi 2018-05-16 11:00:04.671437
8 roik 2018-05-18 14:40:08.671437
9 roik 2018-05-18 17:21:09.671664
10 verk 2018-05-13 08:46:04.671437
11 sant ...
12 sant ...
13 dmk ...
14 roik ...
15 poi ...
... .... ...
I want to have such a table:
name 2018-5-1 2018-5-2 2018-5-3 2018-5-4 2018-5-5 2018-5-6 2018-5-7 2018-5-8 2018-5-9 2018-5-10 2018-5-11 2018-5-12 2018-5-13 2018-5-14 ...
poi 0 3 3 7
roik 0 4 2 1
verk 0 2 0 9
sant 1 0 8 2
dmk 0 3 ...
...
These numbers represent the number of repetitions of each person for each particular day
how can i do this??thank you in advance
This is not exactly what you want but very similar to. You just need to translate "date" colun values to a columns itself, but you can easily do it on client after you queried the dates you need.
https://www.db-fiddle.com/f/7r4AG9MV9zeZEjoU77fCfk/2
SELECT Test.name, SUM(CASE WHEN date(Test.time) = dates.date THEN 1 ELSE 0 END), dates.date FROM Test CROSS JOIN
(SELECT DISTINCT(date(time)) as date FROM Test) as dates
GROUP BY Test.name, dates.date

One SQL Stored Procedure to get cut off date of two different cut off date format

I have one system that read from two client databases. For the two clients, both of them have different format of cut off date:
1) Client A: Every month at 15th. Example: 15-12-2016.
2) Client B: Every first day of the month. Example: 1-1-2017.
The cut off date are stored in the table as below:
Now I need a single query to retrieve the current month's cut off date of the client. For instance, today is 15-2-2017, so the expected cut off date for both clients should be as below:
1) Client A: 15-1-2017
2) Client B: 1-2-2017
How can I accomplish this in a single Stored Procedure? For client B, I can always get the first day of the month. But this can't apply to client A since their cut off is last month's date.
Might be something like this you are looking for:
DECLARE #DummyClient TABLE(ID INT IDENTITY,ClientName VARCHAR(100));
DECLARE #DummyDates TABLE(ClientID INT,YourDate DATE);
INSERT INTO #DummyClient VALUES
('A'),('B');
INSERT INTO #DummyDates VALUES
(1,{d'2016-12-15'}),(2,{d'2017-01-01'});
WITH Numbers AS
( SELECT 0 AS Nr
UNION ALL SELECT 1
UNION ALL SELECT 2
UNION ALL SELECT 3
UNION ALL SELECT 4
UNION ALL SELECT 5
UNION ALL SELECT 6
UNION ALL SELECT 7
UNION ALL SELECT 9
UNION ALL SELECT 10
UNION ALL SELECT 11
UNION ALL SELECT 12
UNION ALL SELECT 13
UNION ALL SELECT 14
UNION ALL SELECT 15
UNION ALL SELECT 16
UNION ALL SELECT 17
UNION ALL SELECT 18
UNION ALL SELECT 19
UNION ALL SELECT 20
UNION ALL SELECT 21
UNION ALL SELECT 22
UNION ALL SELECT 23
UNION ALL SELECT 24
)
,ClientExt AS
(
SELECT c.*
,MIN(d.YourDate) AS MinDate
FROM #DummyClient AS c
INNER JOIN #DummyDates AS d ON c.ID=d.ClientID
GROUP BY c.ID,c.ClientName
)
SELECT ID,ClientName,D
FROM ClientExt
CROSS APPLY(SELECT DATEADD(MONTH,Numbers.Nr,MinDate)
FROM Numbers) AS RunningDate(D);
The result
ID Cl Date
1 A 2016-12-15
1 A 2017-01-15
1 A 2017-02-15
1 A 2017-03-15
1 A 2017-04-15
1 A 2017-05-15
1 A 2017-06-15
1 A 2017-07-15
1 A 2017-09-15
1 A 2017-10-15
1 A 2017-11-15
1 A 2017-12-15
1 A 2018-01-15
1 A 2018-02-15
1 A 2018-03-15
1 A 2018-04-15
1 A 2018-05-15
1 A 2018-06-15
1 A 2018-07-15
1 A 2018-08-15
1 A 2018-09-15
1 A 2018-10-15
1 A 2018-11-15
1 A 2018-12-15
2 B 2017-01-01
2 B 2017-02-01
2 B 2017-03-01
2 B 2017-04-01
2 B 2017-05-01
2 B 2017-06-01
2 B 2017-07-01
2 B 2017-08-01
2 B 2017-10-01
2 B 2017-11-01
2 B 2017-12-01
2 B 2018-01-01
2 B 2018-02-01
2 B 2018-03-01
2 B 2018-04-01
2 B 2018-05-01
2 B 2018-06-01
2 B 2018-07-01
2 B 2018-08-01
2 B 2018-09-01
2 B 2018-10-01
2 B 2018-11-01
2 B 2018-12-01
2 B 2019-01-01