PostgreSQL view with filtered columns - postgresql

i have a table like this:
date_added owner action
01-02-2016 1 note
04-02-2016 1 call
04-02-2016 1 call
05-02-2016 1 note
05-02-2016 1 meeting
06-02-2016 1 meeting
06-02-2016 1 note
06-02-2016 1 cal
06-02-2016 1 note
10-02-2016 1 call
10-02-2016 1 note
10-02-2016 1 meeting
I need a view like this:
date_added owner note call meeting
01-02-2016 1 1 0 0
04-02-2016 1 0 2 0
05-02-2016 1 0 0 1
06-02-2016 1 2 1 1
10-02-2016 1 1 1 1
How do i create a column with something like
WHERE action LIKE 'note'
?

You could use CASE expression.
Query
select date_added, owner,
sum(case action when 'note' then 1 else 0 end) note,
sum(case action when 'call' then 1 else 0 end) call,
sum(case action when 'meeting' then 1 else 0 end) meeting
from your_table_name
group by date_added, owner;
Find demo here

Related

query customer retention over range

I am trying to find the best way to accomplish the following.
Get the beginning customer count, which carries from the previous day
Get New Customer count
Get the number of Customers who have not come in since the prior month
Get the number of Customers who have come back after lapsing
Get the number of total customers
The following example
Customer ID
Store ID
Date
Amount
1
1
1/2/22
1.00
2
2
1/2/22
2.00
1
1
2/2/22
1.00
3
2
3/2/22
1.00
2
2
3/2/22
1.00
1
1
3/2/22
1.00
1
1
4/2/22
1.00
4
1
4/2/22
1.00
2
2
4/2/22
1.00
The result would be
Date
Store
Beginning
New
Dropped
Returned
Total
1/2/22
1
0
1
0
0
1
1/2/22
2
0
1
0
0
1
2/2/22
1
1
0
0
0
1
2/2/22
2
1
0
1
0
0
3/2/22
1
1
0
0
0
1
3/2/22
2
0
1
0
1
2
4/2/22
1
1
1
0
0
2
4/2/22
2
2
0
1
0
1
I kind of have a query, but it's not getting the right results
WITH customerset AS (
SELECT
location_id,
date,
array_agg(DISTINCT customer_id ORDER BY customer_id ASC) AS customer_ids
FROM customer_orders
GROUP BY
location_id,
date
)
SELECT
cset.location_id,
cset.date,
array_length(cset2.customer_ids, 1) AS beginning,
array_length((past2.customer_ids - cset.customer_ids), 1) AS dropped,
array_length((cset.customer_ids - past2.customer_ids), 1) AS returned
FROM
(
SELECT
ords.location_id,
ords.date,
array_agg(DISTINCT ords.customer_id ORDER BY ords.customer_id ASC) AS customers_id
FROM customer_orders ords
GROUP BY
ords.location_id,
ords.date
) cset
JOIN
customerset cset2 ON cset.date - '1 month'::interval = cset2.date
AND cset2.location_id = cset.location_id
GROUP BY
cset.location_id,
cset.date,
cset2.customer_ids,
cset.customer_ids
ORDER BY
cset.date ASC

Max(case when) to expand indicator from single row to group of rows

I need to expand the indicator (currently on daily basis) to a larger group (groups multiple consecutive days into one grp). I have following type of data:
id date grp new_ind traditional_ind
--------------------------------------------------
1 02-01-2021 1 1 0
1 02-02-2021 1 0 1
1 02-03-2021 1 0 0
1 02-04-2021 1 null null
1 02-06-2021 2 0 1
1 02-07-2021 2 0 0
2 02-01-2021 1 null null
where new_ind and traditional_ind are mutually exclusive. With this, I am trying to create new indicator that expands the indicators that are currently on daily level to grp level, that will look like:
id date grp new_ind traditional_ind final_type
----------------------------------------------------------------
1 02-01-2021 1 1 0 new
1 02-02-2021 1 0 1 new
1 02-03-2021 1 0 0 new
1 02-04-2021 1 null null new
1 02-06-2021 2 0 1 traditional
1 02-07-2021 2 0 0 traditional
2 02-01-2021 1 null null none
basically,
if new_ind was ever 1, I want to flag entire grp as 'new'
if new_ind=0 and if traditional_ind is ever 1, flag entire grp as 'traditional'
if both indicators were null, then flag entire grp as 'none'
so that each id and grp can have single value of final_type.
I've tried:
max(case when new_ind = 1 then 'New'
when traditional_ind = 1 then 'Traditional'
else 'None' end) over (partition by id, grp) as final_type
but this wouldn't recognize when new_ind=1 then 'New' and flag all of new_ind = 1 as 'None' (but show traditional correctly):
id date grp new_ind traditional_ind final_type
----------------------------------------------------------------
1 02-01-2021 1 1 0 none
1 02-02-2021 1 0 1 none
1 02-03-2021 1 0 0 none
1 02-04-2021 1 null null none
1 02-06-2021 2 0 1 traditional
1 02-07-2021 2 0 0 traditional
2 02-01-2021 1 null null none
But if I remove else statement and only run:
max(case when new_ind = 1 then 'New'
when traditional_ind = 1 then 'Traditional'
end) over (partition by id, grp) as final_type
then this does accurately expand indicator as I hope, just returns null values (which I need to show as 'None' instead of nulls):
id date grp new_ind traditional_ind final_type
----------------------------------------------------------------
1 02-01-2021 1 1 0 new
1 02-02-2021 1 0 1 new
1 02-03-2021 1 0 0 new
1 02-04-2021 1 null null new
1 02-06-2021 2 0 1 traditional
1 02-07-2021 2 0 0 traditional
2 02-01-2021 1 null null null
Can anyone help identify issue with my max case when statement?
I think something like this should work:
WITH final_types AS (
SELECT
id,
grp,
( case
when bool_or(new_ind = 1) then 'New'
when bool_or(traditional_ind = 1) then 'Traditional'
else 'None'
end
) AS final_type
FROM your_table
GROUP BY id, grp
)
SELECT
t1.*,
t2.final_type
FROM your_table t1
JOIN final_types t2 ON t1.id = t2.id AND t1.grp = t2.grp

Can I combine the results a single line?

My query is:
select urunbolgesi,sube,
count(case etiket when 'BOŞTA' then 1 else null end) as bosta,
count(case etiket when 'ZİMMET' then 1 else null end) as zimmet,
count(case etiket when 'ISKART' then 1 else null end) as iskart
from tblurun
where urunadi='CASPER-11'
group by urunbolgesi,sube,etiket,urunadi
My result is:
urunbolgesi sube bosta zimmet iskart
A qwer 0 1 0
B asdf 5 0 0
B asdf 0 0 1
B asdf 0 1 0
What I want that is:
urunbolgesi sube bosta zimmet iskart
A qwer 0 1 0
B asdf 5 1 1
Can I combine with code above result?

Reorder Ranked rows

Recently i needed to implement a way to allow for Table Records to be Ranked.
Initially i deployed an Update statement to seed the ranks:
;with cte as (
select
t.id,
Rank() Over (
Partition by t.field2
Order by t.id
) as [Rank],
t.index,
t.field2,
t.field3 ,
t.field4
from dbo.Table t
where t.field2 = #fldValue
) Update cte
set index = [Rank]
But now i need to be able to have the end-user re-order the ranks. Any suggestions on how to allow an end-user to take Rank value 92 to Rank value 15 and have everything be re-ranked appropriately.
I had thought about doing this via cursor but am trying to do this via Set based operation.
My first goto was to do a Procedural based operation but need to get more inline with Set based operation.
Table Schema
Table:
id bigint
field2 int
field3 int ---> This field will be the key pivoting column for ranking
field4 int
Data:
id field2 field3 field4
1 0 1 1
2 0 1 1
3 0 1 1
4 0 1 2
5 0 1 2
6 0 1 1
7 0 1 1
8 0 1 1
9 0 1 1
10 0 1 2
11 0 1 2
12 0 1 1
13 0 1 1
14 0 1 1
15 0 1 2
16 0 1 1
17 0 1 2
18 0 1 2
19 0 1 1

Count valid values per user

I have a table with a list of values. -1 is a blank value:
ID FieldType1A FieldType1B FieldType2A FieldType2B Person
1 15 14 10 -1 1
2 16 -1 12 10 1
3 17 -1 5 6 1
4 6 -1 7 -1 2
...
So the result should be:
Person FieldType1 FieldType2
1 4 5
2 1 1
there is a users table with a list of user IDs, would there be a way of iterating over that list of values to generate the person list in the result set (0 for the field types being perfectly valid as it is merely counts)? I think the answer to T-SQL Column Values Count is a step in the direction I'm attempting to go, but unsure how to combine columns that are the same (the A/Bs allow for a list of answers). That and I'm interested in combining all valid values as not attempting to count the number of each valid response.
You can use a CASE expression to change all non-negative-one values to 1, and -1 values to 0, and then sum them up.
SELECT Person,
SUM(CASE WHEN FieldType1A <> -1 THEN 1 ELSE 0 END) +
SUM(CASE WHEN FieldType1B <> -1 THEN 1 ELSE 0 END) AS FieldType1,
SUM(CASE WHEN FieldType2A <> -1 THEN 1 ELSE 0 END) +
SUM(CASE WHEN FieldType2B <> -1 THEN 1 ELSE 0 END) AS FieldType2
FROM YourTable
GROUP BY Person
SELECT Person,
count(nullif(FieldType1A, -1)) + count(nullif(FieldType1B, -1)) as FieldType1,
count(nullif(FieldType2A, -1)) + count(nullif(FieldType2B, -1)) as FieldType2
FROM yourtable
GROUP BY person